生产环境建议控制平面 3 节点高可用(配合 keepalived/kube-vip)。
⚠️ ARM 关键点:所有容器镜像必须是 arm64/v8 架构。官方 registry.k8s.io、Calico、Flannel 镜像均为多架构(multi-arch),会自动拉取 arm64 版本,无需手动指定。
以下步骤在master 与所有 worker上都要做。
# 在各节点分别执行(按角色修改主机名)hostnamectl set-hostname k8s-master1#另外节点修改成 k8s-master2 / k8s-master3#worker 节点改为 k8s-worker1 / k8s-worker2
在所有节点追加 hosts:
cat >> /etc/hosts <<'EOF'172.19.69.21 k8s-master1172.19.69.22 k8s-master2172.19.69.23 k8s-master3172.19.69.24 k8s-worker1172.19.69.25 k8s-worker2EOF
setenforce 0sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config# 验证sestatus
Kubernetes 要求关闭 swap,否则 kubelet 无法正常工作。
swapoff -ased -i '/swap/s/^/#/' /etc/fstab# 验证(应无输出)free -m | grep -i swap
dnf install -y chrony# 使用国内 NTP 源(可选)sed -i 's/^pool.*/pool ntp.aliyun.com iburst/' /etc/chrony.confsystemctl enable --now chronydchronyc sources -v
cat <<'EOF' | tee /etc/modules-load.d/k8s.confoverlaybr_netfilterEOFmodprobe overlaymodprobe br_netfilter# 验证lsmod | grep -E 'overlay|br_netfilter'
cat <<'EOF' | tee /etc/sysctl.d/k8s.confnet.ipv4.ip_forward = 1net.bridge.bridge-nf-call-ip6tables = 1net.bridge.bridge-nf-call-iptables = 1EOFsysctl --system
大规模集群建议 kube-proxy 使用 IPVS。预装 IPVS 模块:
dnf install -y ipset ipvsadmcat <<'EOF' | tee /etc/modules-load.d/ipvs.confip_vsip_vs_rrip_vs_wrrip_vs_shnf_conntrackEOFmodprobe ip_vs
控制平面节点(master):
firewall-cmd --permanent --add-port=6443/tcp# kube-apiserverfirewall-cmd --permanent --add-port=2379-2380/tcp# etcdfirewall-cmd --permanent --add-port=10250/tcp# kubeletfirewall-cmd --permanent --add-port=10251/tcp# kube-schedulerfirewall-cmd --permanent --add-port=10252/tcp# kube-controller-managerfirewall-cmd --permanent --add-port=10259/tcp# kube-scheduler (新版本)firewall-cmd --permanent --add-port=10257/tcp# kube-controller-manager (新版本)firewall-cmd --permanent --add-port=179/tcp# Calico BGPfirewall-cmd --reload
工作节点(worker):
firewall-cmd --permanent --add-port=10250/tcp# kubeletfirewall-cmd --permanent --add-port=30000-32767/tcp# NodePortfirewall-cmd --permanent --add-port=179/tcp# Calico BGPfirewall-cmd --reload
若为内网测试环境,也可直接关闭防火墙:
systemctl disable --now firewalld(生产环境不建议)。
#--本次实验环境直接禁用防火墙
Docker 官方仓库提供 aarch64 包(CentOS 8 仓库与 Rocky 8 兼容):
dnf install -y dnf-plugins-corednf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repodnf makecachednf install -y containerd.io
若国内访问 Docker 官方源较慢,可使用阿里云镜像(同样支持 aarch64):dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.reposed -i 's|download.docker.com|mirrors.aliyun.com/docker-ce|g' /etc/yum.repos.d/docker-ce.repo
mkdir -p /etc/containerdcontainerd config default > /etc/containerd/config.toml
修改两处关键配置:
① 启用 systemd cgroup 驱动(与 kubelet 保持一致):
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml② 配置镜像加速器(国内环境推荐,可选):
在 /etc/containerd/config.toml 的 [plugins."io.containerd.grpc.v1.cri".registry.mirrors] 段下添加:
mkdir -p /etc/containerd/certs.d/docker.iocat <<'EOF' | tee /etc/containerd/certs.d/docker.io/hosts.tomlserver = ”https://registry-1.docker.io”[host.”https://docker.m.daocloud.io”]capabilities = [”pull”, ”resolve”]EOF
并在 config.toml 中启用 config_path(containerd 1.7+ 推荐方式):
sed -i 's|config_path = ””|config_path = ”/etc/containerd/certs.d”|' /etc/containerd/config.tomlsystemctl enable --now containerdsystemctl status containerd --no-pager
cat <<'EOF' | tee /etc/crictl.yamlruntime-endpoint: unix:///run/containerd/containerd.sockimage-endpoint: unix:///run/containerd/containerd.socktimeout: 10debug: falseEOF
官方仓库使用 $basearch,在 aarch64 上会自动解析为 aarch64,已提供 ARM64 包:
cat <<'EOF' | tee /etc/yum.repos.d/kubernetes.repo[kubernetes]name=Kubernetesbaseurl=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/enabled=1gpgcheck=1gpgkey=https://pkgs.k8s.io/core:/stable:/v1.33/rpm/repodata/repomd.xml.keyexclude=kubelet kubeadm kubectl cri-tools kubernetes-cniEOF
说明:Kubernetes 新版仓库迁移至 pkgs.k8s.io,按次版本(如 v1.33)分通道,同时提供 x86_64 与 aarch64 架构包。如需其他版本,将 v1.33 改为对应次版本(如 v1.31)即可。
国内若访问 pkgs.k8s.io 较慢,可临时使用阿里云镜像(需确认其 aarch64 可用性):
baseurl=https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.33/rpm/
# 查看可用版本dnf list --showduplicates kubeadm --disableexcludes=kubernetes# 安装(示例固定 1.30.x;根据上面列出的最新补丁版本调整)dnf install -y kubelet-1.33.1-150500.1.1 kubeadm-1.33.1-150500.1.1 kubectl-1.33.1-150500.1.1 --disableexcludes=kubernetes
dnf remove -y kubelet kubeadm kubectl
systemctl enable --now kubelet# 此时 kubelet 会反复重启是正常的(尚未 kubeadm init),可忽略
# 查看所需镜像kubeadm config images list --kubernetes-version=v1.33.1[root@master21 /]# kubeadm config images list --kubernetes-version=v1.33.1registry.k8s.io/kube-apiserver:v1.33.1registry.k8s.io/kube-controller-manager:v1.33.1registry.k8s.io/kube-scheduler:v1.33.1registry.k8s.io/kube-proxy:v1.33.1registry.k8s.io/coredns/coredns:v1.12.0registry.k8s.io/pause:3.10registry.k8s.io/etcd:3.5.21-0# 预拉取(registry.k8s.io 为多架构,会自动拉取 arm64 版本)kubeadm config images pull --kubernetes-version=v1.33.1
查看镜像架构的版本(是X86,还是ARM)
cat <<'EOF' | tee kubeadm-init.yamlapiVersion: kubeadm.k8s.io/v1beta3kind: InitConfigurationlocalAPIEndpoint:advertiseAddress: 172.19.69.21# 改为 master 实际 IPbindPort: 6443nodeRegistration:criSocket: unix:///run/containerd/containerd.sockimagePullPolicy: IfNotPresentname: master21---apiVersion: kubeadm.k8s.io/v1beta3kind: ClusterConfigurationkubernetesVersion: v1.33.1# 与安装版本一致controlPlaneEndpoint: 172.19.69.21:6443networking:podSubnet: 192.168.0.0/16# Calico 默认 CIDR,必须与 CNI 一致serviceSubnet: 10.96.0.0/12---apiVersion: kubelet.config.k8s.io/v1beta1kind: KubeletConfigurationcgroupDriver: systemdEOF
1、替换以下内容:
apiVersion: kubelet.config.k8s.io/v1beta1kind: KubeletConfigurationcgroupDriver: systemdEOF
2、修改 /etc/containerd/config.toml 文件vi /etc/containerd/config.toml
--##sandbox_image = "registry.k8s.io/pause:3.8"
⚠️ podSubnet 必须与后面 Calico 的默认网段一致(Calico 默认 192.168.0.0/16)。若用 Flannel 则改为 10.244.0.0/16。
kubeadm init --config=kubeadm-init.yaml --upload-certs | tee kubeadm-init.log主节点master21
[root@master21 ~]
kubeadm join 172.19.69.21:6443 --token 9kbhpo.g78s8yw1nwseoeir --discovery-token-ca-cert-hash sha256:9f91de41964611bbfeb4fed7a2ef28f6ff6645cf90245349555bf6f39be3db33 --control-plane --certificate-key db88a0fb4ad604bd50c900c7d9dccf6cf21a8cc624fdc4f56e499172520292f9
初始化成功后,务必保存输出中的kubeadm join命令(worker 加入要用)。
mkdir -p $HOME/.kubesudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/configsudo chown $(id -u):$(id -g) $HOME/.kube/config
若用 root 用户:
export KUBECONFIG=/etc/kubernetes/admin.conf# 写入 /etc/profile 持久化echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' >> ~/.bashrc
此时查看节点,master 状态为 NotReady(尚未安装 CNI,属正常):
kubectl get nodeskubeadm init phase upload-certs --upload-certs
删除多作的MASTER控制节点[root@master21 ~]
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master21 NotReady control-plane 12m v1.33.1
master22 NotReady control-plane 3m10s v1.33.1
master23 NotReady control-plane 3m35s v1.33.1
node24 NotReady control-plane 3m12s v1.33.1
node25 NotReady control-plane 3m28s v1.33.1
kubectl drain node24 --ignore-daemonsets --delete-emptydir-data --force
kubectl delete node node24
ETCD_POD=$(kubectl get pods -n kube-system -l component=etcd -o jsonpath='{.items[0].metadata.name}')
kubectl exec -it -n kube-system $ETCD_POD -- etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key --endpoints=https://127.0.0.1:2379member list
3d5b62c253307d43, started, node24,https://172.19.69.24:2380,https://172.19.69.24:2379, falsec15a6b2290b25976, started, master21,https://172.19.69.21:2380,https://172.19.69.21:2379, falsed2ae4cab79113a34, started, master22,https://172.19.69.22:2380,https://172.19.69.22:2379, falsef60d7c7443c12032, started, node25,https://172.19.69.25:2380,https://172.19.69.25:2379, falsef94beacdc4f2ad9d, started, master23,https://172.19.69.23:2380,https://172.19.69.23:2379, false
kubectl exec -it -n kube-system $ETCD_POD -- etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key --endpoints=https://127.0.0.1:2379member remove 3d5b62c253307d43
NODE24上操作:
systemctl stop kubelet
kubeadm reset --force
crictl rm -f $(crictl ps -aq) 2>/dev/null || true
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -Xipvsadm --clear 2>/dev/null || true
rm -rf ~/.kube/
kubectl get nodes
ETCD_POD=$(kubectl get pods -n kube-system -l component=etcd -o jsonpath='{.items[0].metadata.name}')kubectl exec -it -n kube-system $ETCD_POD -- etcdctl --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key --endpoints=https://127.0.0.1:2379member list
kubectl drain node25 --ignore-daemonsets --delete-emptydir-data --forcekubectl delete node node25
ETCD_POD=$(kubectl get pods -n kube-system -l component=etcd -o jsonpath='{.items[0].metadata.name}')
Calico 官方 manifest 为多架构,可直接在 ARM 上使用:
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/tigera-operator.yamlkubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/custom-resources.yaml
curl -Ohttps://raw.githubusercontent.com/projectcalico/calico/v3.28.2/manifests/calico.yaml
kubectl apply -f calico.yaml
kubectl get pods -n kube-system -l k8s-app=calico-node -o widekubectl get pods -n kube-system -l k8s-app=calico-node -o wide
custom-resources.yaml 默认 CIDR 为 192.168.0.0/16,与上面的 podSubnet 一致。若使用不同网段,需修改该文件中的 cidr 字段。
观察 Calico Pod 是否就绪:
watch kubectl get pods -n calico-system使用第 5.2 步保存的 join 命令:
kubeadm join 172.19.69.21:6443 \--token 9kbhpo.g78s8yw1nwseoeir \--discovery-token-ca-cert-hash sha256:9f91de41964611bbfeb4fed7a2ef28f6ff6645cf90245349555bf6f39be3db33
若 token 过期,在 master 重新生成:
kubeadm token create --print-join-command# 节点状态kubectl get nodes -o wide# 所有 Pod 状态(应全部 Running)kubectl get pods -A# 组件健康kubectl get cs# 集群信息kubectl cluster-info
预期输出:所有节点 Ready,kube-system 下 CoreDNS、kube-proxy 均 Running。
部署一个 ARM 镜像应用确认调度正常:
部署 3 个 nginx 副本kubectl create deployment nginx --image=nginx --replicas=3kubectl expose deployment nginx --port=80 --type=NodePortkubectl get pods,svckubectl create deployment nginx --image=nginx:stable --replicas=2kubectl expose deployment nginx --port=80 --type=NodePortkubectl get pods,svc
nginx:stable 官方镜像为多架构,在 ARM 节点上会自动拉取 arm64 版本。
crictl inspect | grep architecture
确认 aarch64 包可用:
dnf list available kubelet kubeadm kubectl --disableexcludes=kubernetes# 若能列出即说明 aarch64 包已就绪
ARM 部分 SoC 内核可能未编译 br_netfilter / overlay。若 modprobe 报错 not found:
# 检查模块是否存在find /lib/modules/$(uname -r) -name 'br_netfilter*'# 若缺失,需安装/更新对应内核模块包,或更换 Rocky 官方 aarch64 内核dnf update kernelreboot
最常见原因:cgroup 驱动不一致。
# 确认 containerd 配置grep SystemdCgroup /etc/containerd/config.toml# 应为 true# 确认 kubelet 配置(kubeadm init 时已设为 systemd)grep cgroupDriver /var/lib/kubelet/config.yaml# 重启systemctl restart containerd kubelet
通常是 CNI 未安装或 podSubnet 网段不匹配。检查:
kubectl get pods -n kube-systemkubectl describe pod -n kube-system
确保 CNI 已部署且 podSubnet 与 CNI 配置一致。
kubectl describe node k8s-worker1# 查看 Events 与 Conditions,常见为 CNI 未就绪 / 防火墙拦截
kubeadm reset -frm -rf /etc/cni/net.d /var/lib/cni /var/lib/etcd /var/lib/kubelet/*iptables -F && ipvsadm -Csystemctl restart containerd
生产环境务必固定版本,防止 dnf update 意外升级导致集群异常:
# 安装 versionlock 插件dnf install -y dnf-plugins-corednf versionlock add kubelet kubeadm kubectl containerd.io
升级时手动解除锁定、按计划逐节点升级,升级前务必备份 etcd:
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot.db \--endpoints=https://127.0.0.1:2379 \--cacert=/etc/kubernetes/pki/etcd/ca.crt \--cert=/etc/kubernetes/pki/etcd/server.crt \--key=/etc/kubernetes/pki/etcd/server.key
完成上述步骤后,一个运行于 ARM (aarch64) 平台、基于 Rocky Linux 8.10 的 Kubernetes 集群即可投入使用。