☰
Kylin ARM集群离线部署K8S多主多从:containerd直连与高可用实践
2026/10/7 18:10:22 网站建设 项目流程

简介:面向麒麟Kylin V10操作系统与ARM架构CPU环境,这套离线资源合集提供了基于containerd部署Kubernetes 1.26.15多主多从集群的完整素材,适合国产化替代背景下需要自建高可用K8S的运维人员与架构师。包内共47个文件,以系统镜像包(gz)、rpm安装包、shell脚本及yml/yaml/service等配置文件为主,其中既包含kube-apiserver、etcd、coredns、calico等核心组件镜像,也提供keepalived高可用配置、kubeadm初始化与节点加入脚本,整体约622MB,结构清晰可直接落地参考。已有254人学习浏览。其核心价值在于将离线部署所需的关键部分集中整理:从containerd运行时、kubeadm/kubelet二进制到网络插件与负载均衡配置均有覆盖,配合多主多从架构的编排思路,可显著降低在ARM+麒麟环境下搭建生产级K8S集群的调研与踩坑成本。

1. Kylin ARM 集群:为什么不选 Docker,而是 containerd 直连

在 Kylin V10 的 ARM 架构服务器上部署 K8S 1.26.15 多主多从集群,我第一个踩的坑不是 kubeadm 命令,而是容器运行时选型。网上大量教程默认先装 Docker 再让 K8S 调用,但 K8S 从 1.24 开始就把 containerd 作为默认运行时,ARM 版麒麟的 Docker 包不全不说,装完还得处理 cgroup driver、手动改 pause 镜像,绕一大圈回到原点。这份资源合集把 ARM 架构下需要的 containerd 1.7.2、pause-3.9、etcd 3.5.10、各组件镜像和 kubeadm 配置模板全部提前打包,内网离线也能直接拉起一套多主多从集群。适合要在国产 ARM 服务器上快速交付 K8S 环境的运维和交付工程师。

2. 环境初始化:rpm 离线包、内核模块与 hosts 解析

2.1 节点规划与架构确认

先把拓扑定下来。多主多从我建议按三主两从来做,三个 master 承载 apiserver、controller-manager、scheduler 和 etcd,两个 node 跑业务负载。资源包里对应的就是 kubeadm-first-master.yml、kubeadm-join-master.yml 和 kubeadm-join-node.yml 三套模板,分别对应第一台主节点、后续主节点和从节点三种初始化方式。

角色主机名推荐配置说明
master1master014C8G首个控制面节点
master2master024C8G第二控制面节点
master3master034C8G第三控制面节点
node1node014C8G运行业务负载
node2node024C8G运行业务负载

动手前先用 uname -m 确认内核架构是 aarch64,如果是 x86_64 的机器,这套 ARM 资源包就用不上。cat /etc/os-release 确认系统是 Kylin Linux Advanced Server V10,子版本一般是 Halberd,内核停在 Linux 4.19 系列。这两个信息直接决定后续依赖包和镜像选型,我习惯在每台机器上都跑一遍确认再继续。

uname -m cat /etc/os-release cat /proc/version

uname -m 返回 aarch64 才说明这套资源里的 arm64 二进制和镜像能直接用;/etc/os-release 里能看到 V10 的具体子版本号,SP1 和 SP2 在部分依赖包的 glibc 版本上有细微差异,不过资源包里的 rpm 都是兼容实测过的,SP1/SP2 都能装。内核版本建议不低于 4.19,太老的内核缺少 IPVS 模块支持。

2.2 离线 rpm 依赖安装

资源包里有个 pkgs 目录,里面是针对 ARM 麒麟编译好的依赖包,包括 ipvsadm、conntrack、ebtables、socat、ipset、sysstat。其中 ipvsadm 和 ipset 是 kube-proxy 开启 IPVS 模式时的核心依赖,socat 是 kubeadm 做端口检查时要用到的,ebtables 和 conntrack 被 kube-proxy 和网络插件调用。sysstat 不是集群必需,但排查 CPU 和 IO 问题时非常好用,我一般顺手装上。

cd pkgs for rpm in $(ls *.rpm | sort); do rpm -ivh --nodeps "$rpm" || echo "install $rpm failed" done

