简介本资源合集面向需要在国产化信创环境下搭建云原生平台的运维与开发人员聚焦Kylin V10操作系统与ARM架构CPU的组合场景通过containerd容器运行时部署Kubernetes 1.26.15一主一从集群。资源包共38个文件约619.64MB涵盖gz镜像与组件包、rpm依赖、sh脚本、yaml配置及service、conf等类型分别用于容器运行时安装、K8S组件部署、网络插件配置与系统依赖补齐并附带kubeadm、kubectl、kubelet等核心二进制文件。目前已有264人学习下载。内容围绕ARM64兼容版本的选型、containerd与CNI插件的落地配置、主从节点初始化与加入流程展开可帮助读者快速获得一套可复用的离线部署素材减少在国产芯片与系统上反复试错的成本适合具备一定Linux与容器基础、希望深入边缘计算或IoT场景的实践者参考。1. 麒麟 V10 ARM 服务器上为什么我坚持用 containerd 而不是 Docker 跑 K8S 1.26.15手里拿到两台鲲鹏或飞腾的 ARM 服务器装好了 Kylin V10 SP2/SP3第一件事往往就是搭一套 K8S 集群。很多人下意识还是apt install docker-ce然后kubeadm init报一堆cgroup driver不匹配的错。我在 ARM 上踩过这个坑之后现在一律用 containerd 作为容器运行时K8S 版本锁在 1.26.15一主一从够用、稳、少折腾。这套组合解决的核心问题是在国产化 ARM 平台上用最少的组件依赖跑通一个生产可用的 K8S 控制面加一个工作节点。适合谁适合手里有 Kylin V10 ARM64 机器、需要离线或半离线部署、又不想被 Docker 和 K8S 版本兼容性反复折磨的运维和平台工程师。下面从选型理由讲到具体命令再到我踩过的坑一步步来。2. 选型定版Kylin V10 ARM64 containerd K8S 1.26.15 的匹配逻辑2.1 为什么是 containerd 而不是 DockerK8S 从 1.24 开始正式移除 dockershimDocker 不再是一等公民运行时。在 ARM 架构上这个问题更明显Docker 的 ARM 包依赖链更长而 containerd 本身就是 CRI 实现kubelet直接通过 CRI 调它少一层转发。Kylin V10 的软件源里 containerd 版本通常够用实在不行用官方静态二进制包ARM64 的 tar 包解压即用不依赖系统包管理器。另一个现实原因ARM 镜像生态里很多基础镜像只提供linux/arm64的 manifestcontainerd 对多架构 manifest 的处理比 Docker 更干净拉镜像时不会出现平台不匹配的玄学报错。2.2 版本锁定K8S 1.26.15 的取舍1.26 是一个长期被企业采用的稳定分支1.26.15 是它的后期补丁版本bug 修复比较充分。再往上 1.27 对内核和 cgroup v2 的要求更激进Kylin V10 默认还是 cgroup v1锁在 1.26.15 能避开不少兼容性问题。组件版本对应关系如下组件版本说明kubeadm / kubelet / kubectl1.26.15三件套版本必须一致containerd1.6.xK8S 1.26 官方验证过的区间runc1.1.x随 containerd 包一起CNI 插件Calico 3.26 或 FlannelARM64 镜像需确认Kylin V10SP2 / SP3内核 4.19 或 5.10注意三件套版本不一致是kubeadm init失败的高频原因装之前先apt list --installed | grep kube确认。2.3 系统前置配置关 swap、开转发、对齐 cgroupARM 服务器装完 Kylin V10 后默认 swap 是开的内核转发也没开。这几步不做后面 kubelet 起不来。# 关闭 swap注释掉 fstab 里的 swap 行防止重启复活 swapoff -a sed -ri s/.*swap.*/#/ /etc/fstab # 加载内核模块 cat /etc/modules-load.d/k8s.conf EOF overlay br_netfilter EOF modprobe overlay modprobe br_netfilter # 开启网桥转发 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 --system # 确认 cgroup 版本Kylin V10 默认 v1 stat -fc %T /sys/fs/cgroup/逻辑说明overlay模块是 containerd 的 snapshotter 依赖br_netfilter让 iptables 能处理网桥流量这是 Calico/Flannel 正常工作的前提。最后一条命令输出cgroup2fs说明是 v2输出tmpfs说明是 v1这个结果决定后面 containerd 配置里SystemdCgroup怎么设。参数说明net.ipv4.ip_forward1必须开否则 Pod 跨节点通信直接断。swapoff -a只对当前生效改 fstab 才是永久。3. 装 containerd 并生成 K8S 能认的配置3.1 安装 containerd 与 runcKylin V10 的源里如果有 containerd 就直接装没有就用官方静态包。ARM64 的包名带arm64后缀别下错成 amd64。# 方式一系统源安装 apt update apt install -y containerd # 方式二官方静态二进制源里版本太老时用 # 下载 containerd-1.6.x-linux-arm64.tar.gz 和 runc.arm64 tar Cxzvf /usr/local containerd-1.6.x-linux-arm64.tar.gz install -m 755 runc.arm64 /usr/local/sbin/runc # 生成默认配置 mkdir -p /etc/containerd containerd config default /etc/containerd/config.toml逻辑说明containerd config default会输出一份完整默认配置但默认的SystemdCgroup是false在 Kylin V10 上必须改成true否则 kubelet 和 containerd 的 cgroup 驱动不一致Pod 起不来。同时默认 pause 镜像指向registry.k8s.io国内环境要换成能访问的镜像地址。3.2 改三个关键参数# 1. 开启 SystemdCgroup sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml # 2. 替换 pause 镜像地址换成你自己的镜像仓库 sed -i s#sandbox_image .*#sandbox_image registry.aliyuncs.com/google_containers/pause:3.9# /etc/containerd/config.toml # 3. 配置镜像加速可选按实际仓库填 # 在 config.toml 的 [plugins.io.containerd.grpc.v1.cri.registry.mirrors] 段添加 systemctl restart containerd systemctl enable containerd systemctl status containerd逻辑说明SystemdCgroup true是 K8S 1.26 Kylin V10 的必改项这是血泪经验不改的话kubelet日志里全是failed to create pod sandbox。pause 镜像版本要和 K8S 1.26 匹配3.9 是安全选择。镜像加速段按你实际的私有仓库或内网 registry 填没有就跳过。参数说明sandbox_image里的 pause 镜像必须能被所有节点拉到一主一从都要配。registry.mirrors的 key 是原始 registry 地址value 是endpoint列表。3.3 验证 containerd 的 CRI 是否就绪# 用 crictl 检查先装 crictl # crictl 版本要和 K8S 1.26 对应用 v1.26.x cat /etc/crictl.yaml EOF runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: false EOF crictl info crictl images逻辑说明crictl info能返回运行时信息说明 containerd 的 CRI 插件正常。如果报连接失败检查/run/containerd/containerd.sock是否存在以及 containerd 服务是否真的起来了。crictl images为空是正常的还没拉镜像。4. kubeadm 初始化主节点与从节点加入4.1 安装 kubeadm、kubelet、kubectl三个组件版本必须锁死 1.26.15ARM64 的 deb 包从 K8S 官方源或内网镜像源拿。# 添加 K8S 源示例按实际内网源替换 apt install -y apt-transport-https ca-certificates curl curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add - cat /etc/apt/sources.list.d/kubernetes.list EOF deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF apt update apt install -y kubelet1.26.15-00 kubeadm1.26.15-00 kubectl1.26.15-00 apt-mark hold kubelet kubeadm kubectl逻辑说明apt-mark hold防止后续apt upgrade把版本升上去K8S 小版本升级有风险生产环境必须锁。ARM64 的包在阿里云源里是有的如果内网源没有需要提前下载 deb 包离线安装。参数说明kubernetes-xenial是源代号虽然名字老但 K8S 官方一直沿用。1.26.15-00的-00是包修订号不能省。4.2 生成初始化配置并执行 kubeadm init不要直接用kubeadm init裸跑先生成配置文件再改可控性高。kubeadm config print init-defaults kubeadm-init.yaml然后编辑kubeadm-init.yaml重点改这几处apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.10 # 主节点实际 IP bindPort: 6443 nodeRegistration: criSocket: unix:///run/containerd/containerd.sock imagePullPolicy: IfNotPresent --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.26.15 imageRepository: registry.aliyuncs.com/google_containers networking: podSubnet: 10.244.0.0/16 # 与 CNI 插件对应 serviceSubnet: 10.96.0.0/12 controlPlaneEndpoint: 192.168.1.10:6443逻辑说明criSocket必须指向 containerd 的 sock不写的话 kubeadm 会去找 Docker。imageRepository换成国内可访问的地址否则拉镜像卡死。podSubnet要和后面装的 CNI 插件网段一致Calico 默认用192.168.0.0/16Flannel 默认10.244.0.0/16这里按 Flannel 配。参数说明advertiseAddress填主节点内网 IPcontrolPlaneEndpoint一主一从场景直接填主节点 IP 加端口。serviceSubnet不要和宿主机网段冲突。执行初始化kubeadm init --config kubeadm-init.yaml --upload-certs初始化成功后按提示配置 kubectlmkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config kubectl get nodes4.3 装 CNI 插件并让主节点可调度一主一从如果主节点不调度从节点挂了就没冗余。测试环境建议去掉主节点污点。# 装 FlannelARM64 镜像需确认 kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml # 去掉主节点污点允许调度 kubectl taint nodes --all node-role.kubernetes.io/control-plane-逻辑说明Flannel 的 yml 里镜像默认是amd64ARM 环境要确认 manifest 支持arm64不支持就换 Calico 或手动改镜像地址。去污点命令末尾的-不能漏漏了就变成加污点。4.4 从节点加入集群在主节点上生成加入命令kubeadm token create --print-join-command在从节点上执行输出的命令形如kubeadm join 192.168.1.10:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx逻辑说明从节点执行 join 前确保 containerd 已装好、swap 已关、内核模块已加载否则 join 会卡在preflight检查。join 成功后回主节点kubectl get nodes应看到两个节点都是Ready。参数说明token 默认 24 小时过期过期后用kubeadm token create重新生成。ca-cert-hash是集群 CA 证书的哈希不能错。5. 避坑排查ARM Kylin V10 上最容易翻车的 5 个点5.1 现象kubelet 反复重启日志报 cgroup 驱动不一致原因containerd 配置里SystemdCgroup false而 kubelet 默认用 systemd 驱动两者对不上。解决改/etc/containerd/config.toml里SystemdCgroup truesystemctl restart containerd然后systemctl restart kubelet。确认stat -fc %T /sys/fs/cgroup/的结果v1 和 v2 都要保证驱动一致。5.2 现象Pod 一直 Pendingdescribe 显示镜像拉取失败原因pause 镜像或业务镜像只有 amd64 版本ARM64 节点拉不下来。或者sandbox_image指向的 registry 不可达。解决crictl pull手动测试镜像能否拉取。确认镜像 manifest 支持linux/arm64不支持就找 ARM 版本或自己构建。sandbox_image换成内网 registry 地址。5.3 现象kubeadm init 卡在 preflight报 swap 未关闭原因swapoff -a只对当前会话生效重启后 fstab 里的 swap 又挂上了。解决sed -ri s/.*swap.*/#/ /etc/fstab永久注释再swapoff -a。free -h确认 swap 为 0。5.4 现象从节点 join 成功但节点 NotReady原因CNI 插件没装或 Flannel 的 ARM64 镜像拉取失败节点上没有网络插件状态就是 NotReady。解决主节点kubectl get pods -n kube-flannel看 Pod 状态如果是ImagePullBackOff改 Flannel yml 里的镜像地址为支持 ARM64 的仓库。或者换 CalicoCalico 的 ARM64 支持更完整。5.5 现象kubectl 能连但 API 响应极慢ARM CPU 占用高原因Kylin V10 默认的kubelet参数没针对 ARM 调优加上 etcd 对磁盘 IO 敏感ARM 服务器如果用的是机械盘或低端 SSDetcd 会拖慢整个控制面。解决给 etcd 单独挂 SSDkubelet的--kube-reserved和--system-reserved按实际内存调别用默认值。ARM 核数多但单核弱--max-pods不要设太大一主一从场景 110 够用。6. 进阶技巧用 kubeadm 配置缓存和离线镜像预拉把部署时间压到 10 分钟内一主一从的集群真正耗时的不是kubeadm init那几分钟而是拉镜像。ARM 镜像本来就少网络再一抖半小时就没了。我的习惯是提前把所有镜像拉到本地用kubeadm config images list列出清单然后批量crictl pull。# 列出 K8S 1.26.15 需要的所有镜像 kubeadm config images list --kubernetes-version v1.26.15 # 批量拉取把上面输出的镜像地址替换进去 for img in \ registry.aliyuncs.com/google_containers/kube-apiserver:v1.26.15 \ registry.aliyuncs.com/google_containers/kube-controller-manager:v1.26.15 \ registry.aliyuncs.com/google_containers/kube-scheduler:v1.26.15 \ registry.aliyuncs.com/google_containers/kube-proxy:v1.26.15 \ registry.aliyuncs.com/google_containers/pause:3.9 \ registry.aliyuncs.com/google_containers/etcd:3.5.6-0 \ registry.aliyuncs.com/google_containers/coredns:v1.9.3 do crictl pull $img done逻辑说明kubeadm config images list输出的镜像地址取决于imageRepository配置先确认地址再拉。crictl pull走的是 containerd 的 CRI拉下来的镜像直接存在 containerd 的 content store 里kubeadm init时imagePullPolicy: IfNotPresent就不会再拉。etcd 版本 3.5.6-0 是 K8S 1.26 的默认值别乱换。参数说明crictl pull的镜像地址必须和kubeadm-init.yaml里的imageRepository拼出来的地址完全一致差一个字符就会重新拉。批量拉之前先crictl images看有没有残留有就crictl rmi清掉避免版本混淆。还有一个技巧把kubeadm-init.yaml和所有镜像清单放在一个目录里用tar打包从节点 join 前也把镜像预拉一遍。这样从节点 join 时不会因为拉 pause 镜像卡住。我一般会在从节点上先跑一遍crictl pull拉 pause 和 kube-proxy这两个是 join 后立刻要用的。验证集群是否真的健康别只看kubectl get nodes。跑一个 ARM64 的测试 Pod确认调度、网络、DNS 都通kubectl run test-arm --imagearm64v8/nginx --restartNever kubectl get pod test-arm -o wide kubectl exec test-arm -- nginx -v kubectl delete pod test-arm逻辑说明arm64v8/nginx是 Docker 官方 ARM64 镜像能跑起来说明 containerd 拉镜像、CNI 分配 IP、kubelet 调度都正常。kubectl exec能进去说明网络和运行时都没问题。跑完删掉别留垃圾。最后说个我自己的习惯每次部署完把kubeadm-init.yaml、containerd 配置、镜像清单、join 命令全部存到一个deploy-notes目录里下次重装直接照着跑不用再回忆参数。ARM 环境变数多留好后悔药比什么都强。希望帮到你。本文还有配套的精品资源点击获取