kube1.20.12.tar.gz离线交付实战:Sealos加载、集群初始化与避坑指南
简介Kubernetes 1.20.12 离线部署包基于 sealos 制作面向集群管理员与运维人员解决无公网环境下 K8s 安装依赖多、易出错的问题。资源共 59 个文件涵盖 shell 脚本、yaml 配置、systemd 服务文件、conf 配置文件与离线镜像 tar 包等类型shell 脚本负责自动化安装与初始化yaml 文件定义集群组件参数systemd 服务文件注册守护进程conf 文件保存容器运行时配置tar 包内置离线镜像与二进制整体约 530.85MB目录结构清晰便于按需取用。包内集成了 kubeadm、kubelet、kubectl、containerd 等核心组件以及 calico 网络插件配置、kubeadm 初始化配置和多种自动化脚本可用于快速完成 Master 节点初始化、节点加入与网络插件部署免去逐一下载安装包的繁琐过程。已有 226 人学习/下载借助 sealos 命令行用户能自动化执行环境检查与集群配置大幅降低手动操作复杂度附带的说明文档与多种初始化脚本也为离线部署与排错提供了可参考的实践路径适合具有一定 Linux 基础并希望快速搭建 K8s 环境的读者。对于内网隔离、镜像拉取受限的环境这一部署包尤其实用。1. kube1.20.12.tar.gz 不是安装包是 Sealos 给 1.20 集群做的离线骨架部署过 Kubernetes 的人一眼就能看出这类文件名的分量kube1.20.12.tar.gz不是某个软件的压缩包而是 Sealos 这类工具在离线交付场景里用来把 Kubernetes 1.20.12 整套集群跑起来的最小介质。它里面装的不是源码而是 kube-apiserver、etcd、pause 这些组件的容器镜像以及 Sealos 自己用来拉起集群的编排脚本和配置文件。对这个包最常见的诉求就三个这是什么、能不能直接装、装完哪里会翻车。这篇笔记面向的是拿到包后要在一个隔离环境里交付集群的运维和交付工程师也适合在旧集群上做补丁升级、想搞清楚包里镜像清单的人。它解决的问题很具体一台干净机器到kubectl get nodes全部 Ready中间每一步都看得见、可复现。2. 先把包用起来Sealos 加载 kube1.20.12.tar.gz 与两条命令路径拿到kube1.20.12.tar.gz最忌讳的就是不拆包就直接开跑。同一个 tar 后缀里面可能是两种完全不同的东西一种是用docker save打的普通镜像包另一种是 Sealos 自己构建的集群镜像。这两种东西的加载命令不一样混着用会报manifest unknown或者提示找不到 Kubefile。2.1 先拆包还是先跑命令三分钟判断 tar 是 docker save 产物还是 Sealos 集群镜像我一般会先在包所在的机器上执行tar tzf /opt/media/kube1.20.12.tar.gz | head -20看输出结构再决定下一步。如果是docker save产物前面会出现manifest.json和一堆 64 位十六进制的 layer 目录如果开头就是Kubefile、registry/、etc/这类路径那就是 Sealos 的集群镜像可以直接走sealos load流程。还有一种老式 Sealos 离线包里面是bin/、kube/images/、sh/目录结构对应的是老版本sealos init的--pkg-url参数而不是新版的 load 流程。这一步的价值在于避免选错命令路径。把 docker save 产物塞给sealos loadSealos 会在本地 registry 初始化时报错把集群镜像拿去docker load虽然能导出一堆镜像但 Sealos 的编排逻辑完全没被加载等于白装。三种形态的判断表如下tar 内首层内容判断结果推荐操作manifest.json layer 目录docker save 产物docker load 或导入私有仓库Kubefile registry/ 目录Sealos 集群镜像sealos load -ibin/ kube/images/ sh/老式 Sealos 离线包sealos init --pkg-url提示先跑sealos version或者sealos --help确认当前 Sealos 主版本。1.x/2.x 和 4.x 的加载命令差别很大下面两条路径我都会写到但实际执行以你本机--help输出为准。2.2 老式 Sealos 路径sealos init 直接吃掉本地 tar.gz如果你的包是上表第三种结构或者你手里是一套还在用老版本 Sealos 的存量脚本那走sealos init是最顺的路。这个命令的特点是把「节点准备 镜像导入 kubeadm 初始化」打包成一个动作参数直接写在命令行上。先做节点侧准备。以三 master 两 node 为例# 控制节点到所有机器的 ssh 免密Sealos 全程靠 ssh 分发文件 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa ssh-copy-id root10.0.0.11 ssh-copy-id root10.0.0.12 ssh-copy-id root10.0.0.13 # 所有节点关闭 swap1.20 的 kubelet 对 swap 零容忍 swapoff -a sed -i /swap/d /etc/fstab # 确认 hostname 唯一且 /etc/hosts 里写清了通信地址 hostnamectl set-hostname master-1然后执行初始化sealos init \ --master 10.0.0.11 --master 10.0.0.12 --master 10.0.0.13 \ --node 10.0.1.11 --node 10.0.1.12 \ --user root \ --passwd 你的密码 \ --version v1.20.12 \ --pkg-url /opt/media/kube1.20.12.tar.gz参数里--pkg-url是核心它告诉 Sealos 本地包在哪--version必须和包内镜像 tag 一致写成1.20.12不带 v 有时候会匹配不上。--passwd会暴露在 shell 历史里建议改用--pk /root/.ssh/id_rsa指定私钥。这里有个容易被忽略的点老版本 Sealos 对节点的操作系统发行版敏感CentOS 7.9 和 Ubuntu 20.04 的初始化脚本分支不一样遇到卡在init cluster步骤时先看/var/log/sealos.log里是哪条 shell 挂了。2.3 新版 Sealos 路径load 进本地 registry 再 run 集群镜像现在更常见的是新版 Sealos 的集群镜像流程文件名虽然还是kube1.20.12.tar.gz但内部是Kubefile registry 目录结构。操作分两步先把 tar 里的镜像和配置注册到 Sealos 自己的本地仓库再执行 run 让 Sealos 去编排节点。# 第一步导入包 sealos load -i /opt/media/kube1.20.12.tar.gz # 确认导入结果正常会看到 kubernetes:v1.20.12 这类条目 sealos imagesload的实质是把包内的集群镜像解到 Sealos 的本地 registry 目录而不是往 docker 或 containerd 里塞镜像。这样做的好处是 Sealos 在后续run时能把镜像推送到它自己启动的集群内仓库各节点从内网 registry 拉取不依赖外网也不依赖每台机器都预装 docker。确认镜像列表里有kubernetes:v1.20.12后再执行sealos run kubernetes:v1.20.12 \ --masters 10.0.0.11,10.0.0.12,10.0.0.13 \ --nodes 10.0.1.11,10.0.1.12 \ --pk /root/.ssh/id_rsa--masters和--nodes后面可以直接跟逗号分隔的 IP 列表不用为每个节点写一遍参数。--pk指定 ssh 私钥路径比--passwd安全。跑完后集群不一定立刻 Ready因为 1.20 这套镜像还要和节点上的容器运行时、CNI 插件配合第三节说的三件事没做好run 成功也会在十分钟后露出问题。3. 1.20.12 的选型暗坑运行时、cgroup 驱动与 IPVS 模块三件事Kubernetes 1.20 是个特殊版本它是最后一个内置 dockershim 的版本线这意味着选 docker 当运行时是「顺路」的不需要像 1.24 之后那样额外装 cri-dockerd。但也正因为老很多配套选择和后来的版本习惯不一样。这一章讲清楚运行时、cgroup 驱动、kube-proxy 模式这三组决定成败的参数。3.1 运行时二选一Docker 是顺路Containerd 是绕路但更省资源如果这个kube1.20.12.tar.gz是按最保守的方式打的里面大概率同时准备好了 docker 和它需要的 pause 镜像。1.20 里选 docker 的显著优势是 kubeadm 不需要手动指定 CRI socketkubelet 直接走内置 dockershim 和 docker 通信。如果包里的镜像列表是基于 containerd 打的那就要在 kubeadm 初始化时显式指定 CRI socket否则 kubelet 找不到运行时节点会一直 NotReady。判断当前节点 kubelet 用的是哪个运行时可以看kubelet --container-runtime --version # 常见输出Kubernetes v1.20.12这个命令只能看到 kubelet 自身的版本运行时信息要看/var/lib/kubelet/kubeadm-flags.env或 kubelet 启动参数。用 containerd 时初始化命令里需要加--cri-socket/run/containerd/containerd.sock用 docker 时不用加kubelet 在 1.20 里默认找/var/run/dockershim.sock。两种运行时在离线场景的核心差异在沙箱镜像配置上containerd 需要显式告诉它 pause 镜像在哪见 3.2 节的配置片段docker 则直接认本地已加载的 pause 镜像。提示1.20 的 kubelet 对 containerd 的版本有下限要求一般来说 containerd 1.4.x 系列是稳妥选择太老的 1.2.x 在--container-runtimeremote模式下会出现failed to get version之类的握手失败。3.2 cgroup 驱动systemd 是 1.20 集群的默认正确解1.20 时代踩得最多的坑就是 cgroup 驱动不一致。系统用 systemd 初始化的节点kubelet 配置里写cgroupDriver: systemd是标准做法但如果节点上 docker 还是默认的cgroupfs两者就会打架kubelet 反复报错起不来报错长这样failed to run Kubelet: misconfiguration: kubelet cgroup driver: systemd is different from docker cgroup driver: cgroupfs解决办法是在 kubeadm 配置里显式声明 kubelet 的 cgroup driver同时在 docker 侧对齐。kubeadm 配置片段kind: KubeletConfiguration apiVersion: kubelet.config.k8s.io/v1beta1 cgroupDriver: systemddocker 侧则要改/etc/docker/daemon.json{ exec-opts: [native.cgroupdriversystemd] }改完重启 docker 再初始化集群或者对已有集群逐台 drain 后重启 kubelet。血泪经验是这条配置必须在集群初始化之前就写好等节点 NotReady 再补虽然能救回来但 kubelet 重启时可能会把已有 Pod 重新调度一遍小集群也够忙活半天。3.3 kube-proxy 模式与 CIDRIPVS 内核模块在 1.20 上的老毛病kube-proxy 默认走 iptables 模式流量规模上来后很多人想切 ipvs但在 1.20 上切换前得先把内核模块装上。缺模块时 kube-proxy 不会直接崩溃而是静默回退 iptables表现是kubectl get svc一切正常但高并发下长连接延迟异常排查起来很隐蔽。先手动加载modprobe br_netfilter modprobe ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh nf_conntrack然后确认lsmod | grep ip_vs再配sysctl让包转发和桥接流量生效echo net.ipv4.ip_forward 1 /etc/sysctl.conf echo net.bridge.bridge-nf-call-iptables 1 /etc/sysctl.conf sysctl -pbridge-nf-call-iptables依赖br_netfilter模块没加载的话这条 sysctl 会报错属于连锁问题。CIDR 部分也要在 init 前想清楚--service-cidr建议保持 1.20 默认的10.96.0.0/12--pod-network-cidr要和后面装的 CNI 默认值一致例如 Flannel 默认10.244.0.0/16Calico 默认192.168.0.0/16。如果节点所在网段正好落在 Pod CIDR 里路由会互相打架症状是跨节点 Pod 通但出网卡这类问题改配置要重来没有后悔药。4. 拆包与重新打包确认 kube1.20.12 里的镜像补全缺失项不是所有拿到的kube1.20.12.tar.gz都是完整的。交付场景里经常发生一种情况包是在一台装了 docker 的机器上临时打的漏掉了 coredns 或 pause等集群初始化时才发现某个镜像拉不到。这一章讲怎么拆包核对、怎么补镜像、怎么重打一个能用的包。4.1 拆包核对一个 tar 里到底该有哪些 1.20.12 的镜像先拆包看内容同时拿 1.20.12 的镜像清单做对照。在没有现成清单的情况下最靠谱的来源是 kubeadm 自己kubeadm config images list --kubernetes-version v1.20.12这个命令会输出该版本 kubeadm 初始化时需要的全部镜像包括版本号精确到补丁的 pause、etcd、coredns。1.20.12 的典型清单里会有k8s.gcr.io/kube-apiserver:v1.20.12 k8s.gcr.io/kube-controller-manager:v1.20.12 k8s.gcr.io/kube-scheduler:v1.20.12 k8s.gcr.io/kube-proxy:v1.20.12 k8s.gcr.io/pause:3.4.1 k8s.gcr.io/etcd:3.4.13-0 k8s.gcr.io/coredns/coredns:v1.7.0拿到这份清单后把它和kube1.20.12.tar.gz里的镜像列表比对。docker save 产物用这个命令看包内镜像tar tzf kube1.20.12.tar.gz | grep manifest.json || true但更方便的是先导入再查docker load -i /opt/media/kube1.20.12.tar.gz docker images | grep -E kube-apiserver|etcd|pause|coredns注意文件名是kube1.20.12.tar.gz这种缩写包内镜像 tag 一般还是完整的v1.20.12格式不要因为文件名没写全就在对照清单时搞混。如果发现缺了 coredns 或 pause这个包不能直接用于离线交付要继续走补镜像流程。4.2 补镜像与重打包用 docker tag 统一仓库名再 save离线环境里补镜像的常见做法是在一台能访问镜像仓库的机器上把缺的镜像拉下来tag 成和包内一致的仓库名再重新打包。因为 1.20 的 kubeadm 默认从k8s.gcr.io拉镜像离线机器上要么把所有镜像 tag 成这个默认仓库名要么在 kubeadm 配置里改imageRepository。我一般选后者因为名前缀统一后续切换内网 registry 更省事。补完镜像后的打包命令长这样IMAGES$(kubeadm config images list --kubernetes-version v1.20.12) for img in $IMAGES; do docker pull $img done docker save $IMAGES | gzip /opt/kube1.20.12-full.tar.gz这段命令先把清单里的镜像全部拉取到本机再一次性 save 并压缩。docker save支持多个镜像作为参数输出会合并成一个 tar 流避免逐个镜像打多个小包。gzip 放在管道末尾是为了能用一条命令搞定但大包压缩时 gzip 会把 CPU 打满翻车点在于如果网速快但 CPU 弱建议分开两段执行先docker save -o /opt/kube1.20.12-full.tar再单独gzip避免管道中断后整包作废。4.3 Sealos 集群镜像的自定义从 tar 到可 run 的集群镜像如果你手里的kube1.20.12.tar.gz是 Sealos 集群镜像格式但想往里面加自己的 CNI 插件或仓库组件不需要手动重新打 docker tar。Sealos 提供了基于 Kubefile 的重新构建方式常见做法是这样FROM kubernetes:v1.20.12 COPY calico.yaml /opt/calico.yaml然后在同目录执行sealos build -t my-k8s:v1.20.12 .命令会基于已有集群镜像再生成一个新 tag 的镜像里面包含了额外文件。这个方式比拆开 tar 塞文件可靠因为 Sealos 会重新生成 registry 索引而不是硬拼目录。对新接触 Sealos 的人来说不建议直接手工改 tar 内的 registry 目录索引不一致会导致sealos load完成后sealos images看不到任何条目。5. 部署 kube1.20.12 的避坑清单五处让集群翻车的点这一章是踩坑记录。1.20.12 不是新版本网上方案很多但恰恰因为老它的默认行为和 1.24、1.26 差异很大。五条里每一条都按「现象 → 原因 → 解决」写照着排查能少走至少一个晚上的弯路。5.1 证书与 Token装完没事、后来出事的两个坑现象一控制平面初始化成功三天后往集群加新节点执行kubeadm join报 token 过期错误信息里明确写着token expired。原因1.20 的 kubeadm 默认生成的 bootstrap token 有效期为 24 小时离线交付或跨天加节点时必踩。解决在控制平面重新生成一个不过期的 tokenkubeadm token create --ttl 0 --print-join-command--ttl 0表示永不过期--print-join-command会直接输出完整的 join 命令包括--discovery-token-ca-cert-hash省得再手动去算 CA 指纹。现象二集群跑了大半年某天凌晨 kube-apiserver 和 etcd 同时进入 CrashLoopBackOffkubectl也连不上检查发现 apiserver 证书已过期。原因1.20 的 kubeadm 签发的控制平面证书默认有效期只有一年证书到期后 apiserver 直接拒绝提供接口服务。解决先续期再重启kubeadm alpha certs renew all systemctl restart kubelet续期后还要记得更新kubeconfig否则kubectl拿的还是旧证书。注意kubeadm alpha certs renew在 1.20 里是 alpha 命令路径在后续版本里改过但 1.20.12 用这个命令没问题。这类集群建议把证书到期时间写进监控不然后果是凌晨被叫起来。5.2 运行时与沙箱镜像kubelet 起不来的两个镜像层问题现象一kubectl get nodes能看到 master 节点但状态一直是 NotReadyjournalctl -u kubelet里刷Container runtime is down。原因kubelet 和容器运行时之间握手失败最常见是 CRI socket 路径对不上。用 docker 时 kubelet 走 dockershim用 containerd 时必须在初始化阶段指定--cri-socket漏了这条 kubelet 会一直去连默认路径连不上就判定运行时 down。解决如果是 containerd编辑 kubelet 启动参数里的--container-runtimeremote --container-runtime-endpointunix:///run/containerd/containerd.sock重启 kubelet。如果是 docker确认 docker 服务在运行且/var/run/docker.sock存在。现象二Pod 能创建但卡在SandBox阶段事件里反复报ImagePullBackOff拉取的镜像名是k8s.gcr.io/pause:3.4.1而本地明明已经 load 过 pause 镜像。原因1.20 的 kubelet 和 containerd 各自维护一份沙箱镜像配置。docker 直接复用本地镜像containerd 则必须通过sandbox_image字段告诉它 pause 镜像的完整名字。本地仓库名和默认仓库名不一致时containerd 仍然去k8s.gcr.io拉。解决把本地 pause 镜像补一个 tagdocker tag pause:3.4.1 k8s.gcr.io/pause:3.4.1或修改 containerd 配置里的sandbox_image指向本地仓库地址然后重启 containerd。tag 的具体版本以kubeadm config images list --kubernetes-version v1.20.12输出的实际值为准不同补丁版本可能差个 patch 号。5.3 网络多网卡和内核模块把集群拖进半死状态现象一节点注册成功但kubectl get nodes -o wide看到的 InternalIP 是个网桥地址或虚拟网卡地址而不是内网通信地址apiserver 和 kubelet 之间互相访问不稳定。原因多网卡服务器上 kubelet 自动选择第一个网卡作为 node IP1.20 没有可靠的自动识别机制。解决显式指定 kubelet 的 node IP在/etc/sysconfig/kubelet里加KUBELET_EXTRA_ARGS--node-ip10.0.0.11重启 kubelet 后确认 node 的 InternalIP 已更新。这个配置要在 join 或 init 之前加否则节点 IP 变更后 kubelet 证书里的 IP 对不上要额外删节点重来。现象二集群跑着跑着跨节点 Pod 的 Service 访问时通时不通kube-proxy日志里出现cant determine whether ipvs rules are in place。原因节点上ip_vs内核模块没加载kube-proxy 虽然能切到 ipvs 模式但规则写不进去行为表现为时通时不通玄学一样的间歇性故障。解决回到 3.3 节的modprobe命令把ip_vs相关模块全部加载并按需写入/etc/modules-load.d/kube-proxy.conf保证开机自加载。这个坑在云主机上尤其常见因为云内核裁剪版经常默认不带这些模块。6. 怎么验证这个包真装对了三处信号与一个升级前的小习惯集群装完不是看sealos run退出 0 就收工。我自己的验收顺序是先看版本再看组件最后一台节点抽查日志。6.1 装完后的四个验证信号验证项命令期望结果集群版本kubectl get node -o wideVERSION 列为 v1.20.12控制面镜像kubectl get pods -n kube-systemkube-apiserver、etcd、coredns 全 Running集群配置来源kubectl -n kube-system get cm kubeadm-config -o yaml | grep kubernetesVersion输出 kubernetesVersion: v1.20.12kubelet 版本kubelet --versionKubernetes v1.20.12kubeadm-config这个 ConfigMap 是 kubeadm 初始化时写进去的原始配置里面记录了实际使用的版本和初始化参数。如果它是空的或者版本号不对说明集群不是这个包初始化的属于 preflight 检查时必须怀疑的对象。coredns 是 1.20 上最容易 CrashLoopBackOff 的组件它要是起不来多半是CoreDNS镜像版本和包内不一致先看kubectl logs -n kube-system -l k8s-appkube-dns再下结论。6.2 补丁升级前的小习惯sealos 包和 kubeadm 版本要对照v1.20.12表示这是 1.20 系列的第十二个补丁版本。如果后续要升到v1.20.13或更高的 1.20 补丁别直接用kubeadm upgrade绕过 Sealos否则 Sealos 下次 run 时会拿本地 registry 的旧镜像把版本又顶回去。我自己的习惯是用一个 tar 包部署完集群后立刻把包的 SHA256 记录下来写入集群的一个 annotation 或部署文档里这样半年后再看这个集群时能确切知道它当初是基于哪个介质装的。升级时先sealos load新包再按当前 Sealos 版本的升级命令执行不要混用新旧命令路径。希望这个流程能帮你把 1.20 的离线交付从「看运气」变成「可复现」下次再看到kube1.20.12.tar.gz这个文件名时至少心里清楚包里该有什么、不该缺什么、坏了从哪查起。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →