Kubeneters HA Cluster部署

k8s HA Cluster部署

Rocky操作系统镜像下载链接:

bash 复制代码
https://dl.rockylinux.org/vault/rocky/9.7/isos/x86_64/

环境:

角色 规格 OS IP
k8s-vip none none 192.168.1.12
lb1 2C2G Rocky9.7 Minimal 192.168.1.13
lb2 2C2G Rocky9.7 Minimal 192.168.1.14
Master1 2C4G Rocky9.7 Minimal 192.168.1.15
Master1 2C4G Rocky9.7 Minimal 192.168.1.16
Master1 2C4G Rocky9.7 Minimal 192.168.1.17
Node1 2C4G Rocky9.7 Minimal 192.168.1.18

1.初始化系统(所有节点)

关闭防火墙,关闭SELinux::

arduino 复制代码
systemctl stop firewalld;systemctl disable firewalld
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
reboot

关闭 Swap 分区(K8S 强制要求)

bash 复制代码
swapoff -a
sed -ri 's/.*swap.*/#&/' /etc/fstab

配置yum源:

先将默认yum配置删除:

bash 复制代码
cd /etc/yum.repos.d/
​
rm -rf *.repo

然后配置镜像yum源:

ini 复制代码
cat > /etc/yum.repos.d/rocky.repo << 'EOF'
[baseos]
name=Rocky Linux $releasever - BaseOS
baseurl=https://mirrors.aliyun.com/rockylinux/$releasever/BaseOS/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/rockylinux/RPM-GPG-KEY-Rocky-9
​
[appstream]
name=Rocky Linux $releasever - AppStream
baseurl=https://mirrors.aliyun.com/rockylinux/$releasever/AppStream/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/rockylinux/RPM-GPG-KEY-Rocky-9
​
[extras]
name=Rocky Linux $releasever - Extras
baseurl=https://mirrors.aliyun.com/rockylinux/$releasever/extras/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/rockylinux/RPM-GPG-KEY-Rocky-9
​
[crb]
name=Rocky Linux $releasever - CRB
baseurl=https://mirrors.aliyun.com/rockylinux/$releasever/CRB/$basearch/os/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/rockylinux/RPM-GPG-KEY-Rocky-9
EOF

清理dnf缓存,列出可用仓库

css 复制代码
dnf clean all
dnf makecache
dnf repolist

最小化安装后推荐基础包

perl 复制代码
dnf install -y bash-completion vim wget curl net-tools bind-utils tar unzip git

节点初始化:

配置主机名(其他机器以此类推:lb1, lb2, master2, master3, node1)

arduino 复制代码
hostnamectl set-hostname master1

配置本地 DNS 解析

bash 复制代码
cat >> /etc/hosts <<EOF
192.168.1.12 k8s-vip
192.168.1.13 lb1
192.168.1.14 lb2
192.168.1.15 master1
192.168.1.16 master2
192.168.1.17 master3
192.168.1.18 node1
EOF

LB两台节点配置:

开启"允许绑定非本地 IP" 这是 Keepalived + HAProxy 架构的核心底座,确保当 VIP 在另一台机器上时,本机的 HAProxy 也能正常启动并监听 16443 端口

bash 复制代码
cat <<EOF | tee /etc/sysctl.d/haproxy.conf
net.ipv4.ip_nonlocal_bind = 1
net.ipv4.ip_forward = 1
EOF
​
sysctl --system

安装 HAProxy 和 Keepalived 两台机器上安装负载均衡软件:

复制代码
dnf install -y haproxy keepalived

配置 HAProxy(两台 LB 配置完全相同)

perl 复制代码
# 备份原配置
​
mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
​
# 写入新配置
​
cat > /etc/haproxy/haproxy.cfg <<EOF
global
    log /dev/log local0
    log /dev/log local1 notice
    daemon
    maxconn 4000
​
defaults
    mode                    tcp
    log                     global
    retries                 3
    timeout queue           1m
    timeout connect         10s
    timeout client          1h
    timeout server          1h
    timeout check           10s
​
frontend k8s-apiserver
    bind *:16443
    mode tcp
    default_backend k8s-masters
​
backend k8s-masters
    mode tcp
    balance roundrobin
    option tcp-check
​
    # 这里指向你的三台 Master 节点
​
•    server master1 192.168.1.15:6443 check inter 2000 fall 3 rise 2
•    server master2 192.168.1.16:6443 check inter 2000 fall 3 rise 2
•    server master3 192.168.1.17:6443 check inter 2000 fall 3 rise 2
EOF

lb1作为master,keepalived.conf配置如下:

