十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

K8S离线混合架构高可用集群部署实战:基于sealos与containerd

K8S离线混合架构高可用集群部署实战:基于sealos与containerd 生产环境里做一次真正的 K8S 离线部署比在网上看一百篇安装教程都管用。尤其是这次我们遇到的组合一半 x86_64 节点、一半 aarch64ARM64节点、内网隔离没有外网、要求 containerd 运行时、交付一套 K8S 1.33.3 高可用集群。标题里每个词单独拎出来都好办但叠在一起坑就从四面八方冒出来了。这篇就围绕我这次实际落地的过程把离线物料准备、双架构镜像处理、高可用入口、一键部署执行链、部署后验证和踩坑记录都整理出来。内容偏实操适合已经了解 Kubernetes 基础、但第一次做离线混合架构集群的运维或平台工程师参考。如果你只是在自己笔记本上用 kind 玩过 K8S看完这篇也能理解生产环境“一个命令拉起集群”背后到底发生了什么。1. 为什么选择“容器版”K8S containerd而不是胶片式的 kubeadm 流程1.1 “容器版”到底是什么意思先说清楚标题里的“容器版”。这里不是指把业务应用容器化而是说集群自身的安装载体是容器镜像。我们用的是 sealos 这条路径把 Kubernetes 集群、相关组件、交付逻辑整体打包成一个集群镜像。部署的时候一条命令把这个集群镜像“run”起来sealos 自动完成证书生成、etcd 启动、apiserver 配置、节点 join、containerd 适配这些脏活累活。这在离线环境里价值极大。传统 kubeadm 离线部署要准备的东西很长一串kubeadm、kubelet、kubectl 二进制各类组件镜像etcd 镜像CNI 插件pause 镜像还要处理 join token、证书过期、镜像仓库地址替换。这些步骤本身不难但架不住量大、易错、每台节点都要一致。集群镜像相当于把“一套已知可工作的 K8S 交付物”固化了到离线环境只需要做 load 和 run。1.2 选型对比sealos、kubeadm、Kubekey、Rancher离线场景下谁更顺手方案离线友好度混合架构支持高可用编排适合场景sealos高save/load 一条龙集群镜像支持多架构按节点架构自动匹配组件多 master 自动配置配合外部 LB/VIP内网交付、混合架构、批量环境复制kubeadm中所有物料自己整理支持但镜像、二进制都要自己按架构备双份手动维护 keepalived/haproxy 和 join 流程喜欢全链路可控、环境极简的小集群Kubekey中高提供离线包对 ARM 支持得看版本x86 更顺依赖 KubeSphere 体系已有 KubeSphere 生态诉求的团队Rancher/RKE2中RKE2 有离线 bundle支持但控制面组件和节点架构绑定逻辑繁琐自身自带高可用编排需要图形化运维面板的场景我最后选 sealos不是因为它多神而是它把“离线”这件事做成了第一公民。集群镜像本身就是为离线交付设计的不用我再手工维护一套复杂的物料清单。同时它对多架构的处理是“透明”的同一个集群镜像里包含多个平台变体x86 节点拉 x86 的部分ARM 节点拉 ARM 的部分部署时不至于因为镜像架构不一致而失败。不过有一点要说明白sealos 是部署工具不是魔法。它最终管理的其实还是 containerd 和 K8S 标准组件。所以真正要下功夫的地方依然是镜像的多架构准备、containerd 配置、高可用入口规划这些才是离线混合架构部署的命门。2. 部署前的物料清单双架构镜像和离线源怎么准备2.1 节点规划先想清楚 master 架构怎么混混合架构高可用集群第一件事不是敲命令而是定节点角色。我的实际建议是生产环境里控制面尽量同构。下面是我们这次用的规划可以作为模板服务器角色数量CPU 架构系统用途master-011x86_64CentOS Stream 9 / Anolis控制面 etcdmaster-021x86_64CentOS Stream 9 / Anolis控制面 etcdmaster-031x86_64CentOS Stream 9 / Anolis控制面 etcdnode-011aarch64镜像仓库 业务节点业务负载node-022aarch64业务节点业务负载为什么控制面保持 x86_64不是因为 ARM 不能跑控制面而是控面组件apiserver、etcd、controller-manager、scheduler对架构差异不敏感但一旦出问题排查链路会叠加“是架构问题还是配置问题”双重不确定性。工作节点混入 ARM反而正好把业务负载的多架构验证做了。如果你们的 ARM 机器必须进控制面理论可行etcd 跨架构节点之间通过网络通信架构并不影响 Raft 日志同步但请务必在测试环境先验证一轮别上来就生产。2.2 镜像双架构导出docker save 是坑skopeo copy 才是正路多架构离线包最关键的坑就在这里。很多人一开始的思路是对的在一台能联网的机器上把所有组件镜像 docker pull 下来再 docker save 成 tar。单架构环境这么做没问题但混合架构环境会翻车。docker pull默认只拉当前节点平台对应的镜像变体你在 x86_64 机器上 pull 了一个多架构镜像docker save 导出的 tar 里往往只有 amd64 的 layer。这个 tar 拿到 aarch64 节点上 load容器是起不来的报错基本就是exec format error。正确的姿势是用 skopeo带--all参数拷贝整个 manifest list# 把多架构镜像完整拷贝到本地 OCI 格式目录 skopeo copy --all --override-arch amd64 docker://docker.io/library/nginx:1.27 oci:nginx-1.27 # 如果要推到内网仓库直接双架构推送 skopeo copy --all docker://docker.io/library/nginx:1.27 docker://registry.internal/library/nginx:1.27--all会保留镜像的所有平台变体而不是只保留当前机器架构的那一份。这步做对了离线包在 x86 和 ARM 节点上都能正常导入和运行。如果你们对安全要求高不允许直接连外部镜像仓库那就找一台“摆渡机”——既通内网又通外网在上面用 skopeo 把所有需要的镜像同步到内网仓库再在离线节点上从内网仓库拉取。这个模式在军工、金融、政务机房都很常见。2.3 离线软件源yum repourl 失效的坑提前规避离线环境第二个经典坑是系统依赖装不上。热词里那个cannot find a valid baseurl for repo: base/7/x86_64就是这么来的CentOS 7 停止维护后老 yum 源地址失效CentOS Stream 9 如果没配置内网镜像源也报类似错。所以在离线节点上执行yum install之前先在联网机器上把依赖包拉下来搭一个本地 repo。基本流程在联网机器上同步需要的仓库到本地目录用reposync或yumdownloader --resolve。把仓库目录整体拷到离线环境比如/data/yum-repo。离线节点上写 repo 文件[local-baseos] nameLocal BaseOS baseurlfile:///data/yum-repo/baseos gpgcheck0 enabled1 [local-appstream] nameLocal AppStream baseurlfile:///data/yum-repo/appstream gpgcheck0 enabled1执行yum clean all yum makecache确认本地源生效。不要等到部署到一半发现缺个conntrack-tools或ipvsadm再到处找包离线环境的每一分钟都很贵。3. 高可用入口的离线落地keepalived haproxy 与 apiserver 的关系3.1 为什么集群有了多 master 还是需要 VIPKubernetes 高可用核心是 apiserver 高可用。kubeadm 或 sealos 部署的多个 master 节点都会启动 apiserver但客户端kubectl、kubelet、业务组件不可能一个个去试哪个 apiserver 活着它们需要一个稳定的虚拟 IP。正常有云环境的做法是挂一个云负载均衡把 6443 端口转发到所有 master 的 6443。纯离线机房没有云 LB最通用、最轻的方案就是 keepalived haproxykeepalived 提供虚拟 IPVIPhaproxy 做四层 TCP 负载健康检查打到 apiserver 的healthz端口。3.2 关键配置片段我在两台专门跑入口的节点上分别装了 keepalived 和 haproxy这两台节点不一定是 K8S 成员负载均衡器独立部署更干净。keepalived 配置核心vrrp_instance K8S_LB { state BACKUP interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass k8s-ha-pass } virtual_ipaddress { 192.168.1.10/24 dev eth0 label eth0:1 } }两台入口节点之间通过 VRRP 协议协商主备优先级高的成为 VIP 持有者。注意两台机器上这段配置除了priority其他基本一致。haproxy 配置核心在 backendbackend kube-apiserver mode tcp option tcp-check balance roundrobin server master-01 192.168.1.2:6443 check server master-02 192.168.1.3:6443 check server master-03 192.168.1.4:6443 check健康检查的意义是如果某个 master 的 apiserver 挂了haproxy 会自动摘掉这台后端客户端请求只打到健康节点。这样即便一台 master 宕机集群 API 依然可达。3.3 混合架构下入口组件怎么装keepalived 和 haproxy 都有对应的 x86_64 和 aarch64 rpm 包。离线环境下两条路提前在联网机器上分别下载两个架构的 rpm然后拷到对应架构节点安装。用容器镜像跑提前导入 haproxy 的多架构容器镜像在节点上用容器方式启动。我建议用 rpm 装。理由很简单这两个组件不需要跟 containerd 绑定用系统服务管理更直观也没必要为它们再引入容器运行时依赖。混合架构下 rpm 包提前备好离线安装十分钟内搞定。真正要容器化的是后面的 K8S 组件。4. 一键部署执行链sealos 离线 run 背后到底发生了什么4.1 承载部署的 tar 包与 Clusterfile离线包准备好后核心就是 sealos 的 save / load / run 三步。在联网机器上sealos pull kubernetes:v1.33.3 sealos save -o k8s-v1.33.3.tar kubernetes:v1.33.3把k8s-v1.33.3.tar和配套的calico.tar、registry.tar等组件镜像包一起拷入离线首节点然后 load 进去sealos load -i k8s-v1.33.3.tar sealos load -i calico.tar真正部署的入口是 Clusterfile。一个混合架构集群的 Clusterfile 设计要点如下字段以你当前 sealos 版本生成的模板为准这里重点是讲解结构含义apiVersion: apps.sealos.io/v1beta1 kind: Cluster metadata: name: default spec: hosts: - roles: [master] ips: [192.168.1.2, 192.168.1.3, 192.168.1.4] arch: amd64 - roles: [node] ips: [192.168.1.20, 192.168.1.21, 192.168.1.22] arch: arm64 image: - kubernetes:v1.33.3 - calico:v3.28注意arch字段。它让 sealos 明确知道每个节点的 CPU 架构从而在对应节点上拉取正确的组件镜像变体。这比人工在 kubeadm 里一处一处改镜像地址省心得多。执行就一行sealos apply -f Clusterfile4.2 这条命令背后的执行逻辑很多人看到“一键”会觉得没东西可学其实恰恰相反。sealos 背后做了一套标准的 K8S 交付流程建立节点间 SSH 互信拷贝证书和配置。为集群生成 CA 和各类证书。在 master 节点写静态 Pod 清单etcd、apiserver、controller-manager、scheduler 以容器方式由 containerd 拉起。在 node 节点初始化 containerd 配置设置 systemd cgroup driver并把 kubelet 注册到 API Server。等待所有节点 Ready然后安装 CNI 插件。这段逻辑里最容易出问题的就是 containerd 配置。kubelet 和容器运行时对 cgroup driver 的要求必须一致否则节点状态一直 NotReady。sealos 会在初始化时自动写入SystemdCgrouptrue这点比自己手工改config.toml稳妥。但自动写入不等于不用检查。部署完成后我习惯手动看一遍关键节点上的 containerd 配置crictl info重点确认systemdCgroup是否为true以及 sandbox 镜像是否是本架构对应的 pause 镜像。不同架构节点上pause 镜像的架构应该各不相同这正是混合架构部署的隐藏细节之一。4.3 join 节点和等待就绪的容错设计如果集群先建了 3 个 master后面再单独添加 ARM 工作节点不需要重新跑整个 Clusterfile。可以在 Clusterfile 里单独列出新节点架构和 IP再次 applysealos 会识别已存在的集群并只对新节点做 joinspec: hosts: - roles: [node] ips: [192.168.1.23, 192.168.1.24] arch: arm64离线环境下sealos apply可能因为节点资源不足或网络延迟失败。我的建议无论失败在哪个环节都不要盲目重跑先看crictl ps -a和journalctl -u kubelet的日志。很多时候失败原因是某个镜像没导全、磁盘空间不够或者节点时间差太大——这些都是日志里一眼能看出来的问题。5. 部署后的验证高可用切换和混合架构调度缺一不可5.1 高可用切换演练不能只看节点 Ready节点 Ready 只是起点高可用得验证过才作数。我的验证套路如下先在任意一台能访问 VIP 的机器上持续探测 apiserver:while true; do curl -k -o /dev/null -s -w %{http_code}\n https://192.168.1.10:6443/healthz sleep 2 done正常情况会持续输出200。然后在一台 master 节点上搞点动静systemctl stop kubelet观察探活结果。如果 keepalived haproxy 工作正常请求不会中断仍然持续 200。如果出现大量000或502说明 VIP 或健康检查链路有问题——常见原因是 haproxy 健康检查 fail 后没有快速摘除或者 keepalived 没有在 VIP 持有者宕机后完成切换。验证完再systemctl start kubelet让节点恢复并确认集群里三个 master 重新同步回 Ready。高可用不是说节点不挂而是挂了之后系统不感知。5.2 架构标签与业务负载调度验证混合架构集群里调度器默认不会替你做架构决策。虽然 K8S 会给每个节点自动打kubernetes.io/arch标签但你跑 nginx、Java 应用时如果不指定架构Pod 可能被调度到不匹配的节点上镜像架构不符立刻起不来。给节点打业务标签把调度逻辑显式化kubectl label node node-arm-01 nodetypearm kubectl label node node-x86-01 nodetypex86然后写典型的多架构验证 deployment。比如用官方多架构 nginx 镜像验证调度到 ARM 节点apiVersion: apps/v1 kind: Deployment metadata: name: nginx-arm64 spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeSelector: kubernetes.io/arch: arm64 containers: - name: nginx image: nginx:1.27 ports: - containerPort: 80再写一份kubernetes.io/arch: amd64的 deploymentPod 都处于 Running 状态后说明多架构镜像拉取和容器运行时工作正常。如果某个 Pod 一直CreateContainerConfigError或CrashLoopBackOff优先检查镜像架构是不是真的包含当前节点平台。6. 混合架构离线部署的坑我替你们踩过了6.1 exec format error混合架构第一杀手这个报错是所有 ARM 节点集群里出现频率最高的。原因很简单容器镜像的入口二进制是 x86 编译的拿到 ARM 节点上CPU 直接拒绝执行。排查链路kubectl describe pod pod-name # 看 Events 里的报错 # 然后确认节点架构 kubectl get nodes --show-labels | grep arch # 再看镜像架构 crictl inspect container-id | grep -i arch解决手段就一句话让镜像架构和节点架构匹配要么换多架构镜像要么给 Pod 加 nodeSelector。所有上报到这里的镜像建议提前用skopeo inspect --raw确认 manifest 里到底包含哪些平台。6.2 docker save 导致离线包缺 ARM 变体这也是我前面反复强调的。印象最深的一次我们拿到的离线业务镜像包里所有镜像全是在 x86 机器上用 docker save 导出结果 ARM 节点一个容器都拉不起来。后来我们统一改用 skopeo--all同步镜像到内网仓库。这里要特别提醒即便镜像在 Docker Hub 上标记为多架构也得看你导出时用的工具。docker save 不保留其他平台变体这不是 docker 的问题而是工作流设计问题——把 skopeo 作为镜像搬运的标准工具才能避免这个坑。6.3 节点 NotReady问题出在 sandbox 镜像K8S 每个 Pod 创建前kubelet 要先通过 containerd 启动一个 sandbox 容器也就是 pause 容器。如果节点上的 pause 镜像架构和节点架构不匹配所有 Pod 都无法创建节点会反复 NotReady。这个坑在纯 x86 环境几乎不会出现但混合架构下特别容易遇到某个 ARM 节点手动初始化时containerd 配置文件里写的 sandbox 镜像还是 x86 registry 的地址和架构变体。解决办法是在对应节点上检查/etc/containerd/config.toml确认sandbox_image指向一个包含 ARM 变体的 pause 镜像。如果是从内存拷贝的配置别偷懒逐节点核对。6.4 CentOS yum 源失效离线仓库必须提前做热词里的cannot find a valid baseurl不是玩笑。特别是 CentOS 7 停止维护后官方镜像源地址全部失效新节点一旦要装基础依赖直接卡死。我的做法在联网机器上用reposync把 baseos 和 appstream 仓库完整同步到本地做成 tar拷进离线机房后执行createrepo建立本地索引再写好.repo文件。这个仓库做完之后不只是这次部署能用后面任何新增节点、装中间件都靠它。6.5 内网仓库里只缓存了单架构镜像很多团队自建了 harbor 或 registry但镜像推送时只推了 x86 版本。混合架构集群拉到这种镜像如果环境里恰好没有对应架构触发到那个节点可能几周后业务扩容到 ARM 节点才炸。建议给所有走混合架构的内网镜像做一次普查skopeo inspect --raw docker://registry.internal/nginx:1.27 | python -m json.tool看 manifest list 里是否同时存在linux/amd64和linux/arm64。没有的话用前面说的 skopeo 同步方式重新推送。6.6 Apple Silicon 上模拟 x86 构建的坑最后说一个很现实的教训。有人图省事想在 Apple Silicon Mac 上用虚拟机模拟 x86 环境去构建离线包和 rpm。M 系列芯片的虚拟化仿真性能差到离谱而且构建出来的产物是不是真的 x86 兼容还得实测验证简单跑一遍 yum 安装很容易漏问题。正确做法是在真正的 x86_64 服务器上完成所有 x86 物料的下载和验证ARM 物料就在 ARM 机器上准备。多架构的事情最后一定要回到真实架构的机器上验证。虚拟机里的“看起来没问题”在离线生产环境里往往就是隐患。这次项目跑完我个人最大的感受是混合架构离线部署本身没有特别高深的技术真正的复杂度全在“提前量”上——镜像有没有备齐全架构、离线源是否可靠、节点架构规划是否清晰、高可用入口是否演练过。方案可以抄但这些细节不自己走一遍很难形成肌肉记忆。如果你们也在规划类似的集群先把上面这些物料清单逐项打勾再谈一键部署。
返回列表