news 2026/9/17 6:11:11

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
K8S离线混合架构高可用集群部署实战:基于sealos与containerd

生产环境里做一次真正的 K8S 离线部署,比在网上看一百篇安装教程都管用。尤其是这次我们遇到的组合:一半 x86_64 节点、一半 aarch64(ARM64)节点、内网隔离没有外网、要求 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控制面 + etcd
master-021x86_64CentOS Stream 9 / Anolis控制面 + etcd
master-031x86_64CentOS Stream 9 / Anolis控制面 + etcd
node-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。基本流程:

  1. 在联网机器上同步需要的仓库到本地目录,用reposyncyumdownloader --resolve
  2. 把仓库目录整体拷到离线环境,比如/data/yum-repo
  3. 离线节点上写 repo 文件:
[local-baseos] name=Local BaseOS baseurl=file:///data/yum-repo/baseos gpgcheck=0 enabled=1 [local-appstream] name=Local AppStream baseurl=file:///data/yum-repo/appstream gpgcheck=0 enabled=1
  1. 执行yum clean all && yum makecache,确认本地源生效。

不要等到部署到一半发现缺个conntrack-toolsipvsadm再到处找包,离线环境的每一分钟都很贵。

3. 高可用入口的离线落地:keepalived + haproxy 与 apiserver 的关系

3.1 为什么集群有了多 master 还是需要 VIP

Kubernetes 高可用,核心是 apiserver 高可用。kubeadm 或 sealos 部署的多个 master 节点都会启动 apiserver,但客户端(kubectl、kubelet、业务组件)不可能一个个去试哪个 apiserver 活着,它们需要一个稳定的虚拟 IP。

正常有云环境的做法是挂一个云负载均衡,把 6443 端口转发到所有 master 的 6443。纯离线机房没有云 LB,最通用、最轻的方案就是 keepalived + haproxy:keepalived 提供虚拟 IP(VIP),haproxy 做四层 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 配置核心在 backend:

backend 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.tarregistry.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 Clusterfile

4.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 会在初始化时自动写入SystemdCgroup=true,这点比自己手工改config.toml稳妥。

但自动写入不等于不用检查。部署完成后,我习惯手动看一遍关键节点上的 containerd 配置:

crictl info

重点确认systemdCgroup是否为true,以及 sandbox 镜像是否是本架构对应的 pause 镜像。不同架构节点上,pause 镜像的架构应该各不相同,这正是混合架构部署的隐藏细节之一。

4.3 join 节点和等待就绪的容错设计

如果集群先建了 3 个 master,后面再单独添加 ARM 工作节点,不需要重新跑整个 Clusterfile。可以在 Clusterfile 里单独列出新节点架构和 IP,再次 apply,sealos 会识别已存在的集群并只对新节点做 join:

spec: hosts: - roles: [node] ips: [192.168.1.23, 192.168.1.24] arch: arm64

离线环境下sealos apply可能因为节点资源不足或网络延迟失败。我的建议:无论失败在哪个环节,都不要盲目重跑,先看crictl ps -ajournalctl -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。如果出现大量000502,说明 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 nodetype=arm kubectl label node node-x86-01 nodetype=x86

然后写典型的多架构验证 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的 deployment,Pod 都处于 Running 状态后,说明多架构镜像拉取和容器运行时工作正常。如果某个 Pod 一直CreateContainerConfigErrorCrashLoopBackOff,优先检查镜像架构是不是真的包含当前节点平台。

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/amd64linux/arm64。没有的话,用前面说的 skopeo 同步方式重新推送。

6.6 Apple Silicon 上模拟 x86 构建的坑

最后说一个很现实的教训。有人图省事,想在 Apple Silicon Mac 上用虚拟机模拟 x86 环境去构建离线包和 rpm。M 系列芯片的虚拟化仿真性能差到离谱,而且构建出来的产物是不是真的 x86 兼容,还得实测验证,简单跑一遍 yum 安装很容易漏问题。

正确做法是在真正的 x86_64 服务器上完成所有 x86 物料的下载和验证;ARM 物料就在 ARM 机器上准备。多架构的事情,最后一定要回到真实架构的机器上验证。虚拟机里的“看起来没问题”,在离线生产环境里往往就是隐患。

这次项目跑完,我个人最大的感受是:混合架构离线部署本身没有特别高深的技术,真正的复杂度全在“提前量”上——镜像有没有备齐全架构、离线源是否可靠、节点架构规划是否清晰、高可用入口是否演练过。方案可以抄,但这些细节不自己走一遍,很难形成肌肉记忆。如果你们也在规划类似的集群,先把上面这些物料清单逐项打勾,再谈一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 6:10:36

工业智能系统芯片选型与协同设计实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 6:10:00

SMT加工厂怎么选?12个现场验厂避坑要点

1. 为什么“选厂”这件事&#xff0c;比谈价格还烧脑&#xff1f;在SMT行业干了十二年&#xff0c;从贴片机操作员做到工艺主管&#xff0c;再带过三家代工厂的产线审核&#xff0c;我见过太多客户把“选SMT加工厂”当成点外卖——看个报价、扫眼资质、微信聊两句就下单。结果呢…

作者头像 李华
网站建设 2026/9/17 6:09:25

V100单卡跑Qwen3.8-27B:从28到38.6 tok/s的llama.cpp调优实录

如果你手头只有一张 V100&#xff0c;又想跑 Qwen3.8-27B 这个量级的模型&#xff0c;大概率已经看了一堆“换 GPU”的建议。但现实就是设备就在那儿&#xff0c;预算也就这么点&#xff0c;任务卡在这里&#xff0c;必须想办法把它跑起来、跑得稳、跑得快。我前后折腾了三个周…

作者头像 李华
网站建设 2026/9/17 6:08:38

Altium Designer 20.2 实战指南:从安装到PCB设计的高效技巧

1. 安装与首启&#xff1a;20.2最容易卡人的三个位置用Altium Designer做过项目的人都有印象&#xff0c;真正折磨人的往往不是画原理图本身&#xff0c;而是从安装那一刻就开始的连环坑。20.2这个版本在功能上确实能打&#xff0c;但它的安装流程和首启设置做得相当有"个…

作者头像 李华
网站建设 2026/9/17 6:07:37

R1CS与QAP:零知识证明的数学基础解析

1. R1CS 与 QAP 原理概述在密码学和可信计算领域&#xff0c;零知识证明技术正变得越来越重要。作为其中的核心组件&#xff0c;R1CS&#xff08;Rank-1 Constraint System&#xff09;和QAP&#xff08;Quadratic Arithmetic Program&#xff09;构成了许多现代零知识证明系统…

作者头像 李华