
简介K8s 1.18.8 离线安装部署资源包面向需要在内网或受限网络环境快速搭建容器集群的运维与开发人员。压缩包共21个文件以脚本、配置清单、服务单元为核心同时包含集群核心组件、容器镜像离线包及多种辅助工具整体约610MB可满足离线交付需求。当前已有289人学习下载。资源预置了完整的部署材料初始化和主节点配置脚本负责环境预检、控制面初始化与容器运行时适配集群初始化配置和网络插件清单可一键落地基础服务与网络方案镜像压缩包便于批量导入私有仓库另有服务管理配置、连接跟踪、容器命令行等工具帮助在无外网条件下完成高可用集群搭建和故障排查。借助该资源包能大幅缩短集群环境准备时间适合离线实施、教学实训与内部交付场景。1. 拿到 kube1.18.8.tar.gz 之后面前是一个离线交付包不是压缩文件离线机房、内外网隔离的测试区、还要过等保的政务网在这些地方装 Kubernetes 1.18.8网络是天然敌人。你从同事移动硬盘里拷来一个 kube1.18.8.tar.gz解压之后发现里面有二进制、镜像、一堆 yaml。这个包确实能解出来但真正的问题是依赖镜像怎么进集群、私有仓库怎么接以及为什么所有节点上的 kubelet 还是会报 6443 连不上。这篇文章就把这个 tar.gz 从校验、拆包、推私有仓库到离线拉起集群的完整链路讲清楚适合正在做内网交付或镜像站下载后自己维护的工程师。你手里的不是安装包是一套需要自己补完的交付物。2. 先拆包再谈部署校验、解压、二进制落位一次做对2.1 用 SHA256 校验“半路货”离线包最容易翻车的地方是拷一半断了或者对方给你的包本身就不是完整构建。kube1.18.8.tar.gz 这样的包常见做法是从中科大开源镜像站或者阿里云镜像站下载原始文件站点页面一般会列 sha256。下载后先校验再用 tar 解压不要跳过这一步不然后面所有报错都是黑匣子理不清源头。# 先拿到发布方给的 sha256 值比如 4d7029454e2f9c20a12d3b5c8c9ffb7d1eba2d0e2f46e5f2d4d6d8b1a3c9e0a1 echo 4d7029454e2f9c20a12d3b5c8c9ffb7d1eba2d0e2f46e5f2d4d6d8b1a3c9e0a1 kube1.18.8.tar.gz | sha256sum -c - # 输出 kube1.18.8.tar.gz: OK 则说明文件完整可以继续这条命令把期望的哈希值和文件名一起喂给 sha256sum-c表示核对模式。如果输出不是 OK别解压直接回去找包。常见做法是先在镜像站页面把哈希复制到一个文本再执行校验避免手敲漏字符。校验通过后解压不要用 Windows 里的压缩工具解Linux 上用 tar 是最稳的。tar -xzf kube1.18.8.tar.gz # 假设包内是一个 kubernetes/ 或 release/ 目录结构 ls -l解压之后如果看到 bin/ 目录里面有 kubeadm、kubelet、kubectl、kube-apiserver 等二进制说明是标准的服务器包结构。有些发行版会把镜像打成单独的 tar解压后看不到 bin/那就要先做一次 docker load 再看目录。2.2 先看目录结构再决定部署方式我一般会先把解压后的目录整体看一遍确认包里有 Kubernetes 1.18.8 的 server 二进制和配套镜像清单。1.18.8 是 2020 年 9 月左右的版本镜像仓库默认值是 k8s.gcr.io镜像清单里应该有 pause、etcd、coredns、kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy 这七类。离线环境里这个默认仓库地址必须改否则所有节点都会卡在拉镜像这一步。find . -maxdepth 3 -type f \( -name *.tar -o -name *.yaml -o -name *.conf \) | sort # 这一步是为了确认包里有哪些类型的交付物决定后续是走 docker load 还是 direct ctr import如果看到 images/ 目录下有一堆 tar 文件那就走先 load 再 tag 再 push 的链路。如果包内只有二进制和 yaml没有镜像 tar你后面就必须单独准备离线镜像或者在内网另外搭一个 registry并保证网络能访问到。2.3 把二进制放到系统路径顺手解决 PATH 问题解压出来的二进制默认没有权限也未必在 PATH 里。我一般会把它们统一放到 /usr/local/bin然后把 systemd unit 文件也准备好方便后面用 kubeadm init 时直接调用。mkdir -p /opt/kubernetes-1.18.8/bin cp -r kubernetes/server/bin/* /opt/kubernetes-1.18.8/bin/ chmod x /opt/kubernetes-1.18.8/bin/* ln -sf /opt/kubernetes-1.18.8/bin/kubeadm /usr/local/bin/kubeadm ln -sf /opt/kubernetes-1.18.8/bin/kubelet /usr/local/bin/kubelet ln -sf /opt/kubernetes-1.18.8/bin/kubectl /usr/local/bin/kubectl这里把二进制从 tar 包里落位到统一目录然后做软链。软链的好处是以后换版本可以只改 /opt/ 下的目录不影响 systemd 脚本。1.18.8 的 kubeadm 默认对 Docker 的适配比较完整但对 containerd 还需要手工指定 cri-socket这一步后面会专门讲。如果你要在麒麟 v10 这类系统上装先确认系统自带 glibc 版本tar.gz 里的二进制是动态编译的glibc 太老会出现 command not found 或者段错误。3. 把下载好的 tar.gz 推到私有仓库这条链路不只 kubekey 在用3.1 为什么问“怎么推私有仓库”的人最多实际部署时master 和 node 都在内网几乎所有机器都没有外网访问权限。你在镜像站下载 tar.gz 后第一件事就是把镜像导入到内网私有仓库比如 registry:5000。很多帖子会提到 kubekey但 kubekey 本身是 KubeSphere 的安装工具不是专门处理任意 tar.gz 镜像推送的。常见的做法是手工完成一条链docker load、docker tag、docker push或者用 skopeo 在不依赖 docker daemon 的情况下把镜像直接 copy 到 registry。下面我分别给出两条路线。3.2 路线一先本地 load再打标推送到私有仓库如果 kube1.18.8.tar.gz 里带了镜像 tar第一件事是先把镜像导入本机 Docker。注意导入的镜像是仓库名标签的形式比如 k8s.gcr.io/kube-apiserver:v1.18.8需要改成内网 registry 的地址再推送。# 把 tar.gz 里的镜像文件导入本地 docker docker load -i kube-apiserver.tar docker load -i kube-controller-manager.tar # 对所有需要推送到内网的镜像执行打标签 docker tag k8s.gcr.io/kube-apiserver:v1.18.8 registry.internal:5000/kube-apiserver:v1.18.8 docker push registry.internal:5000/kube-apiserver:v1.18.8这段命令的作用是把本地镜像库里的原始镜像重新命名为内网 registry 地址然后再推送。打标签必须注意三层结构私有仓库路径一般写成 registry地址/项目名/镜像名:版本号。很多人栽在漏掉版本号或多了一个斜杠push 时报 manifest invalid。如果镜像文件较多建议写一个循环for img in $(docker images --format {{.Repository}}:{{.Tag}} | grep k8s.gcr.io); do newimgregistry.internal:5000/${img#k8s.gcr.io/} docker tag $img $newimg docker push $newimg done这里的参数替换${img#k8s.gcr.io/}是把镜像名里开头的 k8s.gcr.io/ 去掉再拼上私有仓库前缀。注意 grep 的写法要按你实际 load 进来的镜像列表来过滤不能凭空硬编。执行完后去 registry 的 web 页面或者用 curl 看一下 v2/_catalog确认镜像已经在仓库里。3.3 路线二不想碰 docker daemon 就用 skopeo有些离线环境没有 Docker或者 daemon 起不来这时候 skopeo 就派上用场了。skopeo 可以从本地 tar 直接 copy 到 registry不需要经过 docker load/tag。# 把 tar 包里的镜像直接推送到 registry skopeo copy docker-archive:./kube-apiserver.tar docker://registry.internal:5000/kube-apiserver:v1.18.8这条命令里docker-archive:指本地 tar 包docker://指目标 registry。skopeo 的好处是它直接操作镜像层不占用本地 docker 存储空间。缺点是你得先确认 tar 包里到底包含哪些镜像不能批量处理的时候盲目猜测。常见做法是解包后先看 manifest再用 skopeo 逐一把镜像 copy 过去。3.4 推送私有仓库后必须验证一件事推完镜像后第一时间做一次拉取测试从一台没有本地镜像缓存的机器上docker pull registry.internal:5000/kube-apiserver:v1.18.8。如果拉不下来检查 registry 证书和 HTTP 配置。很多团队用 HTTP 私有仓库kubelet 默认不允许非 TLS 仓库需要给所有节点配 containerd 或 Docker 的 insecure-registries。这个不提前做好后面 kubeadm init 会一直报拉镜像失败而且日志里只显示 context deadline exceeded特别像网络不通。# 拉取测试确保私有仓库可以被集群内节点访问 curl -X GET http://registry.internal:5000/v2/_catalog # 如果返回的 JSON 里能看到 kube-apiserver 等镜像名说明仓库侧正常这一步是玄学集中地。很多人在内网装 registry 后本机能 curl 通但到 kubelet 那边就超时原因是节点上的 Docker 没有配置 insecure-registries或者 containerd 的 config.toml 里没有加 registry 配置。后面第 5 章会专门展开排错。4. 用离线包拉起 1.18.8 集群容器运行时、kubeadm 配置与镜像仓库接线4.1 先确认你准备用什么容器运行时kubeadm 1.18.8 默认优先找 Docker如果你只用 containerd必须在 init 时指定--cri-socket否则它找不到运行时直接退出。我一般建议离线环境统一用 containerd因为它在内网更可控不依赖 docker daemon 的额外维护成本。但用的 containerd 版本不能太新太新的 cri 插件路径变了kubelet 1.18.8 认不出。稳妥做法是先用一台上网机器下载好的 tar.gz 里自带的镜像在内网机器上先部署 containerd确认/run/containerd/containerd.sock存在再继续。# 启动 containerd 并确认 socket 存在 systemctl enable --now containerd ls -l /run/containerd/containerd.sock如果 socket 路径不存在常见原因有两个containerd 没启动成功或者配置里的 cri 插件被注释掉了。去/etc/containerd/config.toml看disabled_plugins [cri]是不是被打开了1.18.8 要求 cri 插件必须启用。这个坑能卡住很多人因为 containerd 本身起来了也能拉镜像但 kubeadm 就是探测不到 runtime。4.2 写 kubeadm 配置文件并修正 imageRepositorykubeadm 默认从 k8s.gcr.io 拉镜像离线环境必须改成内网私有仓库。在镜像推送做完后我一般会生成一份 kubeadm.yaml把 imageRepository 指到 registry.internal:5000。注意 1.18.8 版本里kubeadm 的 imageRepository 只支持一个前缀地址不支持像新版那样写多级仓库路径所以你的私有仓库地址后面不要带子路径除非你把镜像 tag 按子路径重推了一份。# kubeadm-config.yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration kubernetesVersion: v1.18.8 imageRepository: registry.internal:5000 controlPlaneEndpoint: 192.168.10.10:6443 networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 --- apiVersion: kubeadm.k8s.io/v1beta2 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.10.10 bindPort: 6443 nodeRegistration: criSocket: /run/containerd/containerd.sock这段 yaml 是 kubeadm 1.18.8 的标准配置。imageRepository 指到私有仓库后kubeadm 会拉取registry.internal:5000/kube-apiserver:v1.18.8这样的镜像。controlPlaneEndpoint 写成集群 VIP 或者 master 实际 IP如果只有一个 master直接写 master IP。podSubnet 的 10.244.0.0/16 是 Flannel 默认网段你可以根据自己的 CNI 选型改但改了之后 CNI 配置要和它一致。4.3 执行初始化kubeadm init 前的两个检查在 init 之前先做一次kubeadm config images list --config kubeadm-config.yaml确认 kubeadm 会从私有仓库拉哪些镜像。这一步很重要能提前发现仓库地址拼写错误或者镜像缺失比直接 init 省时间。如果镜像列表里出现的是registry.internal:5000/kube-apiserver:v1.18.8说明--config生效了。# 预检查镜像列表 kubeadm config images list --config kubeadm-config.yaml # 直接初始化控制面 kubeadm init --config kubeadm-config.yaml --upload-certs | tee kubeadm-init.log--upload-certs会把证书上传到集群 secret 里方便后续 join 时不用手动拷贝证书但 1.18.8 会要求在 join 命令里显式带上--certificate-key。别把这条信息弄丢kubeadm-init.log里会输出完整的 join 命令。如果 init 失败先看日志里的 error 关键词不要反复 init因为第一次失败留下的 etcd 数据会干扰后续操作。处理办法是kubeadm reset -f后清理/var/lib/etcd再重新 init。4.4 工作节点加入集群join 命令的完整链工作节点上需要先装好 kubelet、kubeadm、kubectl 三个二进制还要让 kubelet 知道使用哪个 CRI。只把二进制放上去不够kubelet 的 systemd unit 和配置文件必须就位。我一般会在工作节点上同样解压 tar.gz然后把二进制复制到 /usr/local/bin再把 kubelet 服务设置为开机自启。# 仅在工作节点执行拷贝二进制并启用 kubelet cp /opt/kubernetes-1.18.8/bin/kubelet /usr/local/bin/ cp /opt/kubernetes-1.18.8/bin/kubeadm /usr/local/bin/ systemctl enable --now kubeletkubelet 启动后不一定能立刻选到 CRI需要你手动写/etc/default/kubelet加上KUBELET_EXTRA_ARGS--cri-socket/run/containerd/containerd.sock。然后在 master 上拿到的 kubeadm join 命令把 token 和 hash 填进去在节点上执行。如果 join 时报 6443 refused别急着怀疑防火墙先回想一下 controlPlaneEndpoint 对不对、负载均衡有没有建、证书 key 有没有带全。# 工作节点上执行 join kubeadm join 192.168.10.10:6443 --token xxxx \ --discovery-token-ca-cert-hash sha256:yyyy \ --cri-socket /run/containerd/containerd.sockjoin 之后至少等 30 秒再查节点状态因为镜像拉取和组件启动都需要时间。kubectl get nodes如果看到工作节点是 NotReady下一步看kubectl describe node和journalctl -u kubelet这两个是排查的关键入口。5. 离线部署 1.18.8 的五个高频翻车点现象、原因、解决5.1 校验失败明明包能打开sha256 却对不上现象sha256sum -c报 FAILED但解压和复制都正常。原因对方把打包和哈希打包成了两个不同文件或者 tar.gz 是从网盘下载后被网盘自动改过格式。解决用镜像站原始文件重新下载或者在目标机器上用head -c 1024 kube1.18.8.tar.gz | hexdump和源站对比魔数。记住哈希对不上就不要用尤其是要推到生产集群的包血泪经验告诉你这种包大概率在某个镜像上缺层。5.2 docker load 成功但 kubelet 仍然找不到镜像现象docker images能看到registry.internal:5000/kube-apiserver:v1.18.8但kubeadm init一直报Failed to pull image。原因如果你用的是 containerd而不是 Docker那 docker load 进去的镜像完全不会被 containerd 看到两个运行时各有各的存储。解决要么统一用 Docker要么改用 containerd 的ctr -nk8s.io images import导镜像。注意命名空间必须是k8s.io否则 kubelet 还是无法识别。# 用 containerd 导入镜像注意必须带命名空间 ctr -nk8s.io images import ./kube-apiserver.tar ctr -nk8s.io images list | grep kube-apiserver如果你之前用 docker load 导过之后换了 containerd那这些镜像相当于没有进入集群的视角。解决方法是把打包好的镜像 tar 重新用ctr -nk8s.io导入然后 restart kubelet。不要再相信 docker load 在当前场景里有用这是 1.18.8 时代最常见的黑匣子之一。5.3 kubeadm init 报 etcd 端口被占用现象第一遍 init 失败后清理不彻底第二遍直接报listen tcp :2379: bind: address already in use。原因etcd 容器删了但宿主机端口没释放或者之前的静态 pod 还在。解决执行kubeadm reset -f然后检查 2379 和 2380 端口占用必要时kill -9遗留进程。还要清理/var/lib/etcd、/etc/kubernetes、~/.kube确保环境干净再重新 init。1.18.8 不像新版有--force重置你得手动清干净。5.4 join 时报 6443 refused但防火墙没开现象节点 join 时输出couldnt find a server或 dial tcp 超时。原因kube-apiserver 的静态 pod 没起来或者 controlPlaneEndpoint 填的是不可达 IP。解决在 master 上先kubectl get pods -n kube-system | grep kube-apiserver如果是 ContainerCreating用kubectl logs -n kube-system kube-apiserver-hostname看具体错误。很多情况下是 apiserver 的镜像 tag 在私有仓库里名字不对导致拉取失败。还有一种情况是 join 时用 6443但 master 上 port 没监听netstat -lnp | grep 6443看一次就知道。5.5 麒麟 v10 等国产化系统上依赖缺失现象二进制解压后执行kubeadm version报error while loading shared libraries: libc.so.6或者段错误。原因tar.gz 里的二进制是在较新的 glibc 环境编译的老系统 glibc 版本低于它需要的版本。解决用ldd /usr/local/bin/kubeadm查看动态库依赖如果系统 glibc 过低需要单独使用官方发布的针对该系统的二进制包或者用容器方式运行 kubelet。这是 tar.gz 安装模式在麒麟这类系统上绕不过去的坎别硬扛编译参数先确认你是在同版本或兼容系统上解包的。如果只是缺 libcrypto 或 libssl可以尝试复制同版本库文件到 /usr/lib64但要看清楚软链。6. 部署完先别走节点健康检查、插件补齐与版本固化集群起来后先验证kubectl get nodes全部 Ready再检查核心插件。1.18.8 的 kubeadm init 只帮你把控制面组件部署完不会自动装 CNI 插件、metrics-server、dashboard。没有 CNI所有节点会一直 NotReady没有 metrics-serverkubectl top用不了所以离线包之外还要准备这几个插件的镜像和 yaml。常见做法是手里同时备好 Flannel/Calico 的 tar 包在同一套私有仓库里推进去。# 查看集群工作节点、deployment 和容器组运行状况 kubectl get nodes -o wide kubectl get pod -A -o wide # 如果 Flannel 镜像在私有仓库直接应用其 yaml kubectl apply -f kube-flannel.yml应用完 CNI 后等一到两分钟所有节点 Ready 才算真正成功。最后把你用的 kubeadm-config.yaml、镜像清单、版本号和私有仓库地址写到一个 README 里放到 /opt/kubernetes-1.18.8/ 下作为这次交付的基线。后续如果要做升级至少还有版本对应关系可查。我见过太多团队半年后回来看部署文档发现仓库地址已经换了、镜像 tag 也更新了后悔药都没得吃。希望帮到你动手的时候先把上面第 3 章和第 5 章过一遍能省下不少试错时间。本文还有配套的精品资源点击获取