这里用 rpm -ivh 而不是 yum install,是因为离线环境没有可用软件源,--nodeps 可以跳过极少数无意义的依赖检查,但前提是你清楚这个包的真实依赖已经满足。实际安装时我遇到过个别包因为 glibc 版本被卡住,把报错里提示的冲突包用 rpm -e 先卸掉再装就能过。装完 ipvsadm 后建议用 ipvsadm -L 验证一下模块能否正常加载。

2.3 内核模块与 sysctl 参数

K8S 集群对内核有两个硬性要求:桥接流量要能走 iptables,IPVS 相关模块要能加载。ARM 麒麟的 4.19 内核默认不会自动加载这些模块,需要手动 modprobe,并把开机自动加载写进 /etc/modules-load.d/k8s.conf。

cat > /etc/modules-load.d/k8s.conf <<EOF br_netfilter nf_conntrack ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh EOF for m in br_netfilter nf_conntrack ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh; do modprobe $m done

br_netfilter 让 bridge 上的流量也能被 iptables 规则过滤,K8S 的 Service 和 Pod 通信都依赖这个。ip_vs 系列模块是 kube-proxy IPVS 模式的基础,模块不全时 kube-proxy 会报错并从 IPVS 回退到 iptables。加载完用 lsmod | grep ip_vs 确认,如果有缺失模块,检查内核是否编译了对应功能。

内核参数也要调整,主要三条:net.bridge.bridge-nf-call-iptables 控制 iptables 对 bridge 流量的过滤,net.ipv4.ip_forward 开启路由转发,vm.swappiness 调低避免 swap 干扰 kubelet。

cat > /etc/sysctl.d/k8s.conf <<EOF net.bridge.bridge-nf-call-iptables = 1 net.ipv4.ip_forward = 1 vm.swappiness = 0 EOF sysctl --system

vm.swappiness = 0 是因为 kubelet 对 swap 很敏感,1.26 虽然支持通过 --fail-swap-on=false 容忍 swap,但生产环境建议直接关闭 swap 或者只保留极少量的分页空间。sysctl --system 之后用 sysctl net.ipv4.ip_forward 确认参数已生效,这个参数没开的话,Pod 之间跨节点通信会静默失败。

2.4 主机名与 hosts 解析

多主多从集群里,etcd、apiserver、kubelet 之间大量通过主机名互相访问,机房 DNS 不给力或者干脆没有内网 DNS 时,就得把 /etc/hosts 写死。

hostnamectl set-hostname master01 cat >> /etc/hosts <<EOF 192.168.10.11 master01 192.168.10.12 master02 192.168.10.13 master03 192.168.10.14 node01 192.168.10.15 node02 EOF

注意一定要把当前节点自己的 IP 和主机名也写进去,否则 kubelet 注册节点时会因为无法解析本机 hostname 而卡在 NotReady。这一步不要省,很多 join 之后节点状态异常的案例,最后查出来就是 hosts 漏了本机条目。所有节点的主机名建议统一规划,不要用 localhost 或带下划线的名字,K8S 对主机名里的下划线会直接拒绝。

3. containerd 1.7.2 配置:从解压到 crictl 拉通

3.1 解压 cri-containerd-cni 与 libseccomp 处理

资源包里 cri-containerd-cni-1.7.2-linux-arm64.tar.gz 是 containerd 官方发布的 ARM 版打包,里面已经包含了 containerd、ctr、crictl 和标准 CNI 插件,不需要再额外装 runc。解压直接到根目录,它会自动落到 /usr/local/bin、/etc/containerd、/opt/cni 等标准路径。

tar -C / -xzf cri-containerd-cni-1.7.2-linux-arm64.tar.gz

解压后验证一下 containerd 版本,ARM 版和 x86 版在命令输出上没有任何差别,但二进制文件格式是 aarch64 的,不能在 x86 机器上跑。此时先别急着启动 containerd,ARM 麒麟自带的 libseccomp 版本可能偏老,containerd 启动时加载 seccomp 过滤规则会报符号找不到的错误,资源包里单独带的 libseccomp.so.2 就是用来替换的。

cp libseccomp.so.2 /usr/lib64/ # 或 /lib/aarch64-linux-gnu/ ldconfig ldconfig -p | grep libseccomp

具体放哪个目录,取决于你系统里 libseccomp.so.2 目前所在的路径,用 ldconfig -p | grep libseccomp 查一下原路径再覆盖。这一步做完之后,再启动 containerd 就不会出现 seccomp 相关的加载失败。这个坑在 ARM 麒麟上出现频率很高,x86 的 CentOS 很少遇到,所以我单独列出来。

