简介:这份资源合集面向需要在国产化环境中落地云原生平台的运维与开发人员,聚焦Kylin V10操作系统搭配ARM架构CPU、以containerd为容器运行时部署Kubernetes 1.26.15一主一从集群的完整实践。包内共38个文件,以gz离线镜像包、rpm依赖包、sh脚本、yaml配置为主,另含service、conf及kubelet、kubectl、kubeadm等组件文件,压缩包约619.64MB,覆盖容器运行时、网络插件与集群核心组件的安装素材。内容涉及系统准备、containerd配置、K8S组件安装、主从节点配置、CNI网络插件选择、从节点加入、部署验证以及RBAC与持久化存储等环节,并附带镜像加载与拉取脚本、kubeadm配置模板,便于在离线或受限网络下完成部署。目前已有264人学习,适合希望掌握ARM64平台K8S集群搭建、排查兼容性与网络问题的中高级读者参考。
1. 麒麟 V10 + ARM 上跑 containerd 版 K8S 1.26.15:这套一主一从资源到底能省多少事
手里有一套基于 Kylin V10 操作系统、ARM 架构 CPU、用 containerd 作为容器运行时部署 K8S 1.26.15 一主一从集群的资源合集。如果你正在信创环境里折腾 k8s 集群搭建,大概率已经踩过这样的坑:网上教程全是 x86 + Docker 的,照着敲到kubeadm init直接报镜像拉不下来,或者 flannel 网卡起不来。这套资源针对的就是这个场景——国产 OS、ARM 芯片、containerd 运行时,三个条件叠在一起,能跑通的资料确实不多。它适合正在做信创适配的运维、需要在内网离线环境交付 K8S 的工程师,以及想搞清楚 containerd 和 Docker 在 kubeadm 流程里到底差在哪的从业者。下面按实际部署顺序拆一遍,把参数、命令和翻车点都摆出来。
2. 环境准备与组件选型:为什么是 containerd 而不是 Docker
2.1 Kylin V10 + ARM 的兼容性确认
Kylin V10 有多个版本分支,服务器版和桌面版的内核参数、软件源差异很大。部署前先确认三件事:内核版本、CPU 架构标识、软件源可用性。
# 确认系统版本和内核 cat /etc/kylin-release uname -r # 确认 CPU 架构,aarch64 即为 ARM64 uname -m # 确认软件源是否可用 yum repolistuname -m输出aarch64说明是 ARM64 架构,后续所有镜像和二进制包都必须选 arm64 版本。Kylin V10 默认内核一般在 4.19 以上,满足 K8S 1.26 的最低要求(内核 4.15+)。如果yum repolist报错,需要先挂载 ISO 或配置内网源,因为后面安装 containerd 依赖的libseccomp、conntrack等包都要从这里来。
常见做法是关闭 swap 和防火墙,但 Kylin V10 的防火墙管理用的是 firewalld,和 CentOS 一致:
# 关闭 swap,注释 fstab 中的 swap 行 swapoff -a sed -i '/swap/s/^/#/' /etc/fstab # 关闭 firewalld systemctl stop firewalld systemctl disable firewalld # 关闭 SELinux setenforce 0 sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config这几步看着简单,但 Kylin V10 的 SELinux 策略比社区版更严格,如果保持 enforcing,containerd 的 socket 创建会被拦截,kubelet 启动时报permission denied。改成 permissive 是最省事的做法,生产环境如果必须开 SELinux,需要额外写策略规则,那是另一个工作量。
2.2 containerd 与 Docker 的选型对比
K8S 1.24 之后移除了 dockershim,Docker 不再是官方推荐的运行时。containerd 作为 CNCF 毕业项目,调用链更短:kubelet 通过 CRI 插件直接调 containerd,省掉了 dockerd 这一层。在 ARM 环境下这个优势更明显,因为 Docker 的 arm64 包在部分国产 OS 上依赖冲突更多。
| 对比项 | containerd | Docker |
|---|---|---|
| CRI 支持 | 原生 | 需 dockershim(1.24 已移除) |
| 调用链 | kubelet → containerd | kubelet → dockerd → containerd |
| ARM64 包 | 官方静态二进制 | 依赖较多,国产 OS 易冲突 |
| 资源占用 | 较低 | 多一层 daemon |
| 命令工具 | ctr、crictl | docker |
选 containerd 还有一个实际原因:Kylin V10 的软件源里 containerd 版本可能偏旧,直接yum install containerd装出来的版本不一定满足 K8S 1.26 的要求。建议用官方静态二进制包手动安装,版本选 1.6.x 或 1.7.x 都行,1.26.15 搭配 containerd 1.7.x 比较稳。
# 下载 containerd arm64 静态包(内网环境需提前准备) wget https://github.com/containerd/containerd/releases/download/v1.7.13/containerd-1.7.13-linux-arm64.tar.gz tar Cxzvf /usr/local containerd-1.7.13-linux-arm64.tar.gz # 生成 systemd 服务文件 cat > /etc/systemd/system/containerd.service <<'EOF' [Unit] Description=containerd container runtime After=network.target [Service] ExecStartPre=/sbin/modprobe overlay ExecStart=/usr/local/bin/containerd Restart=always [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable --now containerdExecStartPre加载 overlay 模块是关键,ARM 内核默认可能没编译进去,不加载的话 containerd 启动后创建容器会报failed to mount overlay。装完后用containerd --version确认版本,再用systemctl status containerd看是否 active。
2.3 runc 与 CNI 插件的 ARM 版本
containerd 本身不含 runc,需要单独装。runc 的 arm64 版本同样从官方 release 下载:
wget https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.arm64 install -m 755 runc.arm64 /usr/local/sbin/runc runc --versionCNI 插件也不能忘,flannel 或 calico 都依赖它:
wget https://github.com/containernetworking/plugins/releases/download/v1.4.0/cni-plugins-linux-arm64-v1.4.0.tgz mkdir -p /opt/cni/bin tar Cxzvf /opt/cni/bin cni-plugins-linux-arm64-v1.4.0.tgz到这里运行时层就齐了。很多人卡在kubeadm init之后的ContainerCreating,十有八九是 CNI 插件没装或者路径不对。/opt/cni/bin是 kubelet 默认查找路径,别改。
3. kubeadm 部署一主一从:镜像、初始化与节点加入
3.1 kubelet/kubeadm/kubectl 的安装与版本锁定
K8S 1.26.15 的三个核心组件版本必须一致,否则 kubeadm 会拒绝初始化。ARM 环境下不能用apt或yum直接装,因为源里的版本往往对不上。用二进制下载最稳:
# 下载三个组件的 arm64 二进制 K8S_VER="v1.26.15" wget https://dl.k8s.io/${K8S_VER}/bin/linux/arm64/kubeadm wget https://dl.k8s.io/${K8S_VER}/bin/linux/arm64/kubelet wget https://dl.k8s.io/${K8S_VER}/bin/linux/arm64/kubectl chmod +x kubeadm kubelet kubectl mv kubeadm kubelet kubectl /usr/local/bin/装完后kubeadm version确认输出是 v1.26.15。kubelet 需要配 systemd 服务,但 kubeadm 初始化时会自动生成,这里不用手动写。注意 kubelet 的--cgroup-driver参数,Kylin V10 默认用 systemd,containerd 也要配成 systemd,两边不一致会导致 kubelet 起不来。
containerd 的配置文件需要生成并修改:
mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml # 修改 cgroup driver 和 sandbox 镜像 sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml sed -i 's#registry.k8s.io/pause:.*#registry.aliyuncs.com/google_containers/pause:3.9#' /etc/containerd/config.toml systemctl restart containerdSystemdCgroup = true这行不改,kubelet 启动时会报failed to run Kubelet: misconfiguration: kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs"。pause 镜像换成国内可访问的地址,否则kubeadm init卡在拉 sandbox 镜像。
3.2 kubeadm init 的关键参数与镜像预拉
一主一从的拓扑里,master 节点需要指定--control-plane-endpoint,哪怕只有一个 master 也建议写上 IP,方便后续扩展。完整初始化命令:
kubeadm init \ --apiserver-advertise-address=192.168.1.100 \ --control-plane-endpoint=192.168.1.100 \ --kubernetes-version=v1.26.15 \ --service-cidr=10.96.0.0/12 \ --pod-network-cidr=10.244.0.0/16 \ --cri-socket=unix:///var/run/containerd/containerd.sock \ --image-repository=registry.aliyuncs.com/google_containers \ --ignore-preflight-errors=Swap--cri-socket必须显式指定,因为系统里如果同时存在 Docker 和 containerd,kubeadm 会探测到多个 socket 然后报错。--image-repository指向国内源,ARM 镜像在registry.aliyuncs.com/google_containers上有对应的多架构 manifest,能自动拉 arm64 版本。--pod-network-cidr用 flannel 默认的 10.244.0.0/16,如果换 calico 要改成 192.168.0.0/16。
初始化前可以先预拉镜像,节省时间:
kubeadm config images pull \ --kubernetes-version=v1.26.15 \ --image-repository=registry.aliyuncs.com/google_containers \ --cri-socket=unix:///var/run/containerd/containerd.sock如果这一步报failed to pull image,先确认 containerd 的config.toml里 sandbox 镜像地址改对了,再确认网络能通阿里云。内网离线环境需要用kubeadm config images list列出所有镜像,在外网机器上拉下来后ctr images export导出,再传到内网ctr images import。
3.3 从节点加入与 flannel 网络配置
master 初始化成功后会输出 join 命令,类似:
kubeadm join 192.168.1.100:6443 --token abcdef.1234567890abcdef \ --discovery-token-ca-cert-hash sha256:xxxxx \ --cri-socket=unix:///var/run/containerd/containerd.socktoken 默认 24 小时过期,过期后用kubeadm token create --print-join-command重新生成。从节点执行前同样要装好 containerd、runc、CNI 插件和 kubelet,版本与 master 一致。
flannel 的部署在 master 上执行:
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.ymlARM 环境下 flannel 的镜像flannel/flannel和flannel/flannel-cni-plugin都有 arm64 版本,但国内拉取可能慢。可以先把 yaml 下载下来,把 image 地址换成国内镜像仓库再 apply。部署后kubectl get pods -n kube-flannel应该看到两个 Running 的 pod(一主一从各一个)。
验证集群状态:
kubectl get nodes kubectl get pods -A节点状态从NotReady变Ready通常需要一两分钟,如果超过五分钟还是 NotReady,用kubectl describe node <name>看 Conditions,常见原因是 CNI 没就绪或 kubelet 证书问题。
4. 避坑排查:ARM + Kylin V10 环境下最容易翻车的五个点
4.1 镜像拉取报 no matching manifest
现象:kubeadm init或部署 flannel 时 pod 一直ImagePullBackOff,kubectl describe pod显示no matching manifest for linux/arm64。
原因:部分镜像仓库只推了 amd64 架构的 manifest,没有 arm64。ARM 环境下这个问题比 x86 频繁得多。
解决:用docker manifest inspect或skopeo inspect确认镜像是否有多架构支持。没有的话找替代镜像,或者用--platform linux/arm64指定。kubeadm 相关镜像用阿里云源基本都有 arm64,第三方组件要逐个确认。
4.2 kubelet 启动报 cgroup driver 不一致
现象:systemctl status kubelet显示failed to run Kubelet: misconfiguration: kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs"。
原因:containerd 默认配置里SystemdCgroup = false,而 kubelet 默认用 systemd。
解决:改/etc/containerd/config.toml中SystemdCgroup = true,然后systemctl restart containerd && systemctl restart kubelet。这个坑在 Kylin V10 上尤其常见,因为默认安装的 containerd 配置模板就是 false。
4.3 节点 NotReady 且 flannel pod CrashLoopBackOff
现象:从节点加入后一直 NotReady,kubectl logs看 flannel 容器报failed to find plugin "flannel" in path [/opt/cni/bin]。
原因:CNI 插件二进制没装或路径不对。
解决:确认/opt/cni/bin/flannel存在且可执行。如果是从压缩包解压的,检查解压路径是不是/opt/cni/bin而不是当前目录。ARM 版本的 CNI 插件包名带arm64,别下成 amd64 的。
4.4 kubeadm init 卡在 etcd 健康检查
现象:kubeadm init输出[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods,然后超时。
原因:etcd 镜像没拉下来,或者 ARM 环境下 etcd 启动时 CPU 指令集不兼容。
解决:先crictl ps -a看 etcd 容器状态,如果是 Exited 就看crictl logs <id>。Kylin V10 在部分 ARM 芯片上需要确认 CPU 支持crc32指令,etcd 对这点有要求。另外检查/etc/kubernetes/manifests/etcd.yaml里的镜像地址是否可访问。
4.5 join 时 token 过期或证书 hash 不匹配
现象:从节点执行 join 命令报couldn't validate the identity of the API Server: abort connecting to API servers after timeout。
原因:token 过期,或者--discovery-token-ca-cert-hash值不对。
解决:在 master 上kubeadm token create --print-join-command重新生成完整命令。hash 值可以用openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'手动算。
5. 集群验证与日常运维:从节点状态到故障转移的实操技巧
集群跑起来只是第一步,日常运维里几个命令和检查习惯能省很多事。先看节点和 pod 的分布:
# 查看节点状态和角色 kubectl get nodes -o wide # 查看所有命名空间的 pod 分布 kubectl get pods -A -o wide # 查看节点资源占用 kubectl top nodeskubectl top需要 metrics-server,ARM 环境下 metrics-server 的镜像同样要确认 arm64 支持。装完后kubectl top nodes能看到 CPU 和内存使用率,一主一从的拓扑里从节点资源利用率是重点观察对象。
containerd 环境下的调试命令和 Docker 不同,常用的有:
# 查看容器列表(类似 docker ps) crictl ps # 查看镜像列表 crictl images # 查看 pod 沙箱 crictl pods # 查看容器日志 crictl logs <container-id>crictl默认连的 socket 是unix:///var/run/dockershim.sock,containerd 环境要改:
cat > /etc/crictl.yaml <<'EOF' runtime-endpoint: unix:///var/run/containerd/containerd.sock image-endpoint: unix:///var/run/containerd/containerd.sock timeout: 10 debug: false EOF不改这个文件,crictl ps会报连接拒绝。这是从 Docker 转 containerd 最容易忽略的一步。
故障转移方面,一主一从的拓扑本身没有 master 高可用,但可以验证 pod 在节点故障时的重新调度。手动把从节点关机,观察 master 上的 pod 状态:
# 模拟从节点不可用 systemctl stop kubelet # 在 master 上观察 pod 驱逐 kubectl get pods -A -o wide -w默认情况下,节点 NotReady 超过 5 分钟(--node-monitor-grace-period)后,pod 会被标记为Terminating并在其他可用节点重建。一主一从只有 master 能承接,所以会看到 pod 全部挤到 master 上。这个测试能验证集群的故障转移逻辑是否正常,但生产环境别这么干,master 资源扛不住。
最后说一个验证集群 DNS 的技巧。CoreDNS 在 ARM 环境下偶尔会有解析问题,用 busybox 测试:
kubectl run test-dns --image=busybox:1.36 --rm -it --restart=Never -- nslookup kubernetes.default如果返回Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local,说明 DNS 正常。ARM 版的 busybox 镜像要确认是多架构的,busybox:1.36官方支持 arm64。
从那以后我每次部署完 K8S 集群,都会强制走一遍crictl ps+kubectl get pods -A+ DNS 测试这三步,确认运行时、调度、网络三个层面都通了才交付。这套 Kylin V10 + ARM + containerd 的资源合集把镜像地址、cgroup 配置、CNI 路径这些容易翻车的点都覆盖到了,照着走能少熬几个夜。希望帮到你。
本文还有配套的精品资源,点击获取