简介:这份资源合集面向需要在国产化平台上落地云原生环境的运维与架构人员,聚焦Kylin V10操作系统与ARM架构CPU组合下,使用containerd作为容器运行时部署Kubernetes 1.26.15多主多从高可用集群的完整实践。包内共47个文件,以gz离线镜像包、rpm系统依赖、sh自动化脚本、conf与service配置文件以及yml/yaml集群清单为主,另含kubeadm、kubectl、kubelet等核心二进制与keepalived、kube-lb负载均衡组件,压缩包约622MB。资源覆盖etcd集群、控制平面组件、工作节点注册、Calico网络插件及镜像批量导入等关键环节,并附带多主加入与节点加入的kubeadm配置模板,便于读者在ARM服务器上快速复现高可用集群、理解各组件协作关系与排错思路。目前已有254人学习下载,适合具备一定Linux与容器基础、希望掌握非x86平台K8S部署的中高级技术人员参考。
1. 麒麟 V10 + ARM 上跑 K8S 1.26.15:这套离线合集到底解决了谁的痛
手里有一批 ARM 服务器,系统是麒麟 V10,网络还出不了外网,这时候让你把 K8S 1.26.15 多主多从集群拉起来,你大概率会卡在三个地方:ARM 架构的镜像去哪找、containerd 怎么配、kubeadm 初始化时那个the api server is not healthy after 4m0.00747357s到底在报什么。这套资源合集就是冲着这三个问题来的——它不是一份从零讲 K8S 原理的教程,而是一个已经按 ARM64 架构把镜像、二进制、配置模板、负载均衡脚本全部打包好的离线部署包。
里面有什么?k8s-v1.26.15.tar.gz是核心镜像包,包含 kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy、etcd、coredns、pause、calico 全套组件的 ARM64 镜像;cri-containerd-cni-1.7.2-linux-arm64.tar.gz是 containerd 运行时和 CNI 插件的离线包;kubeadm-kubectl-kubelet目录下是三个核心二进制;kube-lb配合keepalived解决多主节点 API Server 的高可用入口问题;kubeadm-first-master.yml、kubeadm-join-master.yml、kubeadm-join-node.yml三个配置文件把初始化、加主、加从三条路径拆开了。
适合谁?手上已经有麒麟 V10 ARM 环境、需要在内网离线部署 K8S 的运维和平台工程师。如果你还在用 x86 那套习惯去套 ARM,镜像架构不对、libseccomp 版本不匹配、IPVS 模块没加载这几个坑基本躲不掉。下面按实际部署顺序拆一遍,重点讲清楚每个文件干什么用、参数怎么改、哪里容易翻车。
2. 先把 containerd 和运行时底座铺好:ARM64 离线包的安装与 systemd 接管
K8S 1.26 已经彻底移除了对 Docker Shim 的支持,containerd 是默认也是推荐的容器运行时。在 ARM 架构上装 containerd 和 x86 最大的区别在于:你没法直接apt install拿到匹配的包,必须用cri-containerd-cni-1.7.2-linux-arm64.tar.gz这种预编译好的离线包。这个包里不只是 containerd 本体,还带了 runc、CNI 插件(bridge、host-local、loopback 等)和 cri 工具,解压到根目录就能用。
2.1 解压离线包并生成默认配置
先确认系统架构和内核版本,麒麟 V10 在 ARM 上一般是aarch64,内核 4.19 或 5.10 都有:
uname -m # 输出应为 aarch64 uname -r # 确认内核版本,4.19+ 即可然后解压 containerd 离线包。注意这个 tar 包的目录结构是相对于根目录的,所以要用-C /:
tar -xzf cri-containerd-cni-1.7.2-linux-arm64.tar.gz -C / # 解压后: # /usr/local/bin/ 下会有 containerd、containerd-shim-runc-v2、ctr、runc # /opt/cni/bin/ 下会有 CNI 插件 # /etc/cni/net.d/ 下会有默认网络配置验证二进制是否可用:
containerd --version # 应输出 containerd github.com/containerd/containerd v1.7.2 runc --version # 确认 runc 版本生成 containerd 默认配置文件,然后改成 K8S 需要的配置:
mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml这里有个关键改动:默认配置里SystemdCgroup是false,K8S 1.26 配合 systemd 的 cgroup 驱动必须改成true,否则 kubelet 启动后会报failed to create pod sandbox之类的错误。同时把 pause 镜像地址改成离线包里的版本:
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参数说明:SystemdCgroup = true让 containerd 用 systemd 管理 cgroup,和 kubelet 的--cgroup-driver=systemd保持一致;sandbox_image指向 pause 3.9,这个镜像在k8s-v1.26.15.tar.gz里已经包含了,后面用ctr导入即可。
2.2 配置 systemd 服务并处理 libseccomp 依赖
containerd 离线包里没有自带 systemd unit 文件,需要手动创建/etc/systemd/system/containerd.service:
[Unit] Description=containerd container runtime Documentation=https://containerd.io After=network.target local-fs.target [Service] ExecStartPre=-/sbin/modprobe overlay ExecStart=/usr/local/bin/containerd Type=notify Delegate=yes KillMode=process Restart=always RestartSec=5 LimitNPROC=infinity LimitCORE=infinity LimitNOFILE=infinity TasksMax=infinity OOMScoreAdjust=-999 [Install] WantedBy=multi-user.target这里有个 ARM 上特有的坑:麒麟 V10 自带的 libseccomp 版本可能偏低,containerd 启动时会报libseccomp.so.2: version 'LIBSECCOMP_2.5' not found。资源包里带了libseccomp.so.2,直接覆盖到/usr/lib64/下即可:
cp libseccomp.so.2 /usr/lib64/ ldconfig然后启动并设置开机自启:
systemctl daemon-reload systemctl enable containerd --now systemctl status containerd # 确认 active (running)验证 containerd 的 ctr 命令能正常拉取和列出镜像:
ctr images ls # 初始为空是正常的 ctr -n k8s.io images ls # K8S 命名空间下的镜像列表提示:containerd 的默认命名空间是
default,K8S 用的是k8s.io,用ctr导入镜像时一定要加-n k8s.io,否则 kubelet 看不到。
3. 导入 ARM64 镜像与 kubeadm 初始化:多主多从的第一台 master 怎么拉起来
镜像导入和 kubeadm 初始化是整个部署里最容易翻车的环节。ARM64 镜像不像 x86 那样随手docker pull就有,必须用离线包里的 tar 文件逐个导入。资源包里images目录下已经按组件拆好了: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、etcd-3.5.10-0.tar.gz、coredns-v1.9.3.tar.gz、pause-3.9.tar.gz、calico-cni-v3.26.4.tar.gz、calico-node-v3.26.4.tar.gz、calico-kube-controllers-v3.26.4.tar.gz。
3.1 批量导入镜像的脚本逻辑
资源包里有个load_images.sh,核心逻辑就是遍历目录下的 tar.gz 文件,逐个导入到k8s.io命名空间:
#!/bin/bash # load_images.sh - 批量导入 K8S 组件镜像到 containerd IMAGES_DIR="./images" for image in ${IMAGES_DIR}/*.tar.gz; do echo "Loading ${image} ..." ctr -n k8s.io images import ${image} if [ $? -eq 0 ]; then echo "OK: ${image}" else echo "FAIL: ${image}" fi done ctr -n k8s.io images ls | grep -E "kube|etcd|coredns|calico|pause"逻辑说明:ctr -n k8s.io images import是 containerd 导入镜像的标准命令,-n k8s.io指定命名空间。导入完成后用ctr images ls过滤确认关键组件都在。如果某个镜像导入失败,常见原因是 tar 包在传输过程中损坏,重新从原始包解压一次即可。
参数说明:images目录下所有 tar.gz 文件都是docker save或ctr images export导出的 OCI 格式,containerd 1.7.2 可以直接识别。导入后镜像的 tag 会保留原始仓库地址,比如registry.k8s.io/kube-apiserver:v1.26.15。
3.2 kubeadm-first-master.yml 的关键参数
第一台 master 的初始化配置文件kubeadm-first-master.yml是整个集群的起点。这个文件里需要重点关注几个字段:
apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.1.10 # 改成当前 master 节点 IP bindPort: 6443 nodeRegistration: criSocket: unix:///run/containerd/containerd.sock imagePullPolicy: Never # 离线环境必须设为 Never taints: [] --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.26.15 imageRepository: registry.k8s.io controlPlaneEndpoint: 192.168.1.100:6443 # 指向 kube-lb 的 VIP networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 dnsDomain: cluster.local etcd: local: dataDir: /var/lib/etcd --- apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration cgroupDriver: systemd --- apiVersion: kubeproxy.config.k8s.io/v1alpha1 kind: KubeProxyConfiguration mode: ipvs参数说明:imagePullPolicy: Never是离线部署的关键,告诉 kubelet 只用本地镜像,不要尝试去拉取;controlPlaneEndpoint指向kube-lb的 VIP 地址,多主节点场景下所有 master 的 kube-apiserver 都注册到这个 VIP 后面;cgroupDriver: systemd必须和 containerd 的SystemdCgroup = true对应;mode: ipvs启用 IPVS 代理模式,性能比 iptables 好,但需要提前加载内核模块。
3.3 初始化前的系统准备与 IPVS 模块加载
在跑kubeadm init之前,有几项系统配置必须做,资源包里的op.sh脚本已经把这些操作串好了:
#!/bin/bash # op.sh - K8S 节点初始化脚本 # 关闭 swap swapoff -a sed -i '/swap/s/^/#/' /etc/fstab # 加载内核模块 modprobe br_netfilter modprobe ip_vs modprobe ip_vs_rr modprobe ip_vs_wrr modprobe ip_vs_sh modprobe nf_conntrack # 设置内核参数 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 # 安装 IPVS 管理工具(资源包 pkgs 目录下已包含) rpm -ivh pkgs/ipvsadm*.rpm pkgs/sysstat*.rpm pkgs/conntrack*.rpm \ pkgs/ebtables*.rpm pkgs/socat*.rpm pkgs/ipset*.rpm逻辑说明:br_netfilter和ip_vs系列模块是 IPVS 模式的前提,麒麟 V10 默认可能没有加载;net.bridge.bridge-nf-call-iptables = 1让桥接流量经过 iptables 规则链,这是 K8S Service 转发的基础;ipvsadm等工具用于后续排查 IPVS 规则。
然后安装 kubeadm、kubelet、kubectl 三个二进制:
cp kubeadm-kubectl-kubelet/kubeadm /usr/local/bin/ cp kubeadm-kubectl-kubelet/kubelet /usr/local/bin/ cp kubeadm-kubectl-kubelet/kubectl /usr/local/bin/ chmod +x /usr/local/bin/kubeadm /usr/local/bin/kubelet /usr/local/bin/kubectlkubelet 需要 systemd 管理,资源包里带了kubelet.service和10-kubeadm.conf:
cp kubelet.service /etc/systemd/system/ mkdir -p /etc/systemd/system/kubelet.service.d/ cp 10-kubeadm.conf /etc/systemd/system/kubelet.service.d/ systemctl daemon-reload systemctl enable kubelet注意 kubelet 此时先不要 start,等kubeadm init跑完会自动拉起。如果提前启动会反复重启报错,这是正常现象。
3.4 执行初始化并验证第一台 master
所有前置条件就绪后,执行初始化:
kubeadm init --config=kubeadm-first-master.yml --upload-certs--upload-certs会把证书加密后上传到 etcd,后续加 master 节点时用--control-plane和--certificate-key就能自动拉取证书,不用手动拷贝。
初始化成功后,按提示配置 kubectl:
mkdir -p $HOME/.kube cp /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config kubectl get nodes # 应看到当前 master 节点,状态 NotReady(因为还没装 CNI)如果卡在the api server is not healthy after 4m0.00747357s,按这个顺序排查:先crictl ps -a看 kube-apiserver 容器是否在运行;再crictl logs <container_id>看具体报错;常见原因是 etcd 数据目录权限不对、证书过期、或者 containerd 的SystemdCgroup没改。资源包里test目录下有nginx和busybox两个测试镜像,集群起来后可以用来验证 Pod 调度。
4. 多主多从的负载均衡与节点加入:kube-lb + keepalived 怎么配才不翻车
单 master 跑通只是第一步,多主多从的核心在于 API Server 的高可用入口。资源包里kube-lb是一个轻量级的 TCP 负载均衡器,配合keepalived实现 VIP 漂移。kube-lb.conf是它的配置文件,kube-lb.service是 systemd 单元。
4.1 kube-lb 的配置与启动
kube-lb.conf的典型内容如下:
# kube-lb.conf - API Server 负载均衡配置 listen: 0.0.0.0:6443 backend: - 192.168.1.10:6443 # master-1 - 192.168.1.11:6443 # master-2 - 192.168.1.12:6443 # master-3 mode: tcp log_level: info参数说明:listen监听所有网卡的 6443 端口;backend列出所有 master 节点的 kube-apiserver 地址;mode: tcp是四层转发,不做 TLS 终止,证书校验由客户端和 apiserver 直接完成。
启动 kube-lb:
cp kube-lb /usr/local/bin/ cp kube-lb.conf /etc/kube-lb/ cp kube-lb.service /etc/systemd/system/ systemctl daemon-reload systemctl enable kube-lb --now systemctl status kube-lb4.2 keepalived 实现 VIP 漂移
keepalived的配置在资源包keepalived目录下,主备模式:
# /etc/keepalived/keepalived.conf (master 节点) vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass k8s123 } virtual_ipaddress { 192.168.1.100/24 } }备节点把state改成BACKUP,priority改成 90。virtual_ipaddress就是kubeadm-first-master.yml里controlPlaneEndpoint指向的 VIP。
启动 keepalived:
cp keepalived /usr/sbin/ cp keepalived.service /etc/systemd/system/ systemctl daemon-reload systemctl enable keepalived --now ip addr show eth0 | grep 192.168.1.100 # 确认 VIP 已绑定4.3 加入第二台 master 和 worker 节点
第二台 master 加入集群,用kubeadm-join-master.yml:
kubeadm join 192.168.1.100:6443 \ --config=kubeadm-join-master.yml \ --control-plane \ --certificate-key <从 init 输出中获取的 key>kubeadm-join-master.yml里需要改localAPIEndpoint.advertiseAddress为当前节点 IP,controlPlaneEndpoint保持 VIP 不变。
worker 节点加入用kubeadm-join-node.yml:
kubeadm join 192.168.1.100:6443 \ --config=kubeadm-join-node.ymlkubeadm-join-node.yml里同样要改nodeRegistration.criSocket和imagePullPolicy: Never。
加入完成后在 master 上验证:
kubectl get nodes -o wide # 所有节点应为 Ready kubectl get pods -n kube-system # 确认 calico、coredns、kube-proxy 全部 Running4.4 Calico 网络插件的 ARM64 部署
资源包里calico.yaml是 Calico v3.26.4 的部署清单,已经适配 ARM64。直接 apply:
kubectl apply -f calico.yaml等 2-3 分钟,检查 Calico Pod 状态:
kubectl get pods -n kube-system -l k8s-app=calico-node kubectl get pods -n kube-system -l k8s-app=calico-kube-controllers如果 calico-node 一直 CrashLoopBackOff,常见原因是CALICO_IPV4POOL_CIDR和 kubeadm 的podSubnet不一致。检查calico.yaml里的CALICO_IPV4POOL_CIDR是否为10.244.0.0/16,和kubeadm-first-master.yml里的podSubnet保持一致。
5. 避坑与排查:ARM + 麒麟 V10 上最容易翻车的五个点
5.1 kube-apiserver 容器起不来,报 the api server is not healthy
现象:kubeadm init卡在the api server is not healthy after 4m0.00747357s,crictl ps -a看到 kube-apiserver 容器反复重启。
原因:麒麟 V10 默认的 libseccomp 版本低于 containerd 1.7.2 的要求,或者 etcd 数据目录/var/lib/etcd权限不对。
解决:先crictl logs <container_id>看具体报错。如果是 libseccomp 相关,用资源包里的libseccomp.so.2覆盖/usr/lib64/后ldconfig;如果是 etcd 权限问题,chmod 700 /var/lib/etcd并确认目录属主是 root。
5.2 calico-node 一直 CrashLoopBackOff
现象:Calico Pod 启动后不断重启,日志报BIRD is not ready或failed to set up IPVS。
原因:内核模块ip_vs系列没加载,或者CALICO_IPV4POOL_CIDR和 kubeadm 的podSubnet不一致。
解决:modprobe ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh并写入/etc/modules-load.d/;检查calico.yaml里的 CIDR 配置,确保和kubeadm-first-master.yml的podSubnet一致。
5.3 ctr 导入镜像后 kubelet 看不到
现象:ctr images ls能看到镜像,但kubectl describe pod报ErrImageNeverPull。
原因:导入时没加-n k8s.io,镜像进了default命名空间。
解决:重新用ctr -n k8s.io images import导入,或者用ctr -n k8s.io images ls确认镜像在正确的命名空间。
5.4 kubelet 启动报 failed to run Kubelet: misconfiguration: kubelet cgroup driver: "cgroupfs" is different from docker cgroup driver: "systemd"
现象:kubelet 服务反复重启,日志报 cgroup driver 不匹配。
原因:containerd 的SystemdCgroup没改成true,或者 kubelet 的cgroupDriver没设为systemd。
解决:确认/etc/containerd/config.toml里SystemdCgroup = true,kubeadm-first-master.yml里cgroupDriver: systemd,然后systemctl restart containerd kubelet。
5.5 多主节点加入时证书 key 过期
现象:kubeadm join --control-plane --certificate-key报certificate key expired。
原因:--upload-certs上传的证书默认 2 小时过期。
解决:在 master 上重新生成 key:kubeadm init phase upload-certs --upload-certs,然后用新 key 加入。
6. 集群跑起来之后:用 test 镜像验证调度与一个 IPVS 排查技巧
集群所有节点 Ready、Calico 和 CoreDNS 都 Running 之后,别急着上业务。资源包里test目录下的nginx和busybox两个镜像就是用来做冒烟测试的。先导入:
ctr -n k8s.io images import test/nginx.tar.gz ctr -n k8s.io images import test/busybox.tar.gz然后跑一个 Deployment 和 Service:
kubectl create deployment nginx-test --image=nginx --replicas=3 kubectl expose deployment nginx-test --port=80 --type=ClusterIP kubectl get pods -o wide # 确认 3 个 Pod 分布在不同 worker 节点上用 busybox 验证 Service 的 ClusterIP 能不能通:
kubectl run busybox-test --image=busybox --restart=Never -- sleep 3600 kubectl exec -it busybox-test -- wget -qO- http://nginx-test # 应返回 nginx 欢迎页 HTML如果 wget 超时,大概率是 IPVS 规则没生效。在任意节点上执行:
ipvsadm -Ln # 查看 IPVS 虚拟服务列表,应能看到 nginx-test 的 ClusterIP 和对应 RealServer如果ipvsadm -Ln输出为空,说明 kube-proxy 没走 IPVS 模式。检查 kube-proxy 的 ConfigMap:
kubectl -n kube-system get configmap kube-proxy -o yaml | grep mode # 应输出 mode: ipvs如果显示mode: "",说明kubeadm-first-master.yml里的KubeProxyConfiguration没生效。手动改 ConfigMap 后重启 kube-proxy:
kubectl -n kube-system edit configmap kube-proxy # 把 mode: "" 改成 mode: ipvs kubectl -n kube-system rollout restart daemonset kube-proxy还有一个 ARM 上特有的验证点:conntrack表项数量。IPVS 模式下每个 Service 连接都会在 conntrack 表里留记录,ARM 服务器的内存带宽和 x86 不同,nf_conntrack_max默认值可能偏小。资源包里sysstat和conntrack工具就是用来监控这个的:
conntrack -C # 查看当前 conntrack 表项数量 sysctl net.netfilter.nf_conntrack_max # 查看最大值,ARM 服务器建议调到 131072 以上从那以后我每次在 ARM 上部署完 K8S,都会强制走一遍ipvsadm -Ln+conntrack -C+kubectl get pods -A -o wide这三条命令,确认 IPVS 规则、连接跟踪表和 Pod 分布都正常,再交给业务方。这套资源合集把离线镜像、二进制、配置模板和负载均衡脚本都按 ARM64 对齐了,省掉了逐个找包和改架构的时间,但系统层面的内核模块和 cgroup 配置还是得自己确认一遍。希望帮到你。
本文还有配套的精品资源,点击获取