bash 复制代码
# 备份并写入 lb1 的配置 (作为 MASTER)
mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
​
cat > /etc/keepalived/keepalived.conf <<EOF
global_defs {
   router_id LVS_DEVEL
}
​
vrrp_script check_haproxy {
    script "killall -0 haproxy"
    interval 3
    weight -20
}
​
vrrp_instance VI_1 {
    state BACKUP
    nopreempt                      # <--- 开启非抢占模式
    interface ens160               # <--- 请核对你的网卡名称
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass k8s_ha
    }
    unicast_src_ip 192.168.1.13   # 本机 IP,告诉 Keepalived:用本机的这个 IP 发送心跳
    unicast_peer {
        192.168.1.14              # 对端 IP,告诉 Keepalived:不要用大喇叭喊了,直接打电话给这个具体的 IP
    }
    virtual_ipaddress {
        192.168.1.12              # VIP
    }
    track_script {
        check_haproxy
    }
}
EOF

关于state为BACKUP的解释:为什么作为主节点master的LB1也要设置成BACKUP,而不是master,因为设置成master, 如果LB1 发生硬件故障,处于"不断重启-崩溃-重启"的死循环中,VIP 就会在两台机器之间疯狂来回切换(术语叫网络震荡/Flapping),这会导致所有的 API 请求持续被重置。所以还要加上一个参数nopreempt开启非抢占模式。

lb2作为backup,配置:

perl 复制代码
# 备份并写入 lb2 的配置 (作为 BACKUP)
mv /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
​
cat > /etc/keepalived/keepalived.conf <<EOF
global_defs {
   router_id LVS_DEVEL
}
​
vrrp_script check_haproxy {
    script "killall -0 haproxy"
    interval 3
    weight -20
}
​
vrrp_instance VI_1 {
    state BACKUP                  # 状态为备节点
    interface ens160              # <--- 请核对你的网卡名称
    virtual_router_id 51
    priority 90                   # 优先级降低
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass k8s_ha
    }
    unicast_src_ip 192.168.1.14   # 本机 IP
    unicast_peer {
        192.168.1.13              # 对端 IP
    }
    virtual_ipaddress {
        192.168.1.12              # VIP
    }
    track_script {
        check_haproxy
    }
}
EOF

2 master&node配置:

开启 IPv4 转发与网桥过滤

bash 复制代码
cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
​
modprobe overlay
modprobe br_netfilter
​
cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF
​
sysctl --system

(4 台节点都要执行)

安装并配置 containerd 容器运行时

bash 复制代码
# 卸载可能冲突的包(Rocky 9 常见自带) 
dnf remove -y podman buildah
# 添加阿里云的 Docker CE 稳定版仓库
dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 安装 containerd
dnf install -y containerd.io
# 1. 创建配置目录
mkdir -p /etc/containerd
# 2. 导出 containerd 的默认完整配置
containerd config default > /etc/containerd/config.toml
# 3. 将 SystemdCgroup 的值从 false 替换为 true
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml
# 4. 启动 containerd 并设置开机自启
systemctl enable --now containerd
# 5. 检查状态确保处于 active (running)
systemctl status containerd -l --no-pager | grep Active

第一步:配置 K8S 国内源并安装组件

ini 复制代码
# 1. 写入 Kubernetes v1.36 的阿里云 YUM 源
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.36/rpm/
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.36/rpm/repodata/repomd.xml.key
EOF
​
# 2. 清理缓存并安装三大核心组件
dnf clean all
dnf makecache
dnf install -y kubelet kubeadm kubectl
​
# 3. 设置 kubelet 开机自启(千万不要现在 start,它会被 kubeadm init 自动唤醒)
systemctl enable kubelet

第二步:编写集群初始化剧本(仅在 master1 执行)

很多新手喜欢用一长串的命令行参数(比如 kubeadm init --control-plane-endpoint...)去初始化集群。但在生产环境和高可用架构中,作为架构师,我们永远优先推荐使用 YAML 配置文件。 这样不仅便于复查和归档,还能对底层参数(如 Cgroup 驱动)进行最精细的控制。

yaml 复制代码
# 创建一个专门存放配置的目录
mkdir -p /opt/k8s
cd /opt/k8s
​
# 编写 kubeadm-config.yaml
cat > kubeadm-config.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: "v1.36.0"
# 核心:指向我们刚刚做好的高可用 VIP 和 HAProxy 端口
controlPlaneEndpoint: "192.168.1.12:16443"
# 核心:使用阿里云镜像仓库替换谷歌官方仓库,拉取速度飞快
imageRepository: "registry.aliyuncs.com/google_containers"
networking:
  # 预留给网络插件(如 Calico)的 Pod 网段,这个 10.244.0.0/16 是最通用的
  podSubnet: "10.244.0.0/16"
  serviceSubnet: "10.96.0.0/12"
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
# 核心:确保 Kubelet 的 Cgroup 驱动与 containerd 保持一致,使用 systemd
cgroupDriver: "systemd"
EOF