3.2 config.toml:SystemdCgroup、sandbox_image 与 registry

containerd 默认配置不满足 K8S 的要求,必须改两处:cgroup 驱动和 pause 镜像。K8S 1.26 的 kubelet 默认使用 systemd cgroup driver,containerd 如果不对齐,Pod 启动时 kubelet 会报 cgroup driver 不匹配直接拒绝创建沙箱。

mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml
# 在 /etc/containerd/config.toml 中修改或确认以下关键项 [plugins."io.containerd.grpc.v1.cri"] sandbox_image = "registry.k8s.io/pause:3.9" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true

SystemdCgroup = true 让 containerd 用 systemd 来管理 pause 容器的 cgroup,这样与 kubelet 的 cgroup driver 一致。sandbox_image 是每个 Pod 创建时最先拉取的 pause 镜像,K8S 1.26.15 对应的是 pause:3.9,资源包里 pause-3.9.tar.gz 已经打好,导入后把这个值指向导入后的仓库地址即可,避免离线环境下去 registry.k8s.io 拉取超时。

registry 镜像加速的配置也建议顺手加上,虽然离线环境用本地镜像为主,但万一后面要拉公网镜像,没有 mirror 配置的话会一直卡在 ImagePullBackOff。内网 Harbor 或者 Nexus 的地址,按实际环境替换。

3.3 load_images.sh 离线导入全量镜像

资源包 images 目录下放着所有组件镜像的 tar.gz,包括 kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy、etcd、coredns、pause 和 Calico 全家桶。导入时用 ctr 而不是 docker load,因为 containerd 环境下 ctr 直接对接 containerd 的本地存储。

#!/bin/bash # load_images.sh for img in images/*.tar.gz; do ctr -n k8s.io images import "$img" done

关键点在于 -n k8s.io 这个命名空间参数。kubelet 默认通过 CRI 访问 containerd 的 k8s.io 命名空间,而 ctr 默认访问的是 default 命名空间,如果导入时不指定,kubelet 会看不到这些镜像。导入完成后用 ctr -n k8s.io images list 核对,确认每个镜像的 repo 和 tag 都正确。

这里有个容易被忽略的细节:镜像的 repo 名称必须和你 kubeadm 配置里要用的名称一致。比如 kube-apiserver 打包时如果带的前缀是 registry.k8s.io,那么 kubeadm 默认拉取路径就是 registry.k8s.io/kube-apiserver:v1.26.15,只要本地存在这个 tag,kubeadm 就不会再尝试去网络拉取。所以导入后不要随意改 tag,除非你同时改了 kubeadm 配置里的 imageRepository。

3.4 crictl 验证运行时链路

crictl 是排查 containerd 问题的核心工具,但它默认连的是 docker socket,必须配置 /etc/crictl.yaml 指向 containerd 的 socket,否则一执行就报 connection refused。

cat > /etc/crictl.yaml <<EOF runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 5 EOF systemctl daemon-reload systemctl enable --now containerd crictl version crictl images

crictl version 能看到 CRI 版本和 containerd 版本,确认服务端正常响应。crictl images 列出镜像列表,检查 pause 和 kube-apiserver 是否都在。这步相当于把容器运行时链路先拉通,再去做 kubeadm 初始化,能够把问题边界切得非常干净,后面 kubeadm 报错时你不会再怀疑 containerd 本身没装好。

4. kubeadm 多主多从:first-master 初始化到两类 join

4.1 kubelet、kubeadm、kubectl 二进制安装

资源包里有编译好的 v1.26.15 版本 kubeadm、kubelet、kubectl 二进制,直接放到 /usr/bin 并加上可执行权限。这三个二进制是从官方 1.26.15 版本抽出来的,直接用即可,注意不要混用其他小版本的 kubelet 和 kubeadm,组件版本不一致会出现 API 版本协商失败。

cp kubeadm kubectl kubelet /usr/bin/ chmod +x /usr/bin/kubeadm /usr/bin/kubectl /usr/bin/kubelet kubeadm version kubelet --version

kubelet 需要 systemd 托管,资源包里带了 kubelet.service 和 10-kubeadm.conf。10-kubeadm.conf 是 systemd drop-in 配置,核心作用是给 kubelet 指定启动参数,包括 bootstrap-kubeconfig 和 kubelet 配置文件路径,这部分不用自己写,直接放到 /etc/systemd/system/kubelet.service.d/ 目录下即可。

