恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
sealos离线部署Kubernetes 1.20.12:从tar.gz到高可用集群实战
首页
资讯中心
/
sealos离线部署Kubernetes 1.20.12:从tar.gz到高可用集群实战
sealos离线部署Kubernetes 1.20.12:从tar.gz到高可用集群实战
发布时间:2026/9/23 10:26:15
简介面向 Kubernetes 离线部署与运维场景这是一个以 sealos 方式打包的 Kubernetes 1.20.12 完整安装包适合网络受限环境、需要快速交付或二次封装 K8s 集群的运维与开发人员。压缩包约 530.85MB共 59 个文件覆盖 kubeadm、kubelet、kubectl、crictl、nerdctl、conntrack 等核心二进制init.sh、master.sh、containerd.sh、init-kube.sh 等自动化脚本以及 systemd service 配置、Calico/Kubeadm YAML、containerd 离线镜像 tar 包和 cri-containerd-cni 组件。包内附有多份 README 和配置文件便于理解各模块之间的关系同时包含 libseccomp.so 等底层依赖库降低离线环境下的依赖排查成本。已有 226 人浏览学习对于那些希望快速复现 K8s 1.20.12 环境、对照脚本理解集群初始化流程或基于 sealos 做离线交付方案的技术人员来说这套材料提供了可直接参考的脚本、配置与目录组织示例。1. kube1.20.12.tar.gzsealos内网交付 Kubernetes 的第一种形态拿到一个kube1.20.12.tar.gz大多数人的第一反应是解压看看。其实这个文件名本身就暴露了使用它的工具链前面的kube是 Kubernetes 的通用缩写1.20.12是具体的小版本号.tar.gz是打包压缩格式——但到底是谁在消费这个压缩包答案是 sealos而且一定是老版本的 sealos因为从 v4 开始它已经改叫 CloudImage不再用这种裸的 tar.gz 命名了。这个压缩包的真正价值在不联网的机房。Kubernetes 1.20.12 那个年代把一个集群装起来需要拉取 apiserver、controller-manager、scheduler、etcd、pause 等二十多个镜像内网环境没有外部网络全靠提前准备好一个离线仓库。kube1.20.12.tar.gz就是 sealos 在 v1/v2 时代做这件事的载体集群需要的所有容器镜像、二进制文件和部署配置被打进一个包sealos 在目标机器上自建 registry然后直接把镜像分发到 node 节点。这篇内容适合两类人。一类是负责机房交付、需要反复搭建同版本集群的运维另一类是刚接触 sealos、手头正好有一个别人移交下来的kube1.20.12.tar.gz不知道如何下手的工程师。我会按「离线包机制 → 部署步骤 → 镜像导入 → 参数与规避问题 → 版本锁定」的顺序把这个 tar.gz 从拿到手到稳定运行的关键路径拆清楚重点讲那些不跑一遍就会翻车的地方。2. 拆开 kube1.20.12.tar.gz离线包内部结构与 sealos 的分发机制2.1 sealos 为什么要把 Kubernetes 打包成 tar.gz在 sealos 出现之前kubeadm 是搭建 Kubernetes 的主流方式但 kubeadm 本身不负责镜像仓库的初始化。你在内网跑kubeadm init它会尝试从外部镜像仓库拉取组件镜像没有外网就卡死。通常的补救手段是提前在一台有网的机器上把镜像 pull 下来再docker save成 tar 拷进内网最后docker load。问题在于一个集群涉及十几台机器每台都要重复导入而且docker save之后的镜像归档和 kubeadm 期望的镜像名可能对不上修正过程非常痛苦。sealos 的解决思路是把「镜像归档」和「镜像分发」合并到一个动作里。kube1.20.12.tar.gz内部不是一个简单的镜像 tar而是一个完整的安装包里面包含 Docker 镜像压缩层数据、Kubernetes 组件的二进制文件kubeadm、kubelet、kubectl、etcd 镜像、pause 镜像、coredns 配置以及 sealos 自己定义的配置元数据。sealos 在目标机器上解包后会先启动一个本地 registry 服务然后把包里的镜像全部 push 到本地 registry节点上的 kubelet 可以直接从这个 registry 拉取。这个设计把集群交付简化成两个动作拷贝 tar.gz 到任意一台 master 节点然后执行 sealos 的初始化命令。相比 kubeadm 的多步操作sealos 更像一个「Kubernetes 集群安装器的安装包」这也是它敢于直接对外发布打包文件的原因。kube1.20.12.tar.gz 在 sealos v1/v2 时代是标准的离线分发包到了 v4 被 CloudImage 取代但核心思路没有变化。2.2 tar.gz 解压之后能看到什么手头拿到一个kube1.20.12.tar.gz不要盲目直接传给 sealos 去执行先解压看一眼。常见做法是在一台闲置机器上拆包确认里面文件结构是否符合预期尤其是你要部署的架构是 amd64 还是 arm64镜像列表里有没有你需要的组件。tar -tzvf kube1.20.12.tar.gz | head -50这条命令不实际解压只是列出归档内的文件清单。输出里一般能看到images/目录存放压缩后的镜像层bin/目录存放 kubelet、kubeadm、kubectl 二进制可能还有一个conf/目录存放 sealos 的部署模板。镜像文件的格式通常是images/*.tar即 Docker save 之后未压缩的镜像归档。tar -xzf kube1.20.12.tar.gz -C /opt/kube-offline find /opt/kube-offline -type f | head -30真正解压到/opt/kube-offline后重点看两份东西images/下有多少个镜像文件以及conf/或scripts/下有没有版本说明。输入输出的对应关系是如果images/下有 ten 几个镜像文件说明是一个相对完整的集群镜像集如果只有三四个可能是一个裁剪版本只能用kubeadm init完成控制面搭建worker 节点需要的镜像得另行准备。这里有个参数容易被忽略tar -xzf的-C指定解压目录务必使用绝对路径。如果你解压到一个包含空格的路径后续 sealos 读取配置时可能因为路径解析问题失败。另外解压后的目录最好保留在 root 用户可读的位置因为 sealos 执行时涉及 systemd 服务写入和/etc/kubernetes目录的创建普通用户权限不够。2.3 sealos 的本地 registry 分发原理解开 tar.gz 后sealos 初始化集群的第一步不是直接跑 kubeadm而是启动一个本地 registry。这是它和 kubeadm 最根本的区别。sealos 在 master 节点上启动一个 registry 容器监听默认端口 5000然后把包内的镜像全部 push 进去。每个 node 节点加入集群时kubelet 配置里的imagePullPolicy是IfNotPresent并且配置了私有仓库地址因此会优先从这台 master 的 registry 拉取镜像。sealos init --master 192.168.1.10 \ --node 192.168.1.11 --node 192.168.1.12 \ --passwd YourPassword \ --kubernetes-version v1.20.12 \ --pkg-url /opt/kube-offline/kube1.20.12.tar.gz以上是 sealos v2 时代的典型写法。--master指定控制平面节点 IP--node指定工作节点 IP可以重复声明多个--passwd是 ssh 远程连接密码--pkg-url指向 tar.gz 的路径。set 参数说明一下--kubernetes-version必须与 tar.gz 内部的版本完全一致否则 sealos 在解包阶段找不到对应的 kubeadm 二进制会直接报错退出--pkg-url支持本地路径也支持 http 远程下载但内网环境建议提前把包放在每台机器都能访问的共享目录避免重复下载。执行完 init 后sealos 会通过 ssh 把 kubelet、kubeadm、kubectl 二进制分发到所有节点配置 systemd 服务写入/etc/kubernetes下的证书与 kubeconfig最后启动 kubeadm init。整个流程看起来像一体的实际是分阶段的registry 启动 → 镜像推送 → 二进制分发 → kubeadm init → node join。任何一个阶段失败sealos 都会留下阶段日志排查时不要只看最后的错误提示要回头翻/var/log/sealos下的日志。提示不要试图在生产环境把 tar.gz 删除后再执行 init。sealos 在执行过程中会二次读取包内文件特别是二进制和模板删除后会导致莫名的「文件不存在」错误而且错误信息不会直接指明是你删了包。3. 用 sealos 部署 kube 1.20.12从单机到高可用的完整落地流程3.1 部署前的四个检查项缺一个都别动手跑 sealos 之前先把环境检查做扎实。很多部署失败不是因为 sealos 本身有问题而是基础环境不满足要求。我习惯在每台机器上按顺序跑下述检查。cat /etc/os-release # 确认操作系统发行版与版本sealos 官方支持 CentOS 7.x、Ubuntu 16.04但不同版本的内核模块差异会影响 kubelet 启动 sysctl net.ipv4.ip_forward # 必须返回 1否则 kubelet 无法创建 pod 网络kube-proxy 的转发规则也不会生效 systemctl status firewalld --no-pager # 需要停止并禁用 firewalld否则 6443、10250、2379 等端口会被拦截node join 直接超时 df -h /var/lib/docker # 确保磁盘空闲大于 20Gkube1.20.12 全量镜像解压后占用约 6-8G运行时有日志增长还有一个容易被遗漏但非常关键的检查/etc/hosts。sealos 通过 ssh 访问节点时使用的是 IP但 kubeadm 初始化时会读取机器的主机名并写入证书的 SAN。如果两台机器的主机名一样kubelet 注册时会出现节点名称冲突导致 approve csr 失败。建议先把所有机器的主机名改成不重复的例如k8s-master01、k8s-node01。hostnamectl set-hostname k8s-master01 echo 127.0.0.1 k8s-master01 /etc/hostshostnamectl 修改立即生效但在 ssh 会话里可能不刷新建议新开一个终端确认。这里有个小细节kubeadm 生成的 apiserver 证书里会包含初始化时的节点 IP如果后续你改了 IP证书需要重新生成。所以检查好/etc/hosts和主机名再开始能帮你少走一次清理重来的弯路。3.2 sealos init金丝雀式搭建一套单主集群先别直接上高可用第一次跑通单主集群比什么都重要。单主集群没有 VIP、没有 keepalived、没有 haproxy排错面小很多适合用来验证 tar.gz 包的完整性和 sealos 配置的正确性。sealos init --master 192.168.1.10 \ --node 192.168.1.11 \ --passwd YourPassword \ --kubernetes-version v1.20.12 \ --pkg-url /opt/kube-offline/kube1.20.12.tar.gz \ --network flannel--network flannel是网络插件的选择sealos 内置了 flannel 和 calico 两种模板。1.20.12 的内核版本普遍支持 vxlan 模式flannel 的性能足够配置最简单。若直接省略这个参数sealos 不会安装任何 CNI集群创建成功后只有kube-system的 coredns 处于 Pendingnode 节点状态也会是 NotReady等于集群不可用。所以这个参数不是可选项是必选项。命令执行后sealos 会进入长时间日志输出进度推进大约在 1 到 3 分钟之间取决于机器性能和网络。出现Your Kubernetes cluster has been successfully initialized之类的信息后不要急着欢呼先验证集群状态。kubectl get nodes kubectl get pods -n kube-system -o wide验证输出里node 节点的STATUS必须是Readykube-system 下的所有 pod 都必须处于Running状态。如果 apiserver 起来了但 coredns 一直 CrashLoopBackOff90% 以上是 CNI 没有正确安装重新检查--network flannel是否生效。如果 node 节点NotReady用journalctl -u kubelet -f查看 kubelet 日志常见的报错是 CNI 配置文件找不到或者容器运行时连接失败。3.3 sealos join扩容 worker 节点时的几个硬性注意点单主跑通后再执行节点扩容。扩容在 sealos v2 里用的是 join 命令注意参数不能只写一个 IP--node可以重复写多个也可以写一个网段范围例如192.168.1.11-192.168.1.15。sealos join --master 192.168.1.10 \ --node 192.168.1.11-192.168.1.15 \ --passwd YourPassword \ --kubernetes-version v1.20.12 \ --pkg-url /opt/kube-offline/kube1.20.12.tar.gz--master参数在这条命令里的含义是「集群的已有 master 地址」不能省略否则 sealos 不知道向哪个集群注册新节点。--node的网段写法很方便但注意 sealos 在解析时不会自动跳过已有节点如果你填的范围覆盖了已经加入集群的节点会出现重复 join 的错误报错信息是node xxx already exists此时只需要把该 IP 从参数里去掉。节点加入后sealos 会自动在新节点上执行kubeadm join并把 worker 节点的 kubelet 指向 master 的 apiserver。一个容易踩的坑是--passwd的密码里有特殊字符。如果本地的~/.ssh/id_rsa已经配置了免密登录sealos 优先走密钥通道此时不需要传递--passwd但如果密钥存在但 passwd 也传了sealos 会优先尝试密钥失败后回落到密码登录整个过程没有明确日志提示只会慢 3 到 5 秒。所以统一使用密钥登录是效率最高的做法。加入完成之后返回 master 节点执行kubectl get nodes确认所有新节点进入 Ready。如果某个节点长时间NotReady最先排查的是时间同步master 和 worker 之间时间偏差超过 5 秒kubelet 与 apiserver 的证书校验就会失败节点注册被拒绝。此问题在高可用集群里尤其致命因为 etcd 需要节点间时钟一致。3.4 高可用集群VIP、keepalived 与 haproxy 的联动选型当一个 master 不够用就需要上高可用。sealos 在 v2 版本里内置了 VIP keepalived haproxy 的组合方案每个 master 节点上运行一个 keepalived 实例和一个 haproxy 实例haproxy 负责把访问 VIP 的流量负载均衡到所有 master 的 6443 端口keepalived 负责把 VIP 漂移到当前健康的 master 上。sealos init --master 192.168.1.10 --master 192.168.1.11 --master 192.168.1.12 \ --node 192.168.1.20 \ --passwd YourPassword \ --kubernetes-version v1.20.12 \ --pkg-url /opt/kube-offline/kube1.20.12.tar.gz \ --vip 192.168.1.100 \ --network calico与单主命令对比多了两个关键变化--master写了三个 IP表示三个控制平面节点--vip指定虚拟 IP。注意--vip必须是一个未被占用的、与节点在同一二层网络的地址不能和任何物理机 IP 冲突。实际生产里我也见过把 VIP 配成网关 IP 导致整个集群网络中断的情况这类错误发生得很隐蔽apiserver 证书里写入了 VIP 作为 SAN集群能起来但外部通过 VIP 访问时会被网关设备拦截。另外一个需要调的点是 haproxy 的负载均衡算法。sealos 默认使用roundrobin每个新连接轮流分发到三个 master。这个配置在大多数场景没问题但如果某个 master 因为磁盘 IO 波动导致 apiserver 响应变慢haproxy 不会做健康检查调权。sealos 会把 haproxy 的配置文件生成在 master 节点的/etc/kubernetes/haproxy/haproxy.cfg修改该文件需要手动执行systemctl restart haproxy。生产环境里如果存在某个 master 性能明显低于其他节点建议把算法改成leastconn。关于网络插件高可用场景我建议用 calico 而不是 flannel。原因有两点第一calico 支持 BGP 模式跨网段的 pod 通信不需要额外 overlay第二calico 的 IPIP 模式在节点数量超过三台时性能更好。但代价是配置复杂度上去出现问题排查的链条更长。如果只是验证高可用方案flannel 够用。3.5 部署后的必做验收清单集群部署完成后不要直接交付按下面的顺序跑一遍验收。首先是控制平面高可用验证手动重启一台 master 节点上的 kubelet 服务确认 VIP 漂移到了另一台 master且 kubectl 使用 VIP 地址依然能正常访问。ip a | grep 192.168.1.100 # 确认 VIP 是否飘移重启 kubelet 后 VIP 会转移到其他 master kubectl get leases -n kube-system # 1.20.12 中 kube-controller-manager 与 kube-scheduler 使用 Lease 实现选主第二项是验证 etcd 的健康状态。高可用集群里 etcd 是最容易出问题的组件需要确认 raft 集群是否完整。第三项是验证工作负载的网络通信部署一个 nginx 跨节点访问确认 pod 到 pod 的连通性和 kube-proxy 的 iptables 规则都在工作。kubectl run test --imagenginx:1.20 --replicas2 kubectl get pods -o wide从输出结果中确认两个 pod 不在同一台机器上然后进入其中一个 podcurl 另一个 pod 的 IP能通说明 CNI 正常工作。如果你的环境里 nginx 镜像还没有导入本地 registry这条命令会拉取失败这也是kube1.20.12.tar.gz中只包含 K8s 系统镜像、不含业务镜像的典型问题详见下一章镜像导入方案。4. 避坑kube 1.20.12 sealos 最常见的 5 个翻车点4.1 coredns 一直 CrashLoopBackOff报错 Failed to create listener现象sealos init 成功kubectl 能拿到节点状态但 coredns 始终 CrashLoopBackOff日志里出现Failed to create listener。原因sealos 在某些版本的配置中默认使用--dns-domain为cluster.local如果机器上的/etc/resolv.conf包含 search 配置coredns 启动会尝试监听一个固定的 loopback 地址与系统自带的 systemd-resolved 占用冲突。这在 Ubuntu 18.04 及以上版本尤其常见。解决把 kubelet 的--resolv-conf参数指定到一个空文件或独立配置文件避免系统 dns 干扰。修改文件位于 master 节点/etc/systemd/system/kubelet.service.d/10-kubeadm.conf添加--resolv-conf/etc/resolv.conf使其与系统实际配置一致然后依次重启 kubelet 和 coredns。若不想改 kubelet 参数也可以在初始化前把/etc/resolv.conf整理干净去掉 search 域。4.2 node join 之后 apiserver 一直 403现象sealos join显示成功但新节点上执行kubectl get pods报禁止访问master 节点查看 kube-system 下有 csr 处于 Pending 状态。原因1.20.12 的 kubeadm 采用NodeRestriction准入控制器新节点的 kubelet 第一次启动时会向集群发送证书签名请求。如果集群环境里 RBAC 规则不完整或 controller-manager 的证书未被正确签名csr 不会被自动 approve。sealos 有时因为节点二进制版本与 master 不一致生成的 kubelet 证书无法通过校验。解决手动 approve 对应的 csr并检查二进制版本是否一致。kubectl get csr kubectl certificate approve csr-name4.3 kube-proxy 反复重启后台日志报 iptables 版本太旧或冲突现象高可用集群部署后kube-proxy 所在 pod 出现反复重启日志中报错iptables v1.8.0: unknown option --wait部分机器上iptables-nft与iptables-legacy模式不兼容。原因不同发行版对 iptables 的默认模式不一致。CentOS 8 默认走 nft 模式而 Ubuntu 16.04 走 legacy 模式。kube-proxy 在启动时会自动探测系统当前模式但如果系统里 nft 与 legacy 共存且配置混乱kube-proxy 无法正确选择导致规则写入失败。解决统一每个节点的 iptables 模式到 legacy并重新启动 kube-proxy 服务。update-alternatives --set iptables /usr/sbin/iptables-legacy systemctl restart kube-proxy.service另外建议把内核参数net.bridge.bridge-nf-call-iptables设为 1否则 kube-proxy 的 FORWARD 链规则不会生效。4.4 清理重装时 vip 残留导致 apiserver 不可达现象用 sealos clean 清理集群后重新执行 init但 apiserver 一直无法绑定 VIP报Address already in use。原因sealos clean 清掉了集群配置但没有彻底清理 keepalived 和 haproxy 的 systemd 服务残留old vip 绑定的端口没有释放。解决在每台 master 上手动停掉残留服务再重新执行 init。systemctl stop keepalived systemctl stop haproxy systemctl disable keepalived systemctl disable haproxy然后确认ip a里已经没有 VIP 地址再执行新的 init。这个坑在反复测试多主集群时出现的频率很高sealos 本身确实没有做完整的服务残差清理。4.5 离线包里没有 pause 镜像pod 一直 ContainerCreating现象集群能起来但任何 pod 都卡在ContainerCreatingkubelet 报错Failed to create pod sandbox: unable to pull sandbox image。原因这个原因出乎很多人意料sealos 旧版离线包里的镜像列表是在 amd64 环境生成的如果你的机器架构是 arm64镜像列表里的 pause、coredns 镜像名没有带架构标签导致 kubelet 按照 amd64 架构拉取拉下来发现无法运行。解决手动确认本地 registry 里的 pause 镜像架构并给 kubelet 配置--pod-infra-container-image参数直接指定为本地 registry 里架构正确的镜像完整路径。或者干脆在初始化时用-e参数覆盖镜像地址。sealos 在 init 时支持环境变量传入利用它把 pause 镜像指到你确认可用的那份镜像上。5. 玩转 kube1.20.12 镜像的离线导入与版本锁定5.1 把 tar.gz 里的镜像导入到本地 registrykube1.20.12.tar.gz 里的镜像不仅服务于集群建设阶段后续你运行一个有状态服务也会从 master 节点的本地 registry 拉取镜像。但业务镜像不在包里因此需要建立一个持久化的导入流程。sealos 的 registry 在 master 上以容器方式运行端口固定为 5000。docker exec sealyun-registry ls /var/lib/registry/docker/registry/v2/repositories如果你的 master 节点上 registry 容器名不是sealyun-registry使用docker ps --format {{.Names}}查看实际名称。上面命令列出当前镜像仓库里的所有仓库名如果里面只有 kubernetes 相关镜像说明业务镜像还没有导入。以下代码将本地的镜像 tar 包导入到 sealos 的本地 registrydocker run -d --name registry-importer \ -v /opt/registry-data:/var/lib/registry \ registry:2这样每次需要导入镜像时先docker load -i your-image.tar然后docker tag指向仓库地址再 push 进去。例如导入 nginx 镜像docker load -i nginx.tar docker tag nginx:1.20 192.168.1.10:5000/nginx:1.20 docker push 192.168.1.10:5000/nginx:1.20注意标签中的 IP 地址必须与 kubelet 配置的--image-pull-progress-deadline所在网络可通且所有 node 节点都能访问 5000 端口不能只在本机通。push 完成后在任一 node 节点上docker pull 192.168.1.10:5000/nginx:1.20验证网络可达性。提示用 docker run 方式导入 registry 镜像数据/var/lib/registry 挂载不会影响 sealos 的 registry 数据但无法无缝 merge 已有仓库。如果你的 tar 覆盖多个项目命名空间建议直接导入到 sealos 自带 registry 容器内即把打包镜像导入到/var/lib/registry并重启 registry 容器用docker exec执行验证。5.2 版本锁定理解 image tag 与 sha256 的关系kube1.20.12 的镜像在离线包内通常带确切版本号例如registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.20.12。但这不意味着以后你手动导入其他镜像时也能保证一致性。真正能实现锁定的有两层一是镜像 tag二是镜像 diges。在生产环境我建议只信任 tar.gz 内自带的那份镜像列表清单。docker inspect registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.20.12 \ --format {{.RepoDigests}}这条命令返回sha256:...格式的摘要信息。如果后续有人在你的离线环境里手动导入一个同 tag 但内容不同的镜像用这条命令对比摘要即可快速判断是否一致。为了避免人为误操作可以把这个摘要记录下来放在部署文档里作为环境基线。5.3 手动更新组件版本把 1.20.12 升级到同一分支的补丁版本1.20.12 是 1.20 分支的一个补丁版本。如果你希望升级到 1.20 分支的末尾补丁版本比如 1.20.15但不升级到 1.21那么需要重新对系统组件做镜像替换和二进制替换。这个操作 sealos 本身不直接支持常见做法是先备份若环境可接受直接重建集群。kubectl drain --ignore-daemonsets --delete-local-data k8s-master01 kubectl delete node k8s-master01这三个动作是「驱逐 删节点」的标准操作。随后在该节点上按新版本重新执行 sealos init或单节点加入再把节点重新加入集群。但此操作对多主集群而言来回切换过程比较长而且证书的 SAN 可能包含旧版本信息。所以如果有升级需求应该在部署之初就用稍高版本的离线包而不是指望后期打补丁。我这里给出的建议是非必要不升级。Kubernetes 1.20 是一个已经很成熟的分支如果只是修复 CVE应该通过升级到更高分支解决而不是在 1.20 版本内补丁。如果确认要停留在 1.20 分支则从离线包构建阶段就固定版本并保证每台机器都从同一份校验和确定的 tar.gz 部署。5.4 版本锁定在配置里怎么体现把版本锁定落实到配置层面关键是 Clusterfile。早期 sealos v2 没有 Clusterfile所有配置通过命令行参数传递。后来引入 Clusterfile 统一管理初始化配置这让重复部署同一个版本的集群变得非常简单。cat Clusterfile.yaml EOF apiVersion: sealos.cluster.com/v1 kind: Cluster metadata: name: my-cluster spec: image: kube1.20.12.tar.gz masters: - 192.168.1.10 nodes: - 192.168.1.11 ssh: passwd: YourPassword EOF上面的 Clusterfile 描述了最简配置。注意image字段直接指向你的 tar.gz 文件名说明 sealos v4 之前的版本里这个文件可以反复被同一个 sealos 版本消费。masters和nodes是固定字段接受 IP 列表。执行方式也简单sealos init --cluster Clusterfile.yaml用 Clusterfile 的好处是版本信息和节点信息都在同一份配置里不会出现「代码里明明写的 1.20.12实际部署成 1.20.13」这种连锁问题。如果你需要维护多套环境建议把 Clusterfile 纳入 git 管理每次变更走评审流程集群部署就不再是黑匣子。6. 进阶把 kube1.20.12 部署变成可复现的交付模板多套环境重复部署时我见过两种典型浪费。第一种是每次都用命令行参数现敲一旦中间出错排查完还要对比历史命令找差异第二种是把初始化命令写死在文档里但文档和实际执行的命令早就对不上。这两种问题的解法是相同的把kube1.20.12.tar.gz、Clusterfile 配置、镜像导入脚本、验收命令全部保存在一个项目目录里用 git 管理形成一个「可复现的交付模板」。具体做法我给一个参考。目录结构大致是offline-package 存 tar.gzconfig 目录存 Clusterfile 和各主机 hosts 模板scripts 目录放 init.sh、add-node.sh、del-node.sh 和 verify.sh。init.sh 内部就先做环境检查再做部署#!/bin/bash set -e hostname sealos init --cluster config/Clusterfile.yaml kubectl get nodes -o wide脚本末尾加一个最简单的输出判断确保只有所有节点 Ready 才继续往下走否则直接退出并给出错误信息避免「以为部署成功、实际没起来」的尴尬。新增一个 node 就调用 add-node.sh它内部读取同一个 Clusterfile只把 nodes 列表扩一行然后执行 sealos join。这样整套交付靠脚本驱动不受人工状态影响也比记一条长命令可靠。到了这一步技术本身的坑都踩得差不多了剩下的是组织层面的沉淀。我自己的习惯是每次部署完会把这三个值补到交付文档的固定位置tar.gz 的 sha256 校验和、初始化命令的关键参数、以及验证集群时 kubectl get nodes 的输出。后续再有人接手这套环境不用猜当初是怎么装的看文档就能精确复现。这个习惯帮我避免过太多次「这环境怎么跟想象中的不一样」的被动局面希望帮到你。本文还有配套的精品资源点击获取