第三步:正式点火(仅在 master1 执行)

配置文件准备就绪。我们可以让 kubeadm 先提前拉取一下必需的镜像,确认网络畅通,然后再执行初始化。

master1 上执行:

ini 复制代码
# 1. 预拉取镜像(这步如果能顺利秒跑完,说明阿里云源配置非常完美)
kubeadm config images pull --config=kubeadm-config.yaml
​
# 2. 正式初始化集群,并加上 --upload-certs 参数(非常重要!)
# --upload-certs 会将控制平面的证书加密上传到 k8s 的 secret 中,
# 这样后续加入 master2 和 master3 时,就不需要我们手动去拷贝证书文件了。
kubeadm init --config=kubeadm-config.yaml --upload-certs

假如没有启动成功,报错:

vbscript 复制代码
[kubelet-start] Starting the kubelet
​
error: error execution phase wait-control-plane: cannot obtain client without bootstrap: could not bootstrap the admin user in file admin.conf: unable to create ClusterRoleBinding: client rate limiter Wait returned an error: rate: Wait(n=1) would exceed context deadline
​
To see the stack trace of this error execute with --v=5 or higher 
​

是因为Containerd 的 Pause 镜像被墙了。

虽然我们在 kubeadm-config.yaml 中把镜像源改成了阿里云 (registry.aliyuncs.com/google_containers),K8S 的核心组件镜像也确实拉下来了。但是,Containerd 容器运行时自身底层默认写死了 去谷歌的 registry.k8s.io 拉取沙箱容器镜像(Pause 镜像)。 因为国内网络拉不到这个 Pause 镜像,哪怕 API Server 的镜像已经就绪,Pod 也永远无法创建,最终导致 kubeadm init 苦苦等待直到超时。

我们需要清理失败的残局,填平这个暗坑,然后重新点火。请在 master1 上严格按以下三步执行:

第一步:清理失败的残局(极其重要)

初始化失败后,系统会残留很多损坏的证书和配置文件。如果不清理干净,下一次 init 会直接秒报错。 在 master1 上执行:

bash 复制代码
kubeadm reset -f
rm -rf /etc/kubernetes/ /var/lib/etcd/ /var/lib/kubelet/ $HOME/.kube/config
rm -rf /etc/cni/net.d

第二步:修复 Containerd 的 Pause 镜像源(暗坑修复)

我们需要把 Containerd 配置文件里写死的官方 Pause 镜像替换为阿里云的镜像。 在 master1 上执行以下命令(建议后续在 master2, master3, node1 上也执行一次):

bash 复制代码
# 替换默认的 registry.k8s.io 为阿里云源
sed -i 's#registry.k8s.io/pause#registry.aliyuncs.com/google_containers/pause#g' /etc/containerd/config.toml
​
# 重启 containerd 让配置生效
systemctl restart containerd
​
# 确认替换成功(你应该能看到包含 aliyuncs 的 sandbox_image 这一行)
grep sandbox_image /etc/containerd/config.toml

第三步:确认网络并重新启动

为了确保咱们刚才那段时间 VIP 没有乱飘,顺手检查一下网络,然后再次使用配置文件初始化。 依然在 master1 上执行:

ini 复制代码
# 1. 确认 VIP 还能 ping 通(或者在 lb1 上看看 192.168.1.12 还在不在)
ping -c 2 192.168.1.12
​
# 2. 重新执行初始化
kubeadm init --config=kubeadm-config.yaml --upload-certs

成功后可以看到提示:

sql 复制代码
Your Kubernetes control-plane has initialized successfully!
​
To start using your cluster, you need to run the following as a regular user:
​
  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config
​
Alternatively, if you are the root user, you can run:
​
  export KUBECONFIG=/etc/kubernetes/admin.conf
​
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/
​
You can now join any number of control-plane nodes running the following command on each as root:
​
  kubeadm join 192.168.1.12:16443 --token 8sw2dh.53a7g0oviif1tydp \
        --discovery-token-ca-cert-hash sha256:fdbb4312c296b41d107039387c372ad0915be1f5bbe793320d3040162d67a89b \
        --control-plane --certificate-key a6d59374aae5555d7860551b9b6ca1ef9ee879e358efc5018bfe0d6c333f0195