cp kubelet.service /etc/systemd/system/kubelet.service mkdir -p /etc/systemd/system/kubelet.service.d cp 10-kubeadm.conf /etc/systemd/system/kubelet.service.d/10-kubeadm.conf systemctl daemon-reload systemctl enable --now kubelet

此时 kubelet 会因为还没有集群而反复重启报错,这是正常的,不要慌。kubelet 启动后会一直尝试连接 apiserver,只有在 kubeadm join 或 init 之后才能稳定运行。只要 systemctl status kubelet 能看到 active 并且在不断重试,就说明配置本身没问题。

4.2 kubeadm-first-master.yml 关键参数

第一台 master 的初始化模板是 kubeadm-first-master.yml,它决定了整个集群的控制面端点、Pod 网段和 Service 网段。这个文件是三台 master 共用的,因为 controlPlaneEndpoint 指向的是 VIP,而不是某个具体节点的 IP。

apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.10.11 --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.26.15 controlPlaneEndpoint: 192.168.10.100:6443 networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12

controlPlaneEndpoint 必须写成 keepalived 提供的 VIP 加端口,这样所有 join 进来的节点都会通过 VIP 访问 apiserver,VIP 在三台 master 之间漂移时,节点端的 kubelet 不需要做任何调整。podSubnet 用 10.244.0.0/16 是因为 Calico 默认的 IPAM 池和这个网段一致,如果不改 Calico 配置,这里就不要改网段。serviceSubnet 保持默认的 10.96.0.0/12 即可。

4.3 初始化与 kubeconfig 分发

配置检查无误后,在 master01 上执行初始化。整个初始化过程会拉取 etcd、apiserver、controller-manager、scheduler、coredns 等镜像,因为前面已经完成了离线导入,本地仓库里有对应镜像,kubeadm 会直接使用本地镜像,不会去外网拉取。

kubeadm init --config kubeadm-first-master.yml --v=5

初始化成功的标志是最后输出一段提示,包含 kubeconfig 配置命令和一条完整的 kubeadm join 命令。先把 kubectl 的 kubeconfig 配置好,这一步不做的话 kubectl 无法连接集群。

mkdir -p $HOME/.kube cp /etc/kubernetes/admin.conf $HOME/.kube/config kubectl get nodes

然后把 admin.conf 分发到其他节点,后续在 master02、master03 和 node 节点上操作时都需要这个文件。建议统一都放到用户家目录的 .kube/config 路径下,避免每台机器都重新生成证书。

scp /etc/kubernetes/admin.conf root@master02:/root/.kube/config scp /etc/kubernetes/admin.conf root@master03:/root/.kube/config scp /etc/kubernetes/admin.conf root@node01:/root/.kube/config scp /etc/kubernetes/admin.conf root@node02:/root/.kube/config

4.4 join-master 与 join-node 的模板差异

多主多从的本质区别在于:master 用 kubeadm-join-master.yml,node 用 kubeadm-join-node.yml。先拿 token 和 CA 哈希,再到新节点上执行 join。

kubeadm token create --print-join-command kubeadm init phase upload-certs --upload-certs

kubeadm token create --print-join-command 会输出一行标准的 join 命令,包含 token 和 discovery-token-ca-cert-hash。kubeadm init phase upload-certs --upload-certs 用来把控制面的证书加密上传,输出的 certificate-key 是 join 新 master 时的必填参数,依赖这个 key 来解密控制面证书,然后复制到新 master 上。

# master02 / master03 执行,增加 --control-plane 和 --certificate-key kubeadm join 192.168.10.100:6443 \ --token <token> \ --discovery-token-ca-cert-hash sha256:<hash> \ --control-plane \ --certificate-key <key> # node01 / node02 执行,不带 --control-plane kubeadm join 192.168.10.100:6443 \ --token <token> \ --discovery-token-ca-cert-hash sha256:<hash>

master 和 node 的 join 命令差别就这两行参数:control-plane 和 certificate-key。带 control-plane 的节点会额外部署 etcd 成员、apiserver、controller-manager、scheduler 这些控制面组件,不带 control-plane 的节点只启动 kubelet 和 kube-proxy。证书 key 是一次性用品,如果过期或者换 token,重新执行一次 kubeadm init phase upload-certs 再拿新的即可。

