1. 为什么在ARM架构下部署K8s值得单独写一篇
装过K8s的人应该都有体会:从裸机到集群跑起来,其实就是一条标准流水线。装容器运行时、初始化控制面、装CNI网络插件、等所有Pod就绪,熟手一小时以内可以搞定。但是,当你拿到的是一台ARM架构的服务器,流水线就可能变成处处碰壁的炼狱。同样的命令,x86上没问题,ARM上就直接报错,或者镜像根本拉不下来。这不是个例,而是横在所有ARM部署者面前的普遍痛点。
这篇文章要解决的就是这个痛点。标题里有两个关键词:ARM架构,以及K8s 1.34.5 与 KubeSphere 3.4.1 的组合。ARM架构意味着从操作系统选型、软件源配置、容器运行时,到镜像仓库里的每一个镜像,都必须有 arm64/aarch64 的版本,缺一个就卡壳。Kubernetes 提供底层容器编排能力,KubeSphere 3.4.1 则是构建在其之上的企业级容器平台,提供可视化运维、多租户、监控日志等功能。两者一起部署,实际工作中也大多是为了获得一个开箱即用的容器云管理界面。
文章会覆盖两条完整路径:一条是在线部署,教你从零开始把集群拉起来;另一条是离线部署,适合内网隔离、没有外网访问权限的生产环境。两条路径都会包含实际操作中验证过的步骤和踩坑记录。适合谁看?维护着ARM服务器、准备上K8s的运维,做边缘计算或者私有云方案的技术人,以及刚拿到一批国产ARM机器、想从零建集群的团队。不管你是第一次接触ARM,还是已经在x86上熟练了想迁移,这篇内容都能帮你把试错成本降下来。
1.1 标题拆解:我们要交付什么
把标题拆开看,任务其实包含三个交付物:第一,基于ARM架构的Kubernetes 1.34.5集群;第二,KubeSphere 3.4.1平台;第三,支持在线安装和离线安装两种交付方式。
先说Kubernetes。1.34.5属于当前较新的K8s版本,控制面组件(kube-apiserver、kube-controller-manager、kube-scheduler、kubelet、kube-proxy)都需要对应的v1.34.5二进制,而且必须是arm64版本。ARM架构下这些二进制不太好找,很多人就是卡在这一步。再说KubeSphere 3.4.1。它本质上不是一个单体应用,而是一堆部署在集群里的组件构成,包括 ks-apiserver、ks-console、ks-controller-manager,以及Prometheus监控栈、Grafana、Elasticsearch日志组件等。安装时不仅要拉KubeSphere本身的镜像,还要带上一堆依赖组件镜像,离线场景下要准备的材料非常多。
最后说在线/离线。在线部署的逻辑是网络可达、软件源可用,难点在于拉镜像的速度和版本匹配。离线部署的逻辑是全面隔离,任何需要从外网获取的东西都要预先准备好,包括系统软件包、K8s二进制、所有容器镜像。两种模式翻车点完全不同,我会分别细讲。
1.2 在线和离线是两种完全不同的底层逻辑
为什么要分开写?因为它们的准备思路差异极大。在线部署,你只需要一台能访问外部网络镜像仓库的ARM机器,给系统配置好软件源,装上containerd,初始化集群,CNI网络起来,KubeSphere基本就顺了。最大的变量是网络速度和镜像加速。
离线部署就麻烦一点。你得在另一台同样ARM架构且有网的机器上,把所有需要的东西导出成文件,再搬到目标内网。这包括Kubernetes组件二进制、containerd安装包、系统依赖包、所有相关镜像的tar包,缺一样都不行。而且离线环境下无法临时从Docker Hub拉镜像,所以必须提前建好私有镜像仓库,或者把镜像导入到节点本地。
还有一点很多人会忽略:离线打包必须在同架构机器上进行。在x86机器上导出的镜像tar包,拿到ARM机器上是没法用的。这不是简单的跨平台可执行文件问题,而是容器镜像的镜像平台标识就是linux/arm64,架构不匹配,容器运行时拒绝启动。
2. 部署前置要素准备
2.1 确认ARM架构与系统环境
拿到机器之后,第一步不是装软件,而是确认CPU架构。执行uname -m,输出 aarch64 就说明是64位ARM架构。ARM64和aarch64在绝大多数场景下可以看作同一个概念,软件包标识和Docker镜像平台字段里有时候写linux/arm64,有时候写linux/arm/v8,指的都是同一个目标平台。
系统方面,基于ARM64的Linux发行版都可以,常见的开源选项有Ubuntu ARM版和openEuler,具体看你的使用习惯。需要注意的是,不同发行版的软件源结构不同,对容器运行时和K8s组件的支持程度也不同。有的旧版本系统自带glibc版本过低,可能会带不动最新版Kubernetes的二进制,所以尽量别用太老的版本。
节点规划建议如下表格:
| 节点角色 | 主机名 | 配置推荐 | 系统盘 | 说明 |
|---|---|---|---|---|
| Master | arm-master | 4核8G | 50G SSD | 跑控制面组件和KubeSphere控制面 |
| Worker-1 | arm-worker1 | 8核16G | 100G SSD | 跑业务负载和KubeSphere监控组件 |
| Worker-2 | arm-worker2 | 8核16G | 100G SSD | 跑业务负载和日志组件 |
如果只是测试环境,也可以单节点部署,把Master和Worker合并。但要做完整功能演示,尤其是跑KubeSphere的监控和日志栈,建议至少给Master节点分配4核8G,否则内存很快会被打满,出现各种OOM导致的组件重启。
2.2 系统初始化:关闭Swap和防火墙
这部分和x86上部署K8s的逻辑一致,但ARM机器上比较容易遗忘。首先关闭Swap,Kubernetes从1.8版本开始明确要求节点必须关闭Swap,否则kubelet会拒绝启动。编辑/etc/fstab,把swap那一行注释掉,然后swapoff -a临时关闭。
然后关闭防火墙。生产环境当然是按最小权限放行端口,但部署阶段建议先关闭系统防火墙,排除干扰项。命令是systemctl disable --now firewalld或者用对应发行版的防火墙管理命令。如果是在有安全管控的环境里,至少要确保Kubernetes的6443、2379-2380、10250、30000-32767端口互通。
还需要加载内核模块。K8s依赖overlay和br_netfilter两个模块,前者是容器镜像分层存储的基础,后者用于网桥流量经过iptables处理。用下面的命令写入系统配置:
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter接着写内核网络参数:
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 vm.swappiness = 0 EOF sudo sysctl --system这几个参数尤其重要。net.bridge.bridge-nf-call-iptables保证节点上的iptables规则能作用于容器间的网桥流量,不设置的话,Service的ClusterIP转发很可能不生效,出现跨Pod访问不通的诡异问题。net.ipv4.ip_forward是Pod出网通信的基础,缺少它,Pod无法访问外网。
还有一个容易忽略的点:时间同步。Kubernetes集群对时间偏差很敏感,尤其多节点场景下,如果节点间时间差超过一定阈值,etcd会报错,kubelet的健康检查也会异常。ARM机器很多没有内置RTC电池,开机后时间容易混乱,建议部署前安装并启用chrony或者ntp,确认timedatectl显示的时间和实际时间一致。
3. 在线部署:Kubeadm完整流程加KubeSphere 3.4.1
3.1 容器运行时Containerd的安装与配置
先在/etc/apt/sources.list或者yum源里确认一下,软件源支持aarch64架构,这一点很重要,有的第三方源默认只同步了x86_64的包,会导致安装containerd时直接报"No matching package"。官方源和主流开源镜像源基本都已经同步了ARM架构的容器运行时包,建议直接使用官方源。
安装containerd本身没什么特别的,apt install containerd.io或yum install containerd即可。真正的问题是配置。用默认配置在ARM上跑,大概率会出问题。安装完成后,执行:
mkdir -p /etc/containerd && containerd config default | sudo tee /etc/containerd/config.toml然后重点修改两个地方。第一,SystemdCgroup改成true,让containerd使用systemd管理cgroup。第二,sandbox_image的默认值是registry.k8s.io/pause:3.10,但这个地址在很多网络环境访问不了,需要改成你本地能访问的镜像仓库地址,并且确保这个pause镜像是有linux/arm64平台的版本。
修改后的关键配置大致长这样:
[plugins."io.containerd.grpc.v1.cri"] sandbox_image = "你的可访问仓库地址/pause:3.10" [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true改完配置文件后重启containerd:
systemctl restart containerd systemctl enable containerd具体操作不复杂,但要注意:pause镜像哪怕晚一步配置,集群初始化时kubelet会反复创建sandbox失败,报Failed to create pod sandbox。而这个问题在网络不可达时极其隐蔽,因为NotReady状态会让人先怀疑kubelet配置,实际上就是初始化容器的镜像拉不下来。
3.2 安装Kubeadm、Kubelet、Kubectl
这里的主版本必须跟目标集群版本一致,也就是v1.34.5。用软件源安装时,先锁定版本号:
apt-get install -y kubelet=1.34.5-00 kubeadm=1.34.5-00 kubectl=1.34.5-00ARM架构下安装这三件套时,同样要确认软件源。装完之后需要让kubelet开机自启,但不让它自动启动,因为还没有初始化集群,直接启动会报错:
apt-mark hold kubelet kubeadm kubectl systemctl enable kubeletapt-mark hold是为了避免后面apt upgrade把版本升级,导致和文档不一致。我在实际部署中发现,版本漂移是集群出各种兼容性问题的重要来源,锁定版本是很有必要的习惯。
3.3 用Kubeadm初始化控制面
初始化之前,先拉取控制面镜像。这一步能提前发现网络问题,避免在init过程里卡住。可以用kubeadm直接拉:
kubeadm config images list --kubernetes-version v1.34.5 kubeadm config images pull --kubernetes-version v1.34.5 --image-repository xxx--image-repository用于指定镜像仓库地址,如果你的网络访问registry.k8s.io不通,就换成可访问的公共镜像仓库地址。注意,仓库里的镜像必须包含arm64版本,否则pull阶段会提示manifest unknown。
拉完镜像,开始初始化。典型命令如下:
kubeadm init \ --apiserver-advertise-address=192.168.1.11 \ --kubernetes-version v1.34.5 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12--pod-network-cidr这个网段要跟CNI插件的默认网段匹配,不同CNI插件的默认网段不一样。以Calico为例,它的默认网段通常是192.168.0.0/16,而Flannel默认是10.244.0.0/16。我在自己的环境里习惯用10.244.0.0/16搭配Flannel,或者192.168.0.0/16搭配Calico,避免后面手工调整网络配置。这里以10.244.0.0/16为例,后面选Flannel或者Calico时都需要对应调整。
执行成功后,终端会输出三部分内容:kubeconfig配置命令、join token命令、以及安全提示。kubectl的配置文件是这样的:
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config执行完后可以用kubectl get nodes查看Master节点,此时状态应该是NotReady,因为CNI网络插件还没装,这个是预期的。
3.4 安装CNI网络插件
Kubernetes本身不提供Pod间网络通信方案,需要装CNI插件。推荐看场景,Calico功能全面,支持NetworkPolicy,适合生产;Flannel简单轻量,适合快速验证。
安装Calico时,直接用官方提供的manifest文件:
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/calico.yaml官方manifest是multi-arch的,在ARM节点上会自动拉取对应的arm64镜像,所以只要镜像能拉到,节点网络就会自动就绪。如果网络环境不好,可以先把calico.yaml下载下来,把里面的image地址改成私有仓库地址,再kubectl apply。
在ARM架构下有个常见坑:Calico默认使用的bird进程和VXLAN模式对内核模块有要求,少数精简版内核没有编译相应的overlay模块,会导致Calico Pod起不来。遇到这种情况,检查节点的dmesg日志有没有相关报错,然后选择换成IPIP模式或Flannel的VXLAN。
等Pod状态全部Running后,Master节点状态会变成Ready:
kubectl get nodes3.5 Worker节点加入
Worker节点只需要安装containerd、kubelet和kubeadm,然后执行Master初始化时输出的join命令即可:
kubeadm join 192.168.1.11:6443 --token xxxx --discovery-token-ca-cert-hash sha256:xxxx如果token过期,在Master上重新生成:
kubeadm token create --print-join-command在ARM架构下经常遇到的一个问题是Worker节点跟Master节点镜像仓库配置不一致,导致初始化Pod拉镜像失败。不管你是几台Worker,都要保证containerd的sandbox_image配置一致,这个步骤不能省。
3.6 安装KubeSphere 3.4.1
KubeSphere的在线安装比较简单,它提供了一套基于Kubernetes原生资源的安装方式。先安装核心配置文件:
kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.4.1/kubesphere-installer.yaml kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.4.1/cluster-configuration.yaml第一条命令会创建KubeSphere需要的Namespace、CRD和Controller。第二条命令会创建一个ClusterConfiguration对象,它告诉安装器要启用哪些组件,比如监控、日志、告警等。实际项目中,可以根据机器配置剪裁,如果只有4核8G的Master,建议先只启用核心功能,监控日志组件后续再开,不然内存很容易被撑爆。
安装过程会持续几分钟到十几分钟不等,取决于镜像拉取速度。查看进度:
kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f等全部Pod Running后,拉取控制台服务:
kubectl get svc -n kubesphere-system ks-console默认情况下,KubeSphere控制台通过NodePort暴露,端口通常是30880。初始管理员账号是admin,初始密码在较新版本中一般是P@88w0rd,首次登录后会强制要求修改。建议登录后立刻把默认密码改掉,并把账号绑定到平台内置的多因子认证上。
4. 离线部署:没有互联网也能交付集群
4.1 离线方案整体介绍
离线部署的核心是物料准备。在线部署是实时从网络上拉取组件和镜像,离线部署则要求你提前把所有组件和镜像打包成一个文件,搬到目标环境后解压、导入、安装。相比在线部署,离线多出来的工作量都在准备阶段。
工程上常用的离线部署组件是KubeKey。它可以做到一条命令同时处理Kubernetes和KubeSphere的安装。KubeKey会把以下内容打包到artifact文件里:Kubernetes组件二进制、etcd二进制、containerd安装包、所有相关容器镜像,以及KubeSphere安装所需的各类chart和CRD。在目标机器上导入artifact之后,再执行集群创建命令,它就不需要访问任何外部网络。
离线部署最适合的场景包括:政务或企业内部完全隔离的网络环境、客户现场不允许外联的生产环境、以及依赖公网不稳定导致在线安装反复失败的边缘机房。
4.2 在联网的ARM准备机上生成离线物料
准备机必须是ARM架构,可以是云上的一台arm64虚机,也可以是你本地的一台同架构服务器。至于为什么要同架构,前面已经讲过,就不再重复了。
首先下载KubeKey。在arm64机器上,需要下载的是arm64版本的kk二进制。下载完成后赋予可执行权限并移到系统路径:
chmod +x kk sudo mv kk /usr/local/bin/下一步是生成manifest。manifest是离线打包的清单文件,它声明了要导出的版本和组件范围:
kk create manifest --k8s v1.34.5 --with-kubesphere v3.4.1执行后会生成一个manifest.yaml文件,它里面定义了要打包哪些镜像仓库、哪些组件版本。在ARM机器上生成的manifest会自动带arm64的架构标识,不需要手工改。
如果需要修改镜像仓库为内网仓库,可以编辑manifest里的仓库配置项,把所有镜像的仓库前缀改成目标内网仓库地址,这样后续安装时就无需再调整。
接着导出artifact:
kk artifact export -m manifest.yaml -o k8s-kubesphere-arm64.tar.gz这条命令会做两件事:下载所有Kubernetes和KubeSphere相关镜像,并拉取Kubernetes和etcd二进制,然后打包到单个tar.gz文件里。文件大小通常在2到4GB之间,取决于启用的组件数量。导出过程最耗时,网络好也要等一段时间,建议在磁盘空间充裕的机器上操作,导出前先df -h确认空间足够。
导出完成之后,把artifact文件和接下来要用的配置文件一起拷贝到离线环境的跳板机上。
4.3 在目标内网导入镜像仓库
离线机器上需要准备两样东西:一是刚才导出的artifact包,二是一个可用的私有镜像仓库。你可以选择在企业内网已有的镜像仓库,也可以直接在目标节点上启动一个registry服务。
KubeKey提供了一个导入命令,可以直接把artifact里的镜像导入到节点的本地containerd里:
kk artifact import -m manifest.yaml -o k8s-kubesphere-arm64.tar.gz这个命令会在本机启动一个临时容器仓库服务,把镜像全部加载进去,然后后续集群创建时就从本地这个仓库拉取。如果你的目标环境有多台节点,就需要把artifact分发到每一台节点上分别执行导入,或者搭建一个能被所有节点访问的私有镜像仓库。
生产环境建议选择后者。在有网准备机上提前把镜像推送进私有仓库,然后在目标环境修改所有节点的containerd配置,指向该仓库地址。KubeKey的离线安装虽然支持节点本地仓库,但多节点环境下同步artifact文件还要考虑磁盘空间和传输时间,不如统一仓库来得干净。
4.4 离线创建集群并带上KubeSphere
在目标环境先写好集群配置文件。最简单的方式是先生成一个默认配置:
kk create config --with-kubesphere v3.4.1然后修改生成的config.yaml,把节点IP、角色、SSH账号密码、主机名等信息填进去。单节点测试下,只保留一个master+worker节点即可。
关键配置项包括:
apiVersion: kubekey.kubesphere.io/v1alpha1 kind: Cluster metadata: name: arm-cluster spec: hosts: - { name: master1, address: 192.168.1.11, internalAddress: 192.168.1.11, user: root, password: "你的密码", arch: arm64 } - { name: worker1, address: 192.168.1.12, internalAddress: 192.168.1.12, user: root, password: "你的密码", arch: arm64 } roleGroups: etcd: - master1 control-plane: - master1 worker: - worker1 controlPlaneEndpoint: ip: 192.168.1.11 domain: cluster.local kubernetes: version: v1.34.5 imageRepo: 你的私有仓库地址 registry: plainHTTP: true privateRegistry: 你的私有仓库地址注意arch: arm64这个字段,KubeKey依赖这个字段判断节点架构。如果填错成amd64,后面拉镜像会匹配到x86版本,节点直接起不来。
配置无误后离线创建集群:
kk create cluster -f config.yaml --with-kubesphere v3.4.1安装器和kubelet会在节点上逐步执行:导入二进制、初始化containerd、创建etcd、启动控制面、安装CNI、部署KubeSphere组件。整个过程不需要外网。因为镜像已经导入,所以也不会卡在ImagePull阶段。
等输出日志中出现控制台访问信息,就说明安装完成。同样的,默认端口30880访问控制台,默认账号密码跟在线安装一致。
5. ARM架构下的典型坑点与调优
5.1 镜像架构不匹配是最隐蔽的问题
在线安装时,Pod报ImagePullBackOff,很多人第一反应是网络问题或者镜像不存在,但ARM环境里最常被忽视的是架构不匹配。
判断方法很简单,在Node上手动拉镜像时会看到类似提示:
crictl pull your.registry.com/xxx:v1.34.5如果镜像仓库里只有linux/amd64的镜像,拉取时会返回manifest unknown。有些镜像设置了multi-arch索引,会自动拉arm64,有些镜像没有,那就会报错。所以在准备镜像时,尽量用docker manifest inspect或者crane manifest检查目标镜像是否包含linux/arm64平台。
这个坑在离线部署里更致命,因为离线包生成时如果拉了amd64镜像,目标机器上根本发现不了,直到Pod起不来才会暴露。我自己的做法是,在准备机上完成artifact导出后,随便挑几个关键镜像,比如pause、kube-apiserver、calico-node,通过crictl检查镜像的平台字段,确认都是arm64之后才开始搬运。
5.2 系统软件源和glibc兼容性
ARM机器上安装系统依赖包,最容易出问题的就是软件源。很多第三方软件源只同步了x86_64的包,执行apt或yum安装的时候会报404或者找不到包。解决方式直接换成官方源或者支持aarch64的公共镜像源。
另一个问题是glibc版本。新版本Kubernetes的二进制对系统的glibc版本有要求,如果系统比较老,运行kubelet时会报:
version `GLIBC_2.32' not found遇到这种问题,不要试图手动升级glibc,太容易把系统搞崩。正确做法是选择新一点的系统镜像重新部署,比如把系统替换为较新的长期支持发行版。
5.3 Calico和Flannel在ARM上的选择
CNI插件选择上,我在ARM环境更倾向于Flannel或者Calico的VXLAN模式。原因很简单:ARM节点尤其在多租户环境中,网络性能比x86要敏感,Overlay封装的开销更大。Flannel的VXLAN实现比较轻量,对ARM的支持也稳定。Calico的eBPF数据面在较新的内核上才支持,而且ARM上对eBPF的适配不如x86成熟,使用默认iptables模式时性能还行,但配置复杂度略高。
如果内网环境万兆以上,MTU设置不正确直接导致Pod间大包通信异常,出现TCP传输慢、小包正常大包卡住的现象。解决办法是手动调整Calico的MTU,参考物理网卡MTU,减去VXLAN封装头开销。
5.4 内核参数与内存分配调优
ARM设备做K8s节点时,内存通常比x86同价位服务器紧张。跑KubeSphere时最直观的感受是Prometheus组件非常吃内存。KubeSphere默认的监控栈会占用大约2到3GB内存,如果Master节点只有8GB,光控制面组件就接近临界值。
建议在安装KubeSphere时,在cluster-configuration.yaml里裁剪组件。比如先不启用日志组件,减少Elasticsearch的副本数,或者调整Prometheus的存储保留时长从默认7天改成2天。保留30到60天的监控数据是后期需求,初期先把集群跑稳更重要。
内核参数方面,在原有K8s标准参数基础上,我习惯追加以下内容:
net.core.somaxconn = 65535 net.ipv4.tcp_max_syn_backlog = 65535 fs.file-max = 1048576net.core.somaxconn调整的是Pod内高并发连接队列长度,特别是跑七层代理或网关类应用时,默认值128会明显限制接入能力。fs.file-max则需要跟节点内存匹配,防止高并发场景下出现toomany open files。
5.5 证书过期与版本锁定的提醒
Kubernetes默认签发的一年期证书,集群跑了一年之后,控制面和Kubelet通信证书就会陆续失效。节点会慢慢变成NotReady,kube-apiserver日志里报证书过期。在ARM集群里处理方式跟x86一样,执行:
kubeadm certs renew all然后重启控制面组件。注意,证书续期的前提是集群还能正常访问,如果已经过期到完全不可用的状态,就要手动备份etcd后重新初始化。为了避免这种局面,建议从一开始就写好证书到期的监控告警。
另外,ARM环境里更要注意容器运行时的版本锁定。containerd升级有时会改变配置兼容行为,一旦集群稳定就不要频繁升级。每升一个主版本,先在一台非生产节点上验证,避免全线升级导致集群雪崩。
6. 常见问题速查表
6.1 部署阶段排查清单
下面表格里的内容,是我在ARM部署过程中实际遇到过的典型问题和处理方式,直接照着排查可以省很多时间:
| 现象 | 可能原因 | 排查和处理 |
|---|---|---|
| kubeadm init一直拉镜像失败 | 镜像仓库地址不通,或缺arm64镜像 | 先kubeadm config images pull单独测试,仓库不通就换可访问地址并配置containerd |
| kubelet报sandbox创建失败 | pause镜像地址不可达或用了amd64平台 | 检查containerd的sandbox_image配置,确保是arm64的pause镜像 |
| 节点状态一直是NotReady | CNI网络插件未装或装错 | 检查是否有calico/flannel pod在Running,否则查看kubelet日志定位网络模块 |
| Calico Pod反复重启 | 系统内核缺少overlay模块或MTU配置不对 | `dmesg |
| CoreDNS一直Pending或CrashLoop | 节点DNS配置错误或宿主机resolv.conf包含无效DNS | 调整节点DNS设置,检查CoreDNS配置中upstreamNameserver |
| Worker节点加入后无法就绪 | kube-proxy或CNI daemonset没有调度到该节点 | kubectl get pod -A -o wide看worker上的关键Pod,排查镜像和调度标签 |
| KubeSphere控制台无法访问 | ks-console svc未Ready或端口被防火墙挡 | 查看ks-console svc的NodePort,确认Pod全部Running,防火墙放行端口 |
| Pod创建很慢卡在ContainerCreating | Volume插件或镜像拉取慢 | 确认存储相关组件运行正常,镜像提前导入到本地containerd |
6.2 运行阶段优化建议
集群稳定运行后,建议做几件事。第一,把kubectl get nodes的节点状态做成监控告警;第二,定时检查证书过期时间,提前续期;第三,定期清理容器镜像的悬空tag,避免本地磁盘被堆积镜像占满。
镜像GC方面,containerd默认会在磁盘使用率达到85%时触发回收,但回收策略比较保守,有时候GC不彻底。可以在crictl层面手动清理异常Pod和残留镜像:
crictl rmi --prune还有一个细节是日志轮转。容器日志如果不做轮转,长时间运行会写满系统盘。Kubernetes的kubelet可以配置日志轮转参数,在/etc/sysconfig/kubelet里加上:
KUBELET_EXTRA_ARGS="--container-log-max-files=5 --container-log-max-size=100Mi"这个配置会限制单个容器日志文件大小和最大文件数,在ARM机器上尤为重要,因为ARM设备本地磁盘通常比x86服务器小,日志打满盘之后整个节点会进入异常状态,Pod会被拉走,排查起来非常被动。
在长期运行的大型集群里,建议逐步引入集群层面的监控和日志方案,把节点日志统一收集到中心化存储,具体工具按团队现有技术栈选就好。
我个人在实际部署中的体会是,ARM架构的K8s集群没有幸存者偏差,只要在准备阶段把架构确认、镜像平台验证、软件源配置三关过好,后面其实跟x86差别不大。但如果这三关有一关没守住,后续排查的时间往往是最初部署时间的几倍。最后再分享一个小技巧:在一开始部署时就把集群配置文件和离线artifact文件归档好,标注清楚版本号和架构平台,很多看起来玄乎的环境问题,最后都是因为版本不一致导致的,归档做得好,问题能少一半。