简介本资源面向需要在国产化信创环境中落地容器编排的运维与云原生工程师提供基于银河麒麟Kylin V10、ARM架构并采用外部etcd与containerd运行时部署Kubernetes 1.26.15一主多从集群的完整离线材料可解决ARM平台镜像与依赖包获取困难、离线安装步骤繁琐的问题。压缩包共41个文件约645.74MB包含16个gz离线镜像与组件包、11个rpm系统依赖、4个sh镜像加载与拉取脚本以及kubeadm、kubelet、kubectl等二进制文件和yaml、conf、service配置模板覆盖etcd、containerd、Calico网络与CoreDNS等核心组件。已有131人学习下载。读者可据此在无外网环境下完成集群初始化、节点加入与网络插件部署脚本与配置可直接复用便于快速搭建测试环境并排查ARM架构下的兼容性问题。1. 麒麟 V10 ARM 上跑 K8S 1.26.15这套离线包到底值不值得下如果你手里正好有一台飞腾、鲲鹏或者麒麟的 ARM 服务器系统是 Kylin V10Halberd 或 SP1网络又基本出不去那你大概率已经体会过那种绝望kubeadm init卡在拉镜像crictl pull转圈转到天荒地老最后给你甩一句the api server is not healthy after 4m0.00747357s。这套资源合集就是冲着这个场景来的——它把 K8S 1.26.15 在 ARM64 上跑起来所需的一整套离线物料打包好了kubeadm/kubelet/kubectl 二进制、containerd 1.7.2 的 cri-containerd-cni 包、etcd 3.5.10 的 ARM64 二进制、Calico 3.26.4 的镜像 tar 包、CoreDNS 1.9.3、pause 3.9还有 libseccomp 2.5.4 这种在麒麟上经常缺的底层依赖。适合谁适合要在内网、信创环境里搭一主多从集群的运维和交付工程师也适合想搞明白 ARM 上 K8S 离线部署到底和 x86 差在哪的开发者。它不解决“你会不会 K8S”它解决的是“物料齐不齐、版本对不对、依赖缺不缺”。2. 拆包看物料ARM64 离线部署的依赖链与选型逻辑拿到一个 tar.gz 别急着解压就干先搞清楚里面每一层是干嘛的。ARM 上的 K8S 离线部署本质是一条依赖链内核模块和系统工具 → 容器运行时 → K8S 组件二进制 → 集群网络插件镜像。任何一环版本对不上后面就是玄学报错。2.1 为什么是 containerd 1.7.2 而不是 DockerK8S 1.26 已经正式移除了对 Docker shim 的支持dockershim 在 1.24 就被砍了。所以这套资源直接用 cri-containerd-cni-1.7.2-linux-arm64.tar.gz这是正确路线。containerd 1.7.x 对 CRI 的支持已经稳定而且自带 CNI 插件省得你单独去凑 CNI 的二进制。选 1.7.2 这个版本还有个现实原因它和 K8S 1.26.15 的 CRI 接口兼容性经过大量生产验证再新的 containerd 2.x 在麒麟 V10 这种偏保守的内核上反而容易出幺蛾子。我一般会先确认containerd --version和runc --versionrunc 版本太低会导致容器起不来报OCI runtime create failed。2.2 etcd 3.5.10 独立部署的意义资源里给了 etcd-v3.5.10-linux-arm64.tar.gz 和 etcd-3.5.10-0.tar.gz 两个包还有 etcd_ssl.tar.gz。这说明作者是打算把 etcd 外置的不是用 kubeadm 默认的堆叠式 etcd。外置 etcd 的好处很直接etcd 是 K8S 的“黑匣子”所有集群状态都在里面。堆叠式 etcd 和 master 节点绑死master 挂了 etcd 也悬。外置之后你可以单独备份、单独扩容、单独调优。ARM 机器磁盘 IO 往往不如 x86 服务器etcd 对磁盘延迟极其敏感外置到独立盘或者独立节点是明智的。etcd_ssl.tar.gz 里应该是证书外置 etcd 必须配 TLS否则 kube-apiserver 连不上。2.3 Calico 3.26.4 与镜像清单calico.yaml 配合 calico-cni-v3.26.4.tar.gz、calico-node-v3.26.4.tar.gz、calico-kube-controllers-v3.26.4.tar.gz 三个镜像包。Calico 3.26 支持 ARM64而且它的 BGP 模式在信创环境里比 IPIP 更常用因为很多内网交换机对 IPIP 隧道不友好。镜像清单里还有 coredns-v1.9.3.tar.gz、pause-3.9.tar.gz、kube-apiserver/controller-manager/scheduler/kube-proxy 的 v1.26.15 tar 包。这些就是kubeadm init时会去拉的东西离线环境下必须提前 load 进去。2.4 系统依赖libseccomp 和那些容易被忽略的包libseccomp-2.5.4.tar.gz 和 libseccomp.so.2 是重点。麒麟 V10 默认的 libseccomp 版本可能偏低containerd 1.7.2 依赖较新的 seccomp 支持缺了会报failed to create seccomp profile或者容器直接起不来。pkgs 目录下的 sysstat、ipvsadm、conntrack、ebtables、socat、ipset 是 kube-proxy 走 IPVS 模式必需的。如果你不装这些kube-proxy 会退化成 iptables 模式在大规模 Service 场景下性能差很多。10-kubeadm.conf、kubelet.service、kubelet 这几个文件是配置 kubelet 开机自启和 cgroup 驱动的。提示解压后先别动用tar -tzf列一遍文件对照上面的清单确认没有缺包再开始装。3. 从零到集群 Ready一主多从的实操步骤这一章是能直接抄作业的部分。假设你已经有一台 master比如 192.168.1.10和至少一台 node192.168.1.11系统都是 Kylin V10 ARM64root 权限。3.1 系统层准备关 swap、加载内核模块、装依赖先做所有节点都要做的系统配置。# 关闭 swapK8S 强制要求 swapoff -a sed -i /swap/s/^/#/ /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逻辑说明overlay是 containerd 的存储驱动br_netfilter让 iptables 能过滤桥接流量这是 Calico 和 kube-proxy 正常工作的前提。ip_forward1不打开Pod 跨节点通信直接废掉。参数说明/etc/modules-load.d/k8s.conf是开机自动加载sysctl --system让配置立即生效。麒麟 V10 的 firewalld 建议先systemctl stop firewalld systemctl disable firewalld否则后面端口各种不通。然后装系统依赖包# 进入 pkgs 目录 cd pkgs rpm -ivh *.rpm 2/dev/null || yum localinstall -y *.rpm # 安装 libseccomp tar -xzf libseccomp-2.5.4.tar.gz cd libseccomp-2.5.4 ./configure --prefix/usr make make install ldconfig逻辑说明pkgs 里的 rpm 直接装如果依赖报错就用yum localinstall自动解决。libseccomp 从源码编译装完必须ldconfig刷新动态库缓存否则 containerd 找不到libseccomp.so.2。3.2 部署 containerd 1.7.2# 解压 cri-containerd-cni 包到根目录 tar -xzf cri-containerd-cni-1.7.2-linux-arm64.tar.gz -C / # 生成默认配置 containerd config default /etc/containerd/config.toml # 修改 cgroup 驱动为 systemd sed -i s/SystemdCgroup false/SystemdCgroup true/ /etc/containerd/config.toml # 修改 sandbox 镜像为国内可用的 pause 地址离线环境用本地 sed -i s#sandbox_image .*#sandbox_image registry.aliyuncs.com/google_containers/pause:3.9# /etc/containerd/config.toml systemctl daemon-reload systemctl enable containerd systemctl restart containerd systemctl status containerd逻辑说明SystemdCgroup true必须改否则 kubelet 和 containerd 的 cgroup 驱动不一致Pod 会反复重启。sandbox_image指向 pause 3.9离线环境里这个镜像已经通过 load_images.sh 加载到本地了但配置里写 registry 地址时 containerd 会先查本地。参数说明config default生成的是 containerd 官方默认配置1.7.2 的默认 cgroup 驱动是 false这是 ARM 上最常见的坑之一。3.3 安装 kubeadm、kubelet、kubectl# 拷贝二进制 cp kubeadm kubectl kubelet /usr/local/bin/ chmod x /usr/local/bin/kubeadm /usr/local/bin/kubectl /usr/local/bin/kubelet # 配置 kubelet 服务 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 kubelet逻辑说明kubelet 不通过 systemd 启动管理而是由 kubeadm 在 init 时拉起所以这里只 enable 不 start。10-kubeadm.conf里定义了 kubelet 的启动参数比如--container-runtime-endpointunix:///run/containerd/containerd.sock。参数说明如果你的 containerd socket 路径不是默认的要改10-kubeadm.conf里的KUBELET_EXTRA_ARGS。3.4 加载所有离线镜像# load_images.sh 内容大致如下 for img in *.tar.gz; do echo Loading $img ... ctr -n k8s.io images import $img done # 或者用 crictl # ctr 是 containerd 自带的不需要额外装 ctr -n k8s.io images ls | grep -E kube-apiserver|calico|coredns|pause逻辑说明ctr -n k8s.io指定 namespace 为 k8s.io这是 kubelet 使用的 namespace。如果你用ctr images import不加-n k8s.io镜像会进 default namespacekubelet 看不到然后kubeadm init还是会去拉镜像然后失败。参数说明load_images.sh里如果用的是ctr -n k8s.io images import直接跑就行。导入完成后用ctr -n k8s.io images ls确认关键镜像都在。3.5 初始化 master 节点先准备 kubeadm-config.yamlapiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.10 bindPort: 6443 nodeRegistration: criSocket: unix:///run/containerd/containerd.sock kubeletExtraArgs: cgroup-driver: systemd --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.26.15 imageRepository: registry.aliyuncs.com/google_containers networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 etcd: external: endpoints: - https://192.168.1.20:2379 caFile: /etc/etcd/ssl/ca.pem certFile: /etc/etcd/ssl/etcd.pem keyFile: /etc/etcd/ssl/etcd-key.pem逻辑说明advertiseAddress改成你 master 的实际 IP。podSubnet要和 calico.yaml 里的 CALICO_IPV4POOL_CIDR 一致默认是 10.244.0.0/16。etcd.external指向你外置 etcd 的地址和证书路径证书从 etcd_ssl.tar.gz 解出来放到对应目录。参数说明imageRepository写阿里云地址是为了让 kubeadm 生成静态 Pod 的 yaml 时引用这个地址但实际镜像已经在本地了kubelet 会优先用本地。如果你完全离线这个地址不会被访问。然后执行kubeadm init --config kubeadm-config.yaml --upload-certs如果卡在the api server is not healthy after 4m0.00747357s别慌这是 ARM 离线部署最高频的报错。先看crictl ps -a看 kube-apiserver 容器状态再看crictl logs container_id大概率是镜像没导入到 k8s.io namespace或者 etcd 证书路径不对。3.6 加入 worker 节点master init 成功后会输出 join 命令类似kubeadm join 192.168.1.10:6443 --token abcdef.1234567890abcdef \ --discovery-token-ca-cert-hash sha256:xxxx资源里的 kubeadm-join-node.yml 就是给 node 节点用的 join 配置文件内容大致是apiVersion: kubeadm.k8s.io/v1beta3 kind: JoinConfiguration discovery: bootstrapToken: apiServerEndpoint: 192.168.1.10:6443 token: abcdef.1234567890abcdef caCertHashes: - sha256:xxxx nodeRegistration: criSocket: unix:///run/containerd/containerd.sock kubeletExtraArgs: cgroup-driver: systemd在 node 节点上执行kubeadm join --config kubeadm-join-node.yml即可。加入后在 master 上kubectl get nodes确认状态为 Ready。3.7 部署 Calico 网络# 先加载 calico 镜像 ctr -n k8s.io images import calico-cni-v3.26.4.tar.gz ctr -n k8s.io images import calico-node-v3.26.4.tar.gz ctr -n k8s.io images import calico-kube-controllers-v3.26.4.tar.gz # 修改 calico.yaml 里的 CIDR sed -i s#value: 192.168.0.0/16#value: 10.244.0.0/16# calico.yaml kubectl apply -f calico.yaml kubectl get pods -n kube-system -w逻辑说明Calico 的 CALICO_IPV4POOL_CIDR 必须和 kubeadm 的 podSubnet 一致否则 Pod 拿不到 IP。ARM 上 Calico 的 felix 和 typha 组件对内核版本有要求麒麟 V10 的内核一般没问题但如果报iptables: No chain/target/match by that name检查 br_netfilter 是否加载。参数说明kubectl get pods -n kube-system -w持续观察直到 calico-node 全部 Runningcoredns 也 Running集群才算真正可用。4. 避坑排查ARM 离线部署最常见的五个翻车点这一章全是血泪经验每条都按“现象 → 原因 → 解决”写遇到问题直接对号入座。4.1 现象kubeadm init 卡 4 分钟报 api server not healthy原因kube-apiserver 容器根本没起来。最常见的是镜像没导入到k8s.ionamespace或者 etcd 连不上。ARM 上还可能是 kube-apiserver 二进制和系统 glibc 不兼容。解决先crictl ps -a | grep apiserver看容器状态。如果是 Exitedcrictl logs id看日志。如果是镜像问题重新ctr -n k8s.io images import kube-apiserver-v1.26.15.tar.gz。如果是 etcd 问题在 master 上用openssl s_client -connect 192.168.1.20:2379 -CAfile /etc/etcd/ssl/ca.pem测试连通性。4.2 现象node 节点 join 后状态一直是 NotReady原因node 上的 containerd 没配好或者 cgroup 驱动不一致或者 Calico 没在该节点拉起。解决在 node 上systemctl status containerd和journalctl -u kubelet -f看日志。重点检查/etc/containerd/config.toml里SystemdCgroup是否为 true以及10-kubeadm.conf里 cgroup-driver 是否为 systemd。两边必须一致。4.3 现象Pod 一直 ContainerCreatingdescribe 显示 failed to create seccomp profile原因libseccomp 版本太低containerd 无法为容器生成 seccomp 配置。解决确认ldconfig -p | grep seccomp能看到libseccomp.so.2。如果没有重新编译安装 libseccomp-2.5.4然后systemctl restart containerd。麒麟 V10 上还要确认/usr/lib64和/usr/lib下都有软链接。4.4 现象Calico 节点报 iptables 错误Pod 跨节点不通原因br_netfilter模块没加载或者net.bridge.bridge-nf-call-iptables没设为 1。解决lsmod | grep br_netfilter确认模块加载sysctl net.bridge.bridge-nf-call-iptables确认值为 1。如果没有重新执行 3.1 节的内核配置并重启节点。ARM 上有些内核编译时没带 br_netfilter那就只能换内核或者用 Calico 的 eBPF 模式但 3.26 的 eBPF 在 ARM 上还不算特别稳。4.5 现象coredns Pod 一直 CrashLoopBackOff原因coredns 镜像没加载或者 serviceSubnet 和 podSubnet 冲突或者节点上 resolv.conf 有问题。解决ctr -n k8s.io images ls | grep coredns确认镜像在。检查 kubeadm-config.yaml 里 serviceSubnet 和 podSubnet 没有重叠。麒麟 V10 的/etc/resolv.conf如果指向了不可用的 DNScoredns 会启动失败临时改成nameserver 114.114.114.114再试。注意每次改完 containerd 配置或内核参数都要systemctl daemon-reload再重启对应服务否则改动不生效你会以为改了但实际没改然后怀疑人生。5. 验证与进阶把集群跑稳的几个硬核习惯集群 Ready 只是开始真正交付前我一般会走一遍下面的验证流程这套习惯是从多次翻车之后强制自己养成的。5.1 用 test 目录做冒烟测试资源里有个 test 目录里面是 nginx 和 busybox 的 yaml。别小看这两个它们是验证集群网络和 DNS 的最快方式。kubectl create deployment nginx --imagenginx --replicas2 kubectl expose deployment nginx --port80 --typeNodePort kubectl run busybox --imagebusybox --rm -it --restartNever -- sh # 在 busybox 里执行 wget -qO- nginx nslookup kubernetes.default逻辑说明wget -qO- nginx验证 Service 的 ClusterIP 和 kube-proxy 是否正常nslookup kubernetes.default验证 CoreDNS 是否正常。两个都通集群基本功能就没问题。参数说明--restartNever让 busybox 以 Pod 形式运行而不是 Deployment退出后自动清理。-it进入交互模式。5.2 检查 IPVS 模式是否生效如果你装了 ipvsadm可以确认 kube-proxy 是不是真的走了 IPVSipvsadm -Ln | grep -E 10.96|10.244如果输出为空说明 kube-proxy 还在 iptables 模式。检查 kube-proxy 的 ConfigMapkubectl -n kube-system edit configmap kube-proxy # 把 mode: 改成 mode: ipvs kubectl -n kube-system rollout restart daemonset kube-proxy逻辑说明IPVS 模式在 Service 数量超过 1000 时性能优势明显ARM 机器 CPU 核数通常不多IPVS 的哈希查找比 iptables 的线性匹配更省资源。参数说明改完 ConfigMap 必须重启 kube-proxy 的 DaemonSet否则旧 Pod 不会重新加载配置。5.3 外置 etcd 的备份习惯外置 etcd 最大的好处就是能独立备份。我一般会写个定时任务ETCDCTL_API3 etcdctl \ --endpointshttps://192.168.1.20:2379 \ --cacert/etc/etcd/ssl/ca.pem \ --cert/etc/etcd/ssl/etcd.pem \ --key/etc/etcd/ssl/etcd-key.pem \ snapshot save /backup/etcd-$(date %Y%m%d%H%M).db逻辑说明ETCDCTL_API3必须加否则 etcdctl 会用 v2 API报错。快照文件建议保留最近 7 天etcd 数据目录和快照目录不要放同一块盘。参数说明--endpoints指向你的 etcd 地址证书路径和 kubeadm-config.yaml 里的一致。恢复的时候用etcdctl snapshot restore但恢复前一定要停掉 kube-apiserver否则数据会写冲突。5.4 一个容易忽略的细节kubelet 的 cgroup 驱动麒麟 V10 默认可能用 cgroup v1而 containerd 1.7.2 和 K8S 1.26 对 cgroup v2 的支持更好。检查stat -fc %T /sys/fs/cgroup/如果输出cgroup2fs就是 v2tmpfs就是 v1。v1 也能跑但要在 kubelet 和 containerd 两边都显式指定systemd驱动不能一个 systemd 一个 cgroupfs否则 Pod 资源限制会失效表现为kubectl describe pod里看不到 CPU/内存 limit。从那以后我每次部署完 ARM 集群都会强制走一遍kubectl run冒烟测试 ipvsadm -Ln确认 etcd 快照验证这三步少一步心里都不踏实。希望帮到你。本文还有配套的精品资源点击获取