5. 高可用与 Calico:keepalived、kube-lb 与 CNI 配合

5.1 keepalived 配置与 VIP 生效

控制面高可用依赖 VIP 在三台 master 之间漂移。VIP 就是 kubeadm 配置里写死的 controlPlaneEndpoint 地址,它由 keepalived 负责维护,正常情况落在 master01 上,master01 故障时自动跳到 master02 或 master03。

# /etc/keepalived/keepalived.conf master01 配置 global_defs { router_id K8S_LVS } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass K8S_VIP } virtual_ipaddress { 192.168.10.100/24 dev eth0 } }

master02 和 master03 的配置只改两处:state 改为 BACKUP,priority 改为 90 和 80。priority 决定抢占顺序,数值越大优先级越高。VIP 的 netmask 要和业务网段一致,否则其他节点访问 VIP 时会因为路由问题通不了。配置完成后启动 keepalived,用 ip addr show eth0 能看到 VIP 已经在 master01 上。

systemctl enable --now keepalived ip addr show eth0 | grep 192.168.10.100

有个坑容易忽略:firewalld 会拦 VRRP 广播协议,如果 VIP 在节点间切不出去,先检查防火墙是否放行了 vrrp,或者干脆在测试环境临时停掉 firewalld。keepalived 本身不做流量转发,它只负责通告 VIP,真正的 apiserver 流量要靠下一层的 kube-lb。

5.2 kube-lb 四层转发:VIP 到 apiserver

keepalived 把 VIP 挂到本机网卡后,访问 VIP:6443 的流量会进入本机内核,此时需要一个四层代理把流量转发到三台 master 的 apiserver。资源包里的 kube-lb 就是干这个的,它是轻量级四层负载均衡,配置在 kube-lb.conf 里指定后端列表。

cp kube-lb /usr/local/bin/ cp kube-lb.conf /etc/kube-lb/kube-lb.conf cp kube-lb.service /etc/systemd/system/ systemctl daemon-reload systemctl enable --now kube-lb

kube-lb.conf 的核心是定义一个监听 6443 的前端和后端列表,后端就是三台 master 的 apiserver 地址。三个后端都标记为 check,kube-lb 会周期性做 TCP 健康检查,某个节点挂掉后自动从转发列表中摘除。

frontend k8s-apiserver bind *:6443 default_backend k8s-masters backend k8s-masters server master01 192.168.10.11:6443 check inter 3s fall 3 rise 2 server master02 192.168.10.12:6443 check inter 3s fall 3 rise 2 server master03 192.168.10.13:6443 check inter 3s fall 3 rise 2

kube-lb 必须和 keepalived 同时运行在同一台 master 上,keepalived 负责让 VIP 出现在本机,kube-lb 负责接管本机 6443 端口的流量并转发。验证方法很简单:在三台 master 的任何一台执行 curl https://192.168.10.100:6443/healthz -k,能看到 ok 就说明 VIP 到 apiserver 的链路是通的。如果返回 refused,先确认当前 VIP 在哪台机器上,再到那台机器看 kube-lb 是否在运行。

5.3 Calico 3.26.4 ARM 镜像与网段对齐

控制面起来之后,Pod 网络还是空的,kubectl get nodes 会看到节点全部 NotReady,因为容器网络插件没有安装。资源包里的 calico.yaml 是 3.26.4 版本,对应 ARM 架构的镜像也已经在 images 目录里打好了包。

Calico 安装前要改两处:镜像地址和 Pod 网段。离线环境下 kubelet 不会去拉公网镜像,所以 calico.yaml 里的 image 字段必须和你导入镜像时的 repo 完全一致。资源包里的镜像名是 calico-node-v3.26.4.tar.gz,导入后的默认 tag 一般是 calico/node:v3.26.4,把 yaml 里的 image 字段同步改掉即可。

grep -n "image:" calico.yaml | head -20 sed -i 's|docker.io/calico/node:v3.26.4|calico/node:v3.26.4|g' calico.yaml sed -i 's|docker.io/calico/calico-cni:v3.26.4|calico/cni:v3.26.4|g' calico.yaml kubectl apply -f calico.yaml

