K8S离线部署:从零准备二进制文件与容器镜像
1. 为什么需要K8S离线部署方案
在企业生产环境中,我们经常会遇到服务器无法直接访问外网的情况。可能是出于安全考虑,也可能是特殊行业监管要求,总之这种"网络隔离"的环境给K8S部署带来了巨大挑战。我去年就遇到过这样一个项目:某金融机构的数据中心要求所有服务器必须在内网运行,连yum、apt这些基础包管理器都无法直接使用。
这种情况下,传统的在线安装方式完全行不通。你既不能直接kubeadm init,也没法用docker pull获取镜像。更麻烦的是,K8S的组件依赖关系复杂,光核心组件就有十几个二进制文件和容器镜像,还有各种网络插件、监控工具等附加组件。如果手动一个个准备,不仅容易遗漏,版本兼容性也是个大问题。
离线部署的核心思路很简单:先在能上网的机器上把所有需要的文件下载好,然后打包转移到目标环境。但实际操作中你会发现很多坑:比如官方镜像仓库在国内访问缓慢、不同版本组件存在兼容性问题、二进制文件需要对应操作系统架构等。我在第一次做离线部署时,就曾因为漏掉etcd镜像导致整个集群初始化失败。
2. 准备K8S二进制文件
2.1 确定版本和系统架构
开始下载前,首先要明确三个关键信息:
- K8S版本(如v1.28.2)
- 操作系统类型(Linux/Windows)
- CPU架构(amd64/arm64等)
这非常重要,因为下载错误的版本会导致后续安装失败。我建议使用以下命令检查系统架构:
# 查看Linux系统架构 uname -m # 如果是x86_64就是amd64,aarch64就是arm64 # 查看系统版本 cat /etc/os-release2.2 从官方渠道下载组件
K8S所有官方发布的二进制文件都可以在下面这个地址找到:
https://dl.k8s.io/release/假设我们要下载v1.28.2版本的amd64架构Linux二进制文件,主要需要以下组件:
- kubeadm
- kubectl
- kubelet
- kube-apiserver
- kube-controller-manager
- kube-proxy
- kube-scheduler
这里有个小技巧:可以用curl批量下载所有组件:
VERSION=v1.28.2 ARCH=amd64 for COMPONENT in kubeadm kubectl kubelet kube-apiserver kube-controller-manager kube-proxy kube-scheduler; do curl -LO "https://dl.k8s.io/release/$VERSION/bin/linux/$ARCH/$COMPONENT" chmod +x "$COMPONENT" done下载完成后,建议用sha256sum校验文件完整性:
curl -LO "https://dl.k8s.io/release/$VERSION/bin/linux/$ARCH/sha256sum.txt" sha256sum --check sha256sum.txt3. 准备容器镜像
3.1 核心组件镜像
K8S的核心组件都以容器镜像方式发布在registry.k8s.io仓库。使用以下命令可以查看kubeadm需要的所有镜像:
kubeadm config images list --kubernetes-version v1.28.2输出类似这样:
registry.k8s.io/kube-apiserver:v1.28.2 registry.k8s.io/kube-controller-manager:v1.28.2 registry.k8s.io/kube-scheduler:v1.28.2 registry.k8s.io/kube-proxy:v1.28.2 registry.k8s.io/pause:3.9 registry.k8s.io/etcd:3.5.9-0 registry.k8s.io/coredns/coredns:v1.10.13.2 使用国内镜像源加速
直接拉取registry.k8s.io的镜像在国内可能非常慢。我们可以使用国内镜像源如南京大学的镜像站:
# 先拉取国内镜像 docker pull k8s.mirror.nju.edu.cn/kube-apiserver-amd64:v1.28.2 # 然后重命名为官方镜像名称 docker tag k8s.mirror.nju.edu.cn/kube-apiserver-amd64:v1.28.2 registry.k8s.io/kube-apiserver:v1.28.2我写了个脚本可以批量处理所有核心镜像:
#!/bin/bash VERSION=v1.28.2 for IMAGE in kube-apiserver kube-controller-manager kube-scheduler kube-proxy; do docker pull k8s.mirror.nju.edu.cn/${IMAGE}-amd64:$VERSION docker tag k8s.mirror.nju.edu.cn/${IMAGE}-amd64:$VERSION registry.k8s.io/${IMAGE}:$VERSION done # 特殊处理coredns、pause和etcd docker pull k8s.mirror.nju.edu.cn/coredns/coredns:v1.10.1 docker tag k8s.mirror.nju.edu.cn/coredns/coredns:v1.10.1 registry.k8s.io/coredns/coredns:v1.10.1 docker pull k8s.mirror.nju.edu.cn/pause:3.9 docker tag k8s.mirror.nju.edu.cn/pause:3.9 registry.k8s.io/pause:3.9 docker pull k8s.mirror.nju.edu.cn/etcd:3.5.9-0 docker tag k8s.mirror.nju.edu.cn/etcd:3.5.9-0 registry.k8s.io/etcd:3.5.9-03.3 打包镜像为离线文件
镜像拉取完成后,需要导出为tar文件方便传输:
docker save -o k8s-images.tar \ registry.k8s.io/kube-apiserver:v1.28.2 \ registry.k8s.io/kube-controller-manager:v1.28.2 \ registry.k8s.io/kube-scheduler:v1.28.2 \ registry.k8s.io/kube-proxy:v1.28.2 \ registry.k8s.io/pause:3.9 \ registry.k8s.io/etcd:3.5.9-0 \ registry.k8s.io/coredns/coredns:v1.10.14. 准备网络插件和Dashboard
4.1 Flannel网络插件
在离线环境部署Flannel需要准备:
- 部署配置文件
- Flannel镜像文件
先下载kube-flannel.yml:
curl -LO https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml然后下载Flannel镜像:
docker pull ghcr.io/flannel-io/flannel:v0.22.3 docker save -o flannel.tar ghcr.io/flannel-io/flannel:v0.22.34.2 Dashboard管理界面
Dashboard需要两个组件:
- dashboard主镜像
- metrics-scraper
下载命令:
# 下载配置文件 curl -LO https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml # 下载镜像 docker pull kubernetesui/dashboard:v2.7.0 docker pull kubernetesui/metrics-scraper:v1.0.8 # 打包 docker save -o dashboard.tar \ kubernetesui/dashboard:v2.7.0 \ kubernetesui/metrics-scraper:v1.0.85. 制作完整的离线安装包
5.1 目录结构规划
我建议按以下结构组织文件:
k8s-offline-v1.28.2/ ├── binaries/ # 二进制文件 │ ├── kubeadm │ ├── kubectl │ ├── kubelet │ └── ... ├── images/ # 镜像文件 │ ├── k8s-images.tar │ ├── flannel.tar │ └── dashboard.tar ├── manifests/ # 配置文件 │ ├── kube-flannel.yml │ └── recommended.yaml └── install.sh # 安装脚本5.2 编写安装脚本
install.sh应该包含以下步骤:
- 拷贝二进制文件到/usr/bin
- 加载所有容器镜像
- 部署网络插件
- 初始化集群
示例片段:
#!/bin/bash # 安装二进制文件 cp binaries/* /usr/bin/ # 加载镜像 docker load -i images/k8s-images.tar docker load -i images/flannel.tar docker load -i images/dashboard.tar # 初始化集群 kubeadm init --pod-network-cidr=10.244.0.0/16 # 部署Flannel kubectl apply -f manifests/kube-flannel.yml5.3 验证离线包完整性
最后一步是验证,我通常会:
- 准备一个干净的虚拟机
- 只安装docker和基础依赖
- 执行install.sh
- 检查所有pod是否正常运行
关键检查命令:
kubectl get pods -A kubectl get nodes kubectl cluster-info6. 常见问题与解决方案
在实际操作中,我遇到过不少问题,这里分享几个典型案例:
问题1:镜像版本不匹配症状:kubeadm初始化时报错"unable to get image" 解决:确保kubeadm版本与镜像版本完全一致,可以用kubeadm version和kubeadm config images list核对。
问题2:二进制文件权限问题症状:执行kubelet时报权限错误 解决:记得给所有二进制文件添加可执行权限:
chmod +x kube*问题3:节点无法加入集群症状:worker节点执行kubeadm join失败 解决:检查以下两点:
- 主控节点初始化时生成的token是否有效(默认24小时过期)
- 所有节点的系统时间是否同步
问题4:Flannel网络不通症状:pod间无法ping通 解决:检查两点:
kubeadm init时是否指定了正确的--pod-network-cidr- 节点的防火墙是否放行了Flannel使用的端口(默认8472/udp)
7. 进阶技巧与优化建议
经过多次实践,我总结出一些提升效率的技巧:
使用离线包管理工具可以考虑使用kubespray或sealos这类工具,它们内置了离线部署方案,能自动处理依赖关系。
镜像分层打包如果经常需要更新部分镜像,可以把基础镜像和应用镜像分开打包,比如:
- base-images.tar:包含pause、etcd等基础镜像
- app-images.tar:包含业务相关镜像
版本兼容性检查K8S组件版本必须严格匹配,我推荐使用这个兼容性矩阵: https://kubernetes.io/releases/version-skew-policy/
制作自动化构建流水线对于需要频繁制作离线包的情况,可以搭建一个Jenkins流水线,自动完成:
- 下载指定版本二进制文件
- 拉取对应镜像
- 运行基础测试
- 打包生成离线安装包
内网搭建镜像仓库对于大型环境,建议在内网搭建Harbor等私有镜像仓库,这样:
- 只需一次性导入官方镜像
- 所有节点都从内网仓库拉取
- 方便统一管理镜像版本
