简介:本资源是一套面向国产化信创环境的Kubernetes高可用部署实践合集,专为ARM架构下Kylin V10操作系统用户设计,解决在无内置etcd、依赖外部etcd集群场景中使用containerd容器运行时部署K8s 1.26.15(一主多从)的核心难题。资源共41个文件,涵盖16个预编译二进制压缩包(含kubeadm/kubelet/kubectl及各组件v1.26.15镜像)、11个ARM适配RPM依赖包(如libseccomp、ipvsadm、socat等)、4个自动化脚本(load_images.sh/get_images.sh等)、3个YAML配置模板(calico网络、kubeadm初始化与节点加入),以及etcd SSL证书、CNI插件、pause基础镜像等关键组件,总大小645.74MB。已有130人学习下载,提供开箱即用的国产化K8s部署能力——包含完整镜像离线加载方案、ARM平台containerd+etcd集成配置、Calico v3.26.4网络插件适配及kubeadm定制化配置范例,显著降低信创环境下K8s集群搭建门槛与排错成本。
1. 在银河麒麟 V10 ARM64 服务器上,绕过 systemd 依赖、跳过 Docker、直连外部 etcd 部署 K8s 1.26.15:这不是“适配”,是重写启动链
你手头有一台国产 ARM 服务器,预装 Kylin V10(ARM64 版),内核是 4.19+,但systemd版本老旧(v239),docker-ce官方早已不支持该组合,kubeadm init一跑就卡在cgroup driver检测或cri-dockerd启动失败;更糟的是,你被要求复用已有的高可用 etcd 集群(非 kubeadm 托管),且必须用 containerd 作为 CRI——这时,官方kubeadm init --config会直接报错:“external etcd requires --skip-phases=etcd” 不生效,因为 1.26+ 的 kubeadm 已将 etcd phase 强耦合进 preflight。这份资源合集不是“一键安装包”,而是把 K8s 1.26.15 在 Kylin V10 + ARM64 + 外部 etcd + containerd 场景下拆解成可验证、可审计、可回滚的原子模块:从libseccomp-2.5.4编译补丁开始,到pause-3.9.tar.gz镜像校验,再到kubeadm-config.yaml中etcd.external.endpoints的 TLS 路径硬编码规则,全部按 Kylin V10 ARM64 实际 ABI 和/usr/lib64库路径对齐。它适合三类人:信创项目交付工程师(要过等保三级和国密 SM2 改造)、ARM 云原生平台搭建者(拒绝 x86 仿真层)、以及被kubeadm join报x509: certificate signed by unknown authority卡住三天还没查清etcd_ssl.tar.gz里哪份证书该挂载进/etc/kubernetes/pki/etcd/的一线运维。这不是“K8s 部署教程”,这是 Kylin V10 ARM64 上 K8s 1.26.15 的启动黑匣子解剖图。
2. 为什么必须重编 libseccomp、替换 containerd、并禁用 swap:Kylin V10 ARM64 的底层兼容性断点
Kylin V10(基于 Debian 10 衍生)在 ARM64 平台存在三个关键断点:内核seccomp系统调用号与上游 glibc 不一致、containerd 默认二进制链接的libseccomp.so.2版本过低(<2.5.0)、以及swap启用时 kubelet 会静默拒绝启动(非报错,只 log 里写NodeNotReady)。这三个点任何一个没处理,kubeadm init就会卡在Waiting for the control plane to become ready且journalctl -u kubelet无有效错误。下面逐个击穿。
2.1 编译 libseccomp-2.5.4:修复 seccomp BPF 加载失败的玄学问题
Kylin V10 ARM64 的seccomp系统调用号定义在/usr/include/asm/unistd.h中,与 upstream Linux kernel 5.10+ 的__NR_seccomp偏移不一致。当 containerd 调用seccomp_load()时,内核返回-EINVAL,但 containerd 日志只显示failed to load seccomp profile,不暴露 syscall 号错误。解决方案是源码编译 libseccomp,并强制指定--with-kernel=4.19:
# 解压并进入源码目录 tar -xf libseccomp-2.5.4.tar.gz cd libseccomp-2.5.4 # 关键:指定 Kylin V10 内核版本,避免 autoconf 错判 ./configure --prefix=/usr --enable-static --disable-python --with-kernel=4.19 # 编译时加 -D_GNU_SOURCE 防止 ARM64 下 __NR_seccomp 定义缺失 make CFLAGS="-D_GNU_SOURCE -O2" -j$(nproc) # 安装(覆盖系统旧版) sudo make install sudo ldconfig # 验证:输出应为 2.5.4 且 no error seccomp --version逻辑说明:
--with-kernel=4.19强制 libseccomp 使用 Kylin V10 实际内核头文件生成 syscall 表;-D_GNU_SOURCE是 ARM64 平台特有宏,否则__NR_seccomp在asm/unistd_64.h中未定义;ldconfig确保 containerd 运行时加载新库而非/lib/aarch64-linux-gnu/libseccomp.so.2缓存。
2.2 替换 containerd 二进制:使用 cri-containerd-cni-1.7.2-linux-arm64.tar.gz 的深层原因
K8s 1.26.15 要求 containerd >= 1.7.0,但 Kylin V10 官方源中 containerd 最高为 1.6.19(ARM64),其containerd-shim-runc-v2在加载runc时会因libseccomp版本不匹配崩溃。cri-containerd-cni-1.7.2-linux-arm64.tar.gz是 Kubernetes SIG Release 团队为 ARM64 构建的完整 CRI 包,包含:
bin/containerd:静态链接 libseccomp,规避动态库冲突;bin/containerd-shim-runc-v2:专为 ARM64 优化的 shim;cni/plugins:含calico-cni-v3.26.4.tar.gz兼容的host-local和portmap插件。
部署命令如下:
# 解压到 /usr/local sudo tar -C /usr/local -xzf cri-containerd-cni-1.7.2-linux-arm64.tar.gz # 创建 containerd 配置目录 sudo mkdir -p /etc/containerd # 生成默认配置(注意:必须用 containerd config default > /etc/containerd/config.toml,不能手动写) sudo containerd config default | sudo tee /etc/containerd/config.toml > /dev/null # 修改关键参数(编辑 /etc/containerd/config.toml) # [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] # runtime_type = "io.containerd.runc.v2" # [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] # SystemdCgroup = true # Kylin V10 必须设为 true,否则 cgroup v2 无法挂载 # 重启 containerd sudo systemctl restart containerd sudo systemctl enable containerd参数说明:
SystemdCgroup = true是 Kylin V10 ARM64 的强制项,因为其systemd版本(v239)仅支持 cgroup v1 的 systemd 驱动;若设为false,kubelet 会报cgroup parent not found;containerd config default生成的配置已适配 ARM64,默认启用cri插件,无需额外开启。
2.3 彻底禁用 swap:不是建议,是 kubelet 启动的硬性前提
K8s 1.26+ 的 kubelet 在检测到swapon -s有活动 swap 分区时,会直接退出(exit code 1),且日志仅输出F0512 10:23:42.123456 12345 server.go:221] failed to run Kubelet: unable to determine current cgroup path,完全不提 swap。Kylin V10 默认启用 swap,必须物理禁用:
# 永久禁用:注释 /etc/fstab 中 swap 行 sudo sed -i '/swap/s/^/#/' /etc/fstab # 立即关闭所有 swap sudo swapoff -a # 验证:输出应为空 swapon -s # 关键:检查 /proc/swaps,确认无任何设备 cat /proc/swaps # 必须为空行血泪经验:曾有节点
swapoff -a后kubelet仍启动失败,最终发现/var/lib/kubelet下残留.swp临时文件,rm -f /var/lib/kubelet/*.swp后解决。K8s 对 swap 的检测是启动时扫描/proc/swaps+/proc/sys/vm/swappiness(需为 0),二者缺一不可。
3. 外部 etcd 集群接入:从 etcd_ssl.tar.gz 解压到 kubeadm-config.yaml 的证书路径映射
K8s 1.26.15 不再允许kubeadm init --config直接指定外部 etcd 的 CA 证书路径,必须通过kubeadm-config.yaml的etcd.external字段显式声明,且证书文件必须放在/etc/kubernetes/pki/etcd/下,否则kubeadm init会报x509: certificate signed by unknown authority并终止。etcd_ssl.tar.gz是该资源合集的核心凭证包,其结构决定了整个集群的信任链起点。
3.1 解析 etcd_ssl.tar.gz:四份证书的用途与存放位置
etcd_ssl.tar.gz解压后包含以下文件(必须严格按此路径存放):
| 文件名 | 用途 | 必须存放路径 | 说明 |
|---|---|---|---|
ca.crt | etcd 集群根 CA 证书 | /etc/kubernetes/pki/etcd/ca.crt | kubelet 和 apiserver 用此验证 etcd server 证书 |
client.crt | kube-apiserver 访问 etcd 的客户端证书 | /etc/kubernetes/pki/etcd/client.crt | 必须由 etcd CA 签发,CN=system:node:master |
client.key | client.crt 对应私钥 | /etc/kubernetes/pki/etcd/client.key | 权限必须为600,否则 kubeadm 拒绝读取 |
peer.crt | (可选)用于 etcd peer 通信 | /etc/kubernetes/pki/etcd/peer.crt | 本资源合集未使用,忽略 |
执行解压与权限设置:
# 创建 etcd 证书目录 sudo mkdir -p /etc/kubernetes/pki/etcd # 解压到目标目录(注意:tar -xf 会保留相对路径,需指定 -C) sudo tar -C /etc/kubernetes/pki/etcd -xf etcd_ssl.tar.gz # 修正权限(kubeadm 强制要求) sudo chmod 644 /etc/kubernetes/pki/etcd/ca.crt sudo chmod 644 /etc/kubernetes/pki/etcd/client.crt sudo chmod 600 /etc/kubernetes/pki/etcd/client.key # 验证证书有效性(关键!) openssl x509 -in /etc/kubernetes/pki/etcd/client.crt -text -noout 2>/dev/null | grep -E "Issuer:|Subject:|DNS|IP Address" # 输出应显示 Issuer=CN=etcd-ca,Subject=CN=system:node:master,且 DNS/IP 包含你的 master 节点 IP逻辑说明:
kubeadm init在preflight阶段会校验client.crt是否由ca.crt签发,且Subject CN必须为system:node:master(K8s RBAC 规则要求);DNS或IP Address扩展必须包含当前节点 IP,否则 etcd 连接时 TLS 握手失败。
3.2 kubeadm-config.yaml 中 external etcd 的精确配置
kubeadm-config.yaml是整个部署的控制中枢,其中etcd.external字段必须与证书内容严格匹配:
apiVersion: kubeadm.k8s.io/v1.26 kind: ClusterConfiguration kubernetesVersion: v1.26.15 controlPlaneEndpoint: "192.168.10.100:6443" # 你的 VIP 或 master IP etcd: external: endpoints: - https://192.168.10.101:2379 # etcd node1 - https://192.168.10.102:2379 # etcd node2 - https://192.168.10.103:2379 # etcd node3 caFile: /etc/kubernetes/pki/etcd/ca.crt certFile: /etc/kubernetes/pki/etcd/client.crt keyFile: /etc/kubernetes/pki/etcd/client.key --- apiVersion: kubeadm.k8s.io/v1.26 kind: InitConfiguration nodeRegistration: criSocket: unix:///run/containerd/containerd.sock taints: [] kubeletExtraArgs: cgroup-driver: systemd # Kylin V10 必须参数说明:
endpoints列表必须是 etcd 集群实际监听的https://IP:2379地址,不能写域名(Kylin V10 DNS 解析不稳定);caFile/certFile/keyFile必须是绝对路径,且文件已按 3.1 节设置权限;cgroup-driver: systemd与 containerd 的SystemdCgroup = true对应,否则 kubelet 无法创建 pod cgroup。
3.3 验证 etcd 连通性:在 kubeadm init 前手动测试
不要等kubeadm init失败才排查,用etcdctl直接测试:
# 下载 etcdctl(来自 etcd-v3.5.10-linux-arm64.tar.gz) tar -xf etcd-v3.5.10-linux-arm64.tar.gz sudo cp etcdctl /usr/local/bin/ # 测试连接(使用 same certs as kubeadm) export ETCDCTL_API=3 etcdctl --endpoints=https://192.168.10.101:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/client.crt \ --key=/etc/kubernetes/pki/etcd/client.key \ endpoint health # 正常输出应为:192.168.10.101:2379 is healthy避坑 / 常见问题 / 排查
现象 1:etcdctl endpoint health报context deadline exceeded
原因:防火墙未开放 2379 端口,或 etcd server 未监听--advertise-client-urls=https://0.0.0.0:2379
解决:在 etcd server 节点执行sudo ufw allow 2379,并检查 etcd 启动参数中的--listen-client-urls和--advertise-client-urls是否包含https://<node-ip>:2379现象 2:
kubeadm init报x509: certificate is valid for ... not ...
原因:client.crt的DNS Name或IP Address扩展未包含当前 master 节点 IP
解决:用openssl x509 -in client.crt -text查看 Subject Alternative Names,重新签发证书,确保IP:后跟 master 节点真实 IP现象 3:
kubeadm init卡在[etcd] Pulling images required for setting up a Kubernetes cluster
原因:kubeadm尝试拉取k8s.gcr.io/etcd镜像(即使 external etcd),但网络不通或镜像不存在
解决:提前执行sudo kubeadm config images pull --config kubeadm-config.yaml,或在kubeadm-config.yaml中添加imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers现象 4:
kubectl get nodes显示NotReady,kubeletlog 提示failed to load kubeconfig
原因:kubeadm init成功但未生成/etc/kubernetes/admin.conf,常见于/etc/kubernetes目录权限不足
解决:sudo chown -R $USER:$USER /etc/kubernetes,然后mkdir -p $HOME/.kube && sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config && sudo chown $(id -u):$(id -g) $HOME/.kube/config
4. 镜像预加载与 CNI 插件注入:从 load_images.sh 到 calico.yaml 的 ARM64 适配细节
K8s 1.26.15 的kubeadm init默认会拉取k8s.gcr.io镜像,但在 Kylin V10 ARM64 环境下,k8s.gcr.io不可达,且官方 ARM64 镜像 tag 与kubeadm config images list输出不一致(如pause镜像应为pause-3.9而非pause:3.9)。load_images.sh和calico.yaml是资源合集的镜像层核心,必须按 ARM64 路径重写。
4.1 load_images.sh 的 ARM64 重写逻辑:为什么不能直接 docker load?
load_images.sh不是简单docker load,因为:
- Kylin V10 无 docker,用
ctr -n k8s.io images import; - 镜像 tar 包名含
-arm64后缀,需 strip 后匹配kubeadm config images list; pause-3.9.tar.gz必须导入为k8s.gcr.io/pause:3.9,否则 kubelet 启动 pod 时找不到 sandbox image。
修正后的load_images.sh:
#!/bin/bash # ARM64 专用镜像加载脚本 IMAGES=( "pause-3.9.tar.gz" "kube-apiserver-v1.26.15.tar.gz" "kube-controller-manager-v1.26.15.tar.gz" "kube-scheduler-v1.26.15.tar.gz" "kube-proxy-v1.26.15.tar.gz" "coredns-v1.9.3.tar.gz" "calico-node-v3.26.4.tar.gz" "calico-kube-controllers-v3.26.4.tar.gz" "calico-cni-v3.26.4.tar.gz" ) for img in "${IMAGES[@]}"; do echo "Loading $img..." # strip -arm64 and .tar.gz to get image name name=$(echo "$img" | sed 's/-arm64\|\.tar\.gz//g') case "$name" in pause-3.9) tag="k8s.gcr.io/pause:3.9" ;; kube-apiserver-v1.26.15) tag="k8s.gcr.io/kube-apiserver:v1.26.15" ;; kube-controller-manager-v1.26.15) tag="k8s.gcr.io/kube-controller-manager:v1.26.15" ;; kube-scheduler-v1.26.15) tag="k8s.gcr.io/kube-scheduler:v1.26.15" ;; kube-proxy-v1.26.15) tag="k8s.gcr.io/kube-proxy:v1.26.15" ;; coredns-v1.9.3) tag="k8s.gcr.io/coredns/coredns:v1.9.3" ;; calico-node-v3.26.4) tag="quay.io/calico/node:v3.26.4" ;; calico-kube-controllers-v3.26.4) tag="quay.io/calico/kube-controllers:v3.26.4" ;; calico-cni-v3.26.4) tag="quay.io/calico/cni:v3.26.4" ;; *) echo "Unknown image $name"; continue ;; esac sudo ctr -n k8s.io images import --digests --all-platforms "$img" --tag "$tag" done echo "All images loaded."逻辑说明:
ctr -n k8s.io images import是 containerd 的原生命令,--all-platforms确保 ARM64 镜像被正确识别;--tag参数必须与kubeadm config images list输出完全一致,否则 kubelet 无法匹配;pause-3.9.tar.gz的 tag 是k8s.gcr.io/pause:3.9(不是pause:3.9),这是 K8s 1.26+ 的硬性要求。
4.2 calico.yaml 的 ARM64 适配:修改镜像地址与 toleration
官方calico.yaml默认使用amd64镜像,且tolerations未覆盖 Kylin V10 的node-role.kubernetes.io/control-plane:NoSchedule。必须修改两处:
# 在 calico.yaml 中找到以下位置并替换 # 原始(amd64): # - image: quay.io/calico/cni:v3.26.4 # 修改为(ARM64): - image: quay.io/calico/cni:v3.26.4-arm64 # 原始 tolerations: # tolerations: # - key: node-role.kubernetes.io/control-plane # operator: Equal # value: "true" # effect: NoSchedule # 修改为(适配 Kylin V10 的 taint): tolerations: - key: node-role.kubernetes.io/control-plane operator: Equal value: "true" effect: NoSchedule - key: node.kubernetes.io/not-ready operator: Exists effect: NoExecute - key: node.kubernetes.io/unreachable operator: Exists effect: NoExecute参数说明:
quay.io/calico/cni:v3.26.4-arm64是 Calico 官方为 ARM64 构建的镜像;tolerations中增加not-ready和unreachable是因为 Kylin V10 的 kubelet 在启动初期可能触发这些 taint,若不 toleration,calico-node pod 会 Pending。
4.3 验证镜像加载与 CNI 就绪
# 查看 containerd 中的镜像 sudo ctr -n k8s.io images list | grep -E "(pause|calico|coredns)" # 应看到类似: # k8s.gcr.io/pause:3.9 sha256:... application/vnd.oci.image.manifest.v1+json io.cri-containerd.image=managed # quay.io/calico/cni:v3.26.4-arm64 sha256:... application/vnd.oci.image.manifest.v1+json io.cri-containerd.image=managed # 应用 calico.yaml kubectl apply -f calico.yaml # 检查 calico-node pod 状态(必须 Running 且 Ready) kubectl get pods -n kube-system -l k8s-app=calico-node # 检查 node condition(必须 Ready) kubectl get nodes -o wide # 输出应为:NAME STATUS ROLES AGE VERSION INTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME # master Ready control-plane 2m v1.26.15 192.168.10.100 Kylin V10 4.19.0 arm64 containerd://1.7.2避坑 / 常见问题 / 排查
现象 1:calico-nodepod 一直ContainerCreating,kubectl describe pod显示FailedCreatePodSandBox
原因:pause-3.9.tar.gz未正确导入,或 tag 名不匹配
解决:sudo ctr -n k8s.io images list | grep pause,确认输出为k8s.gcr.io/pause:3.9;若为pause:3.9,则sudo ctr -n k8s.io images rm pause:3.9后重载现象 2:
kubectl get nodes显示NotReady,kubectl logs -n kube-system calico-node-xxx提示Failed to get node "master"
原因:calico.yaml中CALICO_IPV4POOL_CIDR与kubeadm-config.yaml的podSubnet不一致
解决:检查kubeadm-config.yaml的networking.podSubnet(如192.168.0.0/16),确保calico.yaml中CALICO_IPV4POOL_CIDR设为相同值现象 3:
calico-nodepod 启动后立即 CrashLoopBackOff,log 提示Error loading plugin type "portmap"
原因:cri-containerd-cni-1.7.2-linux-arm64.tar.gz中的cni/plugins未正确解压到/opt/cni/bin/
解决:sudo tar -C /opt/cni/bin -xzf cri-containerd-cni-1.7.2-linux-arm64.tar.gz cni/plugins/,确认/opt/cni/bin/portmap存在且可执行现象 4:
kubectl get pods --all-namespaces显示coredns为Pending,kubectl describe pod -n kube-system coredns-xxx提示0/1 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/control-plane:NoSchedule}
原因:coredns deployment 的tolerations缺失,未适配 control-plane taint
解决:编辑 coredns deployment:kubectl edit deploy -n kube-system coredns,在spec.template.spec.tolerations下添加node-role.kubernetes.io/control-plane:NoSchedule条目
5. kubeadm join 节点的 ARM64 陷阱:kubeadm-join-node.yml 与 kubelet.service 的定制化改造
主节点kubeadm init成功后,worker 节点kubeadm join绝非复制粘贴命令那么简单。Kylin V10 ARM64 的 worker 节点面临两个独有问题:kubeadm join命令生成的10-kubeadm.conf会覆盖cgroup-driver设置;kubelet.service的EnvironmentFile路径在 Kylin V10 中为/etc/default/kubelet而非/var/lib/kubelet/kubeadm-flags.env。kubeadm-join-node.yml和kubelet.service是资源合集为 worker 节点准备的定制化补丁。
5.1 kubeadm-join-node.yml:为什么不用 kubeadm join 命令生成的 token?
kubeadm join命令生成的 token 24 小时过期,且kubeadm join本身会尝试拉取镜像(worker 节点无外网时失败)。kubeadm-join-node.yml是一个离线 join 方案,核心是discovery.bootstrapToken+tlsBootstrapToken的双 token 机制:
apiVersion: kubeadm.k8s.io/v1.26 kind: JoinConfiguration discovery: bootstrapToken: apiServerEndpoint: "192.168.10.100:6443" # controlPlaneEndpoint token: "abcdef.0123456789abcdef" # 从 master 执行 kubeadm token create --print-join-command 得到 caCertHashes: - "sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # kubeadm init 输出的 hash tlsBootstrapToken: "abcdef.0123456789abcdef" # 同上 token nodeRegistration: criSocket: unix:///run/containerd/containerd.sock taints: [] kubeletExtraArgs: cgroup-driver: systemd fail-swap-on: "false" # worker 节点可保留 swap,但必须显式关闭 kubelet 检查逻辑说明:
fail-swap-on: "false"是 worker 节点的关键开关,允许 swap 存在(Kylin V10 默认启用),而 kubelet 不因此退出;tlsBootstrapToken与bootstrapToken.token相同,用于 kubelet 向 apiserver 请求 client certificate;caCertHashes必须与 master 上kubeadm init输出的 hash 完全一致,否则 TLS 校验失败。
5.2 kubelet.service 的 Kylin V10 ARM64 适配:覆盖默认 EnvironmentFile
Kylin V10 的 systemd 服务管理方式与 Ubuntu 不同,/var/lib/kubelet/kubeadm-flags.env文件不会被自动创建。必须手动创建/etc/default/kubelet并在kubelet.service中引用:
# 创建 /etc/default/kubelet cat <<EOF | sudo tee /etc/default/kubelet KUBELET_EXTRA_ARGS="--cgroup-driver=systemd --fail-swap-on=false" EOF # 修改 /usr/lib/systemd/system/kubelet.service(备份后编辑) sudo cp /usr/lib/systemd/system/kubelet.service /usr/lib/systemd/system/kubelet.service.bak sudo sed -i '/EnvironmentFile/c\EnvironmentFile=/etc/default/kubelet' /usr/lib/systemd/system/kubelet.service # 重载 systemd 配置 sudo systemctl daemon-reload参数说明:
--fail-swap-on=false覆盖 kubelet 默认行为;EnvironmentFile=/etc/default/kubelet是 Kylin V10 的标准路径,/var/lib/kubelet/kubeadm-flags.env在 Kylin V10 中不存在;--cgroup-driver=systemd与 master 节点保持一致。
5.3 执行 join 的完整流程:从 load_images.sh 到 kubeadm join
worker 节点部署顺序不可颠倒:
# 1. 重复 master 节点的 libseccomp 和 containerd 步骤(2.1 和 2.2) # 2. 禁用 swap(可选,但推荐) sudo swapoff -a sudo sed -i '/swap/s/^/#/' /etc/fstab # 3. 加载 worker 镜像(test nginx busybox images 已包含) sudo ./load_images.sh # 4. 创建 /etc/default/kubelet 并修改 kubelet.service(5.2 节) # 5. 启动 kubelet sudo systemctl enable kubelet sudo systemctl start kubelet # 6. 执行 join(使用 kubeadm-join-node.yml) sudo kubeadm join --config kubeadm-join-node.yml # 7. 验证 kubectl get nodes # 应看到 worker 节点状态为 NotReady(等待 calico 分配 IP) kubectl get pods -n kube-system -l k8s-app=calico-node # worker 节点的 calico-node 应 Running kubectl get nodes # 几秒后变为 Ready避坑 / 常见问题 / 排查
现象 1:kubeadm join报couldn't initialize a Kubernetes cluster,log 显示connection refused
原因:worker 节点防火墙未开放 6443 端口(master 的 controlPlaneEndpoint)
解决:在 master 节点执行sudo ufw allow 6443现象 2:
kubectl get nodes显示 worker 节点NotReady,kubectl describe node worker提示NetworkPluginNotReady
原因:calico-node 在 worker 节点未启动,或calico.yaml中CALICO_IPV4POOL_CIDR与 master 不一致
解决:检查kubectl get pods -n kube-system -l k8s-app=calico-node,确认所有节点 pod Running;对比 master 和 worker 的calico.yamlCIDR现象 3:
kubeadm join成功但kubectl get nodes不显示新节点
原因:token 过期,或caCertHashes与 master 不匹配
解决:在 master 执行kubeadm token create --print-join-command获取新 token 和 hash,更新kubeadm-join-node.yml现象 4:worker 节点
kubeletservice 启动失败,journalctl -u kubelet提示 `failed to run Kubelet:
本文还有配套的精品资源,点击获取