网段对齐也很关键。Calico 默认的 IPv4 池是 192.168.0.0/16,而 kubeadm-first-master.yml 里 podSubnet 写的是 10.244.0.0/16,两者不一致的话,Calico 会给 Pod 分配 192.168 网段的 IP,kubelet 却认为 Pod 应该在 10.244 网段,Pod 直接创建失败。需要在 calico.yaml 里把 CALICO_IPV4POOL_CIDR 改成 10.244.0.0/16。

# calico.yaml 中的 ConfigMap 部分 - name: CALICO_IPV4POOL_CIDR value: "10.244.0.0/16"

Calico 启动后,还需要确认每个节点的转发网卡。ARM 服务器经常有多网卡,Calico 默认自动选择第一个可用网卡做隧道,如果选错会导致跨节点 Pod 不通。一般在 calico-node 的 DaemonSet 环境变量里加一条 IP_AUTODETECTION_METHOD 指定内网网卡名,比如 eth0,这个值根据实际规划改。

6. 验证与常见问题排查:让集群真正可交付

6.1 集群健康检查清单

集群搭建完不要急着部署业务,先把基础链路验证一遍。我从资源包里的 test、nginx、busybox 这套验证组合里挑最简单的方式:起一个 nginx 无头服务,从其他节点访问,检查跨节点打通情况。

kubectl get nodes -o wide kubectl get pods -A kubectl get svc -A kubectl run nginx-test --image=nginx --restart=Never --port=80 kubectl wait --for=condition=Ready pod/nginx-test --timeout=120s kubectl get pod nginx-test -o wide

kubectl get nodes 所有节点 Ready,kubectl get pods -A 里 coredns 和 calico 全部 Running,基础网络就算通了。nginx-test 跨节点访问验证,确认调度到 node01 上的 Pod 能从 node02 访问通,这一步检查的是 Calico 的跨节点路由,很多集群 Pod 本地通、跨节点不通的问题都是在这一步暴露的。

6.2 高频踩坑记录

kubelet 报 cgroup driver 不匹配。现象是 kubelet 日志反复出现 failed to run Kubelet: "cgroup driver" 相关内容,kubelet 起不来。原因是 containerd 的 SystemdCgroup 没有开启,而 kubelet 默认用 systemd driver。解决方法是改 /etc/containerd/config.toml 里 SystemdCgroup = true,重启 containerd 和 kubelet。

crictl images 能看到镜像但 Pod 一直 ErrImagePull。现象是 Pod 事件里报 Failed to pull image,明明本地有镜像。原因是 sandbox_image 的 repo 和你导入时的 tag 不一致,kubelet 按配置的完整地址去本地仓库找,找不到就尝试外网拉取。解决方法是把 sandbox_image 改成 ctr -n k8s.io images list 里显示的完整名称。

node join 后一直 NotReady,describe 显示 CNI 未初始化。现象是 kubectl get nodes 看到节点 NotReady,describe 里 network plugin is not ready: cni config uninitialized。原因是 Calico 的 Pod 还没在这个节点上运行,或者 calico.yaml 里的网段与 kubeadm 配置不一致。解决方法是先确认 calico.yaml 的 CALICO_IPV4POOL_CIDR,再 kubectl apply 完整应用 Calico。

第二个 master join 后 etcd 集群异常。现象是 kubectl get nodes 能看到三台 master,但 etcd 容器反复重启,日志报 member 加入失败。原因是 join 时丢失 --certificate-key 参数,或者 certificate-key 过期。解决方法是重新执行 kubeadm init phase upload-certs --upload-certs 生成新 key,再次执行干净的 join。

VIP 在 master 间漂移后 kubectl 失联。现象是 master01 宕机后 VIP 切到 master02,但 kubectl 连不上集群。原因是 kube-lb 只运行在 master01 上,其它 master 没接管流量转发。解决方法是把 kube-lb 做成 systemd 服务并在三台 master 上都启用,keepalived 和 kube-lb 必须同时运行在同一台机器,VIP 漂到哪台,哪台的 6443 就必须有转发进程在监听。

从那以后我在 ARM 麒麟上搭 K8S,每次都是先跑一遍 get_images.sh 确认仓库,再 load_images.sh 导入镜像,然后才动 kubeadm init。这五条坑覆盖了从运行时到网络插件的大部分故障场景,资源包里配套的脚本和 test 镜像都齐,照着这套流程走一遍,基本上一个工作日能拉起一套可交付的多主多从集群。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询