简介这份资源合集面向需要在国产化平台上落地云原生环境的运维与架构人员聚焦Kylin V10操作系统与ARM架构CPU组合下使用containerd作为容器运行时部署Kubernetes 1.26.15多主多从高可用集群的完整实践。包内共47个文件涵盖gz镜像包、rpm依赖、sh脚本、conf与service配置、yml/yaml清单等类型分别用于镜像导入、系统依赖安装、containerd与kubelet服务配置、kubeadm初始化及Calico网络部署压缩包约622MB。资源中提供了kube-lb与keepalived相关配置配合多主节点实现控制平面高可用并附带镜像拉取与加载脚本、kubeadm主节点初始化及工作节点加入模板便于按角色快速搭建集群。目前已有254人学习下载适合希望掌握ARM平台K8S部署流程、理解containerd集成与高可用配置细节的中高级技术人员参考。1. 麒麟 V10 ARM 上跑 containerd 版 K8S 1.26这套组合到底解决什么问题信创项目里最常被问到的一句话是你们这套 K8S 到底能不能跑在国产 CPU 和麒麟系统上我最近刚交付的一套环境就是 Kylin V10Halberd 内核 ARM 架构 CPU containerd 运行时 K8S 1.26.15 的多主多从集群。之所以选 containerd 而不是 Docker是因为 1.24 之后 K8S 已经彻底移除了 dockershimcontainerd 作为 CRI 直接对接 kubelet调用链更短、资源占用更低在 ARM 服务器上这点尤其明显。这套方案适合正在做信创适配、需要离线部署、又不想被 Docker 中间层拖性能的运维和平台工程师。下面我把从系统准备到集群跑通的全过程拆开讲包括 ARM 镜像怎么选、containerd 配置怎么写、多 master 的 etcd 怎么摆、以及那个让人抓狂的the api server is not healthy after 4m0.00747357s到底怎么解。2. 麒麟 V10 ARM 的前置准备系统层要先把哪些坑填平2.1 确认 CPU 架构与系统版本别拿 x86 的包硬套ARM 服务器上第一件事不是装 K8S而是确认你手里的机器到底是什么架构。Kylin V10 有 x86_64 版也有 aarch64 版包管理器和内核参数都不一样。执行下面几条命令把底摸清楚# 确认 CPU 架构aarch64 才是 ARM 64 位 uname -m # 查看麒麟具体版本和内核 cat /etc/kylin-release uname -r # 确认 containerd 和 kubelet 的包架构 rpm -qa | grep -E containerd|kubelet|kubeadmuname -m输出aarch64说明是 ARM 64 位后面所有二进制包、镜像都必须选 arm64 版本。/etc/kylin-release里会写明是 V10 还是 V10 SP1SP1 对 cgroup v2 的支持更完整K8S 1.26 默认走 systemd cgroup 驱动这点要对上。如果rpm -qa查出来是 x86_64 的包别犹豫直接卸掉重装混架构的包在 ARM 上跑不起来报错还特别隐蔽。2.2 关 swap、调内核参数、对齐时间K8S 对 swap 是零容忍的kubelet 启动时会直接拒绝。ARM 服务器上有些出厂镜像默认开了 swap必须关掉并写进 fstab否则重启后又回来# 临时关闭 swapoff -a # 永久关闭注释掉 swap 行 sed -ri s/.*swap.*/#/ /etc/fstab # 加载内核模块 modprobe br_netfilter modprobe overlay # 写入开机加载 cat /etc/modules-load.d/k8s.conf EOF br_netfilter overlay EOF # 内核参数 cat /etc/sysctl.d/k8s.conf EOF net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 EOF sysctl --systembr_netfilter和overlay这两个模块是 containerd 和 Service 转发的基础ARM 内核里通常都有但默认不加载。net.ipv4.ip_forward1不打开Pod 跨节点通信直接断。时间同步用 chronyd 或 ntpd 都行多 master 的 etcd 对时钟漂移很敏感超过 500ms 就可能选主异常。2.3 离线环境下的 ARM 镜像与二进制包从哪来信创环境大多不能直连外网ARM 的镜像和二进制包得提前准备好。常见做法是在一台能联网的 ARM 机器上用ctr或skopeo把镜像拉下来导出成 tar 再拷进内网# 在联网 ARM 机器上拉取并导出 ctr -n k8s.io images pull registry.k8s.io/kube-apiserver:v1.26.15 ctr -n k8s.io images export kube-apiserver-v1.26.15.tar \ registry.k8s.io/kube-apiserver:v1.26.15 # 内网机器导入 ctr -n k8s.io images import kube-apiserver-v1.26.15.tarkubeadm、kubelet、kubectl 这三个二进制也要选 arm64 版本从官方或镜像站下载后放到/usr/local/bin。注意 containerd 的版本别太新也别太旧1.6.x 系列和 K8S 1.26 配合最稳1.7 以上有些配置项名字变了容易踩坑。3. containerd 配置与 kubelet 对接CRI 这条链路怎么调通3.1 生成默认配置并改三处关键参数containerd 装好后先别急着启动用containerd config default生成一份完整配置再改关键项# 生成默认配置 containerd config default /etc/containerd/config.toml # 改三处SystemdCgroup、sandbox_image、镜像仓库 sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml sed -i s#sandbox_image .*#sandbox_image registry.k8s.io/pause:3.9# /etc/containerd/config.toml systemctl restart containerd systemctl enable containerdSystemdCgroup true必须改K8S 1.26 的 kubelet 默认用 systemd cgroup 驱动containerd 这边如果还是 cgroupfs两边对不上Pod 起来后资源限制会失效甚至启动失败。sandbox_image是 Pod 的 pause 容器镜像ARM 上要确认这个镜像有 arm64 版本pause:3.9 是有的。改完重启 containerd用ctr version确认服务正常。3.2 配置私有镜像仓库加速拉取内网环境通常有 Harbor 或 registry把仓库地址写进 containerd 配置避免每次拉镜像都走外网# /etc/containerd/config.toml 片段 [plugins.io.containerd.grpc.v1.cri.registry.mirrors] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.docker.io] endpoint [https://harbor.internal.com] [plugins.io.containerd.grpc.v1.cri.registry.mirrors.registry.k8s.io] endpoint [https://harbor.internal.com]endpoint指向你的内网仓库containerd 拉docker.io或registry.k8s.io的镜像时会自动重定向过去。如果仓库是 HTTP 的还要在registry.configs里加insecure_skip_verify或plain_http。改完systemctl restart containerd用ctr -n k8s.io images pull测试一下能不能拉到。3.3 kubelet 的 cgroup 驱动和容器运行时端点kubelet 启动参数里要明确指定容器运行时端点和 cgroup 驱动否则它可能去找 Docker 的 socket# /var/lib/kubelet/kubeadm-flags.env 或 kubelet 启动参数 --container-runtime-endpointunix:///run/containerd/containerd.sock --cgroup-driversystemdcontainerd.sock的路径默认在/run/containerd/containerd.sock麒麟系统上如果 containerd 是用 systemd 管理的这个路径一般不变。cgroup-driversystemd要和 containerd 的SystemdCgroup true保持一致。改完systemctl daemon-reload systemctl restart kubelet用crictl info看运行时状态crictl ps能列出容器就说明链路通了。4. 多主多从集群初始化kubeadm 在 ARM 上的实操与参数4.1 第一个 master 节点初始化绕开 api server 健康检查超时多主多从的第一步是初始化第一个 master但 ARM 上经常卡在the api server is not healthy after 4m0.00747357s。这个报错九成是镜像没拉全或者 containerd 配置不对。先手动把 kubeadm 需要的镜像拉下来# 查看需要哪些镜像 kubeadm config images list --kubernetes-version v1.26.15 # 手动拉取ARM 上确认是 arm64 镜像 kubeadm config images pull --kubernetes-version v1.26.15 \ --image-repository registry.aliyuncs.com/google_containers--image-repository换成你的内网仓库或国内镜像源ARM 上要确认仓库里有 arm64 的 manifest。镜像拉全后执行初始化kubeadm init \ --kubernetes-version v1.26.15 \ --control-plane-endpoint k8s-vip.internal.com:6443 \ --pod-network-cidr 10.244.0.0/16 \ --service-cidr 10.96.0.0/12 \ --image-repository registry.aliyuncs.com/google_containers \ --upload-certs--control-plane-endpoint指向 VIP 或负载均衡地址多 master 必须用这个不能写单节点 IP。--upload-certs把证书加密上传到 etcd后面加 master 节点时用--control-plane和--certificate-key直接拉取省去手动拷贝证书。--pod-network-cidr和--service-cidr别和现有网络冲突ARM 环境里如果用了 Calico 或 FlannelCIDR 要对上。4.2 加入其余 master 和 worker 节点第一个 master 初始化成功后会输出 join 命令。加 master 节点用带--control-plane的那条kubeadm join k8s-vip.internal.com:6443 \ --token token \ --discovery-token-ca-cert-hash sha256:hash \ --control-plane \ --certificate-key key加 worker 节点去掉--control-plane和--certificate-key即可。ARM 节点加入时如果卡在Waiting for the kubelet to boot up多半是 kubelet 没起来或者 containerd 没配好去journalctl -u kubelet -f看日志。多 master 的 etcd 会自动组成集群用kubectl get nodes确认所有节点 Readykubectl get pods -n kube-system看核心组件是否正常。4.3 安装网络插件并验证跨节点通信CNI 插件选 Calico 或 Flannel 都行ARM 上 Calico 的镜像要确认有 arm64 版本kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml # 或者离线方式 kubectl apply -f calico-arm64.yaml装完等几分钟kubectl get pods -n kube-system -o wide看 calico-node 是否每个节点都 Running。然后起一个测试 Pod 验证跨节点通信kubectl run test-nginx --imagenginx:alpine --port80 kubectl expose pod test-nginx --port80 --target-port80 kubectl get svc test-nginx用kubectl exec进到另一个节点的 Pod 里curl这个 Service 的 ClusterIP能通就说明网络没问题。ARM 上 nginx:alpine 有 arm64 版本如果拉不下来就换成内网仓库里的镜像。5. 避坑与排查ARM 麒麟 containerd 组合下最容易翻车的几件事5.1 现象kubelet 报failed to run Kubelet: misconfiguration: kubelet cgroup driver: cgroupfs is different from docker cgroup driver: systemd原因containerd 的SystemdCgroup没改成 true或者 kubelet 的--cgroup-driver还是 cgroupfs两边不一致。麒麟 V10 默认 cgroup 版本可能是 v1K8S 1.26 推荐 systemd 驱动必须对齐。解决确认/etc/containerd/config.toml里SystemdCgroup truekubelet 启动参数里--cgroup-driversystemd然后systemctl restart containerd kubelet。如果还报错检查/var/lib/kubelet/config.yaml里的cgroupDriver字段。5.2 现象the api server is not healthy after 4m0.00747357skubeadm init 卡住原因kube-apiserver 的静态 Pod 没起来通常是镜像没拉全、containerd 配置错误、或者 6443 端口被占用。ARM 上还可能是 pause 镜像架构不对。解决先crictl ps -a看容器状态crictl logs container-id看具体报错。如果是镜像问题用kubeadm config images pull手动拉如果是端口占用ss -tlnp | grep 6443查一下如果是 pause 镜像确认sandbox_image指向的镜像有 arm64 版本。5.3 现象Pod 一直 Pendingdescribe 显示no nodes available to schedule pods原因节点 NotReady或者有污点没容忍。ARM 节点上常见的是 kubelet 没起来、CNI 没装好、或者节点资源不足。解决kubectl describe node node-name看 Conditions 和 Taintsjournalctl -u kubelet -f看 kubelet 日志。如果是 CNI 问题确认 calico-node 或 flannel 的 Pod 是否 Running如果是污点用kubectl taint nodes node-name key:effect-去掉。5.4 现象跨节点 Pod 通信不通ping 或 curl 超时原因net.ipv4.ip_forward没开、br_netfilter没加载、或者 CNI 的 CIDR 和节点网络冲突。解决sysctl net.ipv4.ip_forward确认是 1lsmod | grep br_netfilter确认模块加载。检查 CNI 配置里的podCIDR是否和kubeadm init时的--pod-network-cidr一致。ARM 上有些内核版本对 overlay 网络支持有差异Calico 的 IPIP 模式可能更稳。5.5 现象etcd 集群频繁选主master 节点不稳定原因多 master 的 etcd 对时钟和网络延迟敏感ARM 服务器上如果 NTP 没配好或者网络抖动大就会频繁选主。解决所有 master 节点用同一 NTP 源chronyc sources确认同步状态。etcd 的数据盘要用 SSDetcdctl endpoint status看 leader 是否稳定。如果网络延迟大考虑把 etcd 和 master 分开部署或者调整--heartbeat-interval和--election-timeout。6. 集群跑通后的验证与日常维护技巧集群起来只是第一步后面怎么确认它真的稳才是信创环境里更耗精力的事。我一般会先跑一轮基础验证kubectl get componentstatuses看核心组件健康度kubectl get nodes -o wide确认所有节点 Ready 且版本一致kubectl get pods -n kube-system看系统 Pod 有没有反复重启的。然后起一个带 PVC 的 StatefulSet验证存储、网络、调度三条链路都通。ARM 上存储插件也要选 arm64 版本比如 NFS 或 Ceph 的 CSI 驱动。日常维护里最值得养成的习惯是定期导出 etcd 快照。多 master 的 etcd 一旦出问题没有快照就只能重装集群# 在任意 master 上执行 etcd 快照备份 ETCDCTL_API3 etcdctl snapshot save /backup/etcd-$(date %Y%m%d).db \ --endpointshttps://127.0.0.1:2379 \ --cacert/etc/kubernetes/pki/etcd/ca.crt \ --cert/etc/kubernetes/pki/etcd/server.crt \ --key/etc/kubernetes/pki/etcd/server.key # 验证快照 ETCDCTL_API3 etcdctl snapshot status /backup/etcd-20250101.db--endpoints指向本地 etcd证书路径是 kubeadm 默认生成的。快照文件建议异地保存别和 etcd 数据盘放一起。恢复的时候用etcdctl snapshot restore然后改 etcd 静态 Pod 的--data-dir指向恢复出来的目录重启 etcd 和 apiserver。另一个技巧是给 kubelet 和 containerd 配日志轮转。ARM 服务器磁盘通常不大容器日志和系统日志涨得很快/etc/docker/daemon.json那套在 containerd 上不适用得改/etc/containerd/config.toml里的max_container_log_line_size和 kubelet 的--container-log-max-size。我一般设成 100Mi 上限、保留 5 个文件避免日志把根分区撑满。最后说个血泪教训ARM 环境里千万别用 x86 的镜像凑合哪怕 containerd 能拉下来跑起来也会因为指令集不兼容直接崩而且报错信息往往指向别的地方查半天查不到根因。每次拉镜像前用docker manifest inspect或skopeo inspect确认有 arm64 的 manifest这个习惯能省下大量排查时间。希望帮到你。本文还有配套的精品资源点击获取