​
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
​
Then you can join any number of worker nodes by running the following on each as root:
​
kubeadm join 192.168.1.12:16443 --token 8sw2dh.53a7g0oviif1tydp \
        --discovery-token-ca-cert-hash sha256:fdbb4312c296b41d107039387c372ad0915be1f5bbe793320d3040162d67a89b
​

第一步:在 master1 上配置管理员权限

为了能让 master1 使用 kubectl 命令管理集群,你需要把刚才生成的管理员凭证复制到当前用户的目录下。 请在 master1 上执行:

bash 复制代码
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
​
# 验证一下,看看我们的单台控制面是否就绪
kubectl get nodes
# 此时你应该能看到 master1 的状态为 NotReady(这是正常的,因为还没装网络插件)。

第二步:将 master2 和 master3 加入控制平面

要让另外两台机器作为平等的 Master 节点加入,我们需要一个"证书解密密钥"。

  1. 重新获取证书密钥(在 master1 上执行):
csharp 复制代码
kubeadm init phase upload-certs --upload-certs

组装并执行高可用加入命令(在 master2master3 上分别执行): 把刚才生成的密钥,拼接到你发给我的那段基础命令后面。完整的命令格式如下:

sql 复制代码
kubeadm join 192.168.1.12:16443 --token 8sw2dh.53a7g0oviif1tydp \
        --discovery-token-ca-cert-hash sha256:fdbb4312c296b41d107039387c372ad0915be1f5bbe793320d3040162d67a89b \
        --control-plane --certificate-key e01454b570b5036d3a3f147013e64251e3d71159429919f4f235d8fab60e432f

node节点:

sql 复制代码
kubeadm join 192.168.1.12:16443 --token 8sw2dh.53a7g0oviif1tydp \
        --discovery-token-ca-cert-hash sha256:fdbb4312c296b41d107039387c372ad0915be1f5bbe793320d3040162d67a89b

最后的 阶段 3:打通集群网络脉络

安装 Calico 网络插件(集群神经网络)

标准的生产级高可用架构,Calico 是最推荐的 CNI 插件,性能强悍且支持网络策略。

master1 上执行以下命令来部署 Calico:

bash 复制代码
# 1. 下载 Calico 配置文件 (如果 raw.githubusercontent 被墙,这一步可能会卡)
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml
# 2. 将 docker.io 批量替换为华为云的代理源
sed -i 's#docker.io/calico/#swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/calico/#g' calico.yaml
# 3. 应用配置
kubectl apply -f calico.yaml

国内环境,如果第一条 curl 命令一直卡住或报错拒绝连接,可以直接使用国内的加速服务下载:)

ruby 复制代码
# 国内备用下载命令
curl -O https://mirror.ghproxy.com/https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml
# 将 docker.io 批量替换为华为云的代理源
sed -i 's#docker.io/calico/#swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/calico/#g' calico.yaml
​
kubectl apply -f calico.yaml

部署完 Calico 后,K8S 会自动在每个节点上拉取网络组件的镜像。这个过程大概需要 1-3 分钟。

可以用下面这条命令实时"监视" Pod 的启动过程(按 Ctrl+C 退出):

sql 复制代码
watch kubectl get pods -n kube-system -o wide

最后,pod全部running,代表高可用k8s集群搭建成功。

演练:模拟 LB 节点宕机(VIP 漂移测试)

动作一:确认当前 VIP 归属lb1 (13) 和 lb2 (14) 上分别执行:

css 复制代码
ip a | grep 192.168.1.12

找出 VIP 现在到底挂在谁身上(按照咱们之前的配置,它现在大概率在 lb1 上)。

动作二:开启实时监控 API 流量 在任意一台 Master 上(比如 master1),让 kubectl 强制通过 VIP 去请求集群状态,并每秒刷新一次:

arduino 复制代码
watch -n 1 "kubectl --server=https://192.168.1.12:16443 get nodes"

动作三:实施"物理级毁灭" 切回 VMware 宿主机,找到当前挂着 VIP 的那台 LB 虚拟机(比如 lb1)执行关机。

盯着刚才在 master1 上开的 watch 监控窗口会发现,在关机的瞬间,画面可能会停顿 1 到 2 秒钟,然后立刻恢复持续刷新!完全没有报错崩溃。如果这个演练成功了,就说明流量入口已经做到了真正的无单点故障。

相关推荐
江华森5 小时前
Spring Cloud 微服务全栈实战:从 Eureka 到 Docker Compose 一文贯通
运维
江华森5 小时前
Matplotlib 数据绘图基础入门
运维
江华森5 小时前
NumPy 数值计算基础入门
运维
乘云数字DATABUFF4 天前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--6 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森6 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜7 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB8 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode9 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