Appearance
CentOS 7 Kubernetes v1.31.2 离线部署包制作完全指南:从在线环境导出到离线服务器复现

写在前面
很多生产环境是无法连接互联网的——政府内网、金融专网、军工涉密网、企业私有云……在这些场景下,你无法直接从 Docker Hub 或 Google 仓库拉取镜像,也无法通过 yum 在线安装软件包。
唯一的办法就是:在能联网的环境下,把所有东西提前准备好,打包成离线安装包,再拷贝进去。
本文基于上一篇《CentOS 7 手动安装 Kubernetes v1.31.2 完全指南》已经成功运行的集群,完整记录从在线环境导出所有资源,到离线服务器上完成部署的全过程。
免责声明
本文中使用的镜像加速地址(如 https://docker.1ms.run、https://docker.m.daocloud.io)均为公开的镜像代理服务,不保证长期可用性。
建议你在阅读本文时,先验证一下这些地址是否仍然有效。如果失效,请自行替换为可用的镜像加速地址。懂的都懂~ 😉
环境信息
| 项目 | 配置 |
|---|---|
| 源服务器 | CentOS 7.9 (内核 3.10.0-1160.el7.x86_64) |
| Kubernetes 版本 | v1.31.2 |
| 容器运行时 | containerd v1.6.39 |
| 网络插件 | Calico v3.25.0 |
| 目标服务器 | 相同配置的 CentOS 7.9(无互联网访问) |
一、离线包内容规划
一个完整的 Kubernetes 离线部署包需要包含以下内容:
| 组件 | 说明 | 获取方式 |
|---|---|---|
| 容器镜像 | K8s 核心组件 + Calico + Dashboard | ctr/nerdctl 导出 |
| RPM 包 | kubeadm/kubelet/kubectl + 依赖 | yumdownloader 下载 |
| 二进制文件 | containerd, runc, nerdctl | 从 /usr/local/bin/ 复制 |
| 配置文件 | containerd config, crictl.yaml | 从源服务器复制 |
| 部署脚本 | 一键安装脚本 | 手动编写 |
二、准备工作
2.1 确认源服务器状态
在开始导出之前,确保源服务器上的 Kubernetes 集群运行正常:
bash
kubectl get nodes
kubectl get pods -n kube-system2.2 确认镜像列表
bash
# 查看当前所有镜像
crictl images预期输出类似:
IMAGE TAG IMAGE ID SIZE
docker.io/kubernetesui/dashboard v2.7.0 07655ddf2eebe 75.8MB
docker.io/kubernetesui/metrics-scraper v1.0.8 115053965e86b 19.7MB
docker.m.daocloud.io/calico/cni v3.25.0 d70a5947d57e5 88MB
docker.m.daocloud.io/calico/kube-controllers v3.25.0 5e785d005ccc1 31.3MB
docker.m.daocloud.io/calico/node v3.25.0 08616d26b8e74 87.2MB
registry.aliyuncs.com/google_containers/coredns v1.11.3 c69fa2e9cbf5f 18.6MB
registry.aliyuncs.com/google_containers/etcd 3.5.15-0 2e96e5913fc06 56.9MB
registry.aliyuncs.com/google_containers/kube-apiserver v1.31.2 9499c9960544e 28MB
registry.aliyuncs.com/google_containers/kube-controller-manager v1.31.2 0486b6c53a1b5 26.1MB
registry.aliyuncs.com/google_containers/kube-proxy v1.31.2 505d571f5fd56 30.2MB
registry.aliyuncs.com/google_containers/kube-scheduler v1.31.2 847c7bc1a5418 20.1MB
registry.aliyuncs.com/google_containers/pause 3.10 873ed75102791 320kB三、导出容器镜像
3.1 命名空间问题说明
crictl、nerdctl 和 ctr 默认使用的命名空间不同:
| 工具 | 默认命名空间 | 说明 |
|---|---|---|
crictl | k8s.io | 直接使用,无需指定 |
nerdctl | default | 需要加 --namespace k8s.io |
ctr | default | 需要加 --namespace k8s.io |
因此,在使用 nerdctl 或 ctr 操作镜像时,必须指定 --namespace k8s.io。
3.2 确认镜像在 k8s.io 命名空间中
bash
nerdctl --namespace k8s.io images3.3 导出核心组件镜像
bash
# 创建存放镜像包的目录
mkdir -p /root/k8s-offline-export
# 导出 K8s 核心组件
nerdctl --namespace k8s.io save \
-o /root/k8s-offline-export/k8s-core.tar \
registry.aliyuncs.com/google_containers/kube-apiserver:v1.31.2 \
registry.aliyuncs.com/google_containers/kube-controller-manager:v1.31.2 \
registry.aliyuncs.com/google_containers/kube-scheduler:v1.31.2 \
registry.aliyuncs.com/google_containers/kube-proxy:v1.31.2 \
registry.aliyuncs.com/google_containers/pause:3.10 \
registry.aliyuncs.com/google_containers/etcd:3.5.15-0 \
registry.aliyuncs.com/google_containers/coredns:v1.11.33.4 导出 Calico 网络插件镜像
bash
# 导出 Calico 镜像
nerdctl --namespace k8s.io save \
-o /root/k8s-offline-export/k8s-calico.tar \
docker.m.daocloud.io/calico/node:v3.25.0 \
docker.m.daocloud.io/calico/cni:v3.25.0 \
docker.m.daocloud.io/calico/kube-controllers:v3.25.03.5 导出 Dashboard 镜像(可选)
bash
# 导出 Dashboard 镜像
nerdctl --namespace k8s.io save \
-o /root/k8s-offline-export/k8s-dashboard.tar \
docker.io/kubernetesui/dashboard:v2.7.0 \
docker.io/kubernetesui/metrics-scraper:v1.0.83.6 合并所有镜像包
bash
cd /root/k8s-offline-export
tar -cvf k8s-v1.31.2-offline-images.tar k8s-core.tar k8s-calico.tar k8s-dashboard.tar
gzip k8s-v1.31.2-offline-images.tar
ls -lh k8s-v1.31.2-offline-images.tar.gz
# -rw-r--r-- 1 root root 453M Jul 13 06:15 k8s-v1.31.2-offline-images.tar.gz3.7 常见导出问题排查
导出失败:digest not found
如果遇到类似错误:
FATA[0000] failed to get reader: content digest sha256:xxx: not found原因:containerd 的 metadata 索引损坏,但 blob 数据还在。
解决方案:
bash
# 1. 用 crictl 删除有问题的镜像
crictl rmi <镜像名:标签>
# 2. 重新拉取
crictl pull <镜像名:标签>
# 3. 重建索引
systemctl restart containerd
# 4. 再次导出如果问题持续,可以尝试删除 containerd 的 metadata 数据库重建索引:
bash
systemctl stop containerd
mv /var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db \
/var/lib/containerd/io.containerd.metadata.v1.bolt/meta.db.bak
systemctl start containerd
# 然后重新拉取所有镜像四、导出 RPM 包
4.1 使用 yumdownloader 下载 RPM 包
bash
# 安装 yum-utils
yum install -y yum-utils
# 创建 RPM 存放目录
mkdir -p /root/k8s-offline-export/k8s-offline-rpms
# 下载所有需要的 RPM 包
yumdownloader --destdir=/root/k8s-offline-export/k8s-offline-rpms \
kubeadm-1.31.2 \
kubelet-1.31.2 \
kubectl-1.31.2 \
cri-tools \
kubernetes-cni \
runc \
conntrack-tools \
libnetfilter_cthelper \
libnetfilter_cttimeout \
libnetfilter_queue4.2 查看已下载的 RPM 包
bash
ls -lh /root/k8s-offline-export/k8s-offline-rpms/预期输出:
total 54M
-rw-r--r-- 1 root root 187K conntrack-tools-1.4.4-7.el7.x86_64.rpm
-rw-r--r-- 1 root root 7.0M cri-tools-1.31.1-150500.1.1.x86_64.rpm
-rw-r--r-- 1 root root 11M kubeadm-1.31.2-150500.1.1.x86_64.rpm
-rw-r--r-- 1 root root 11M kubectl-1.31.2-150500.1.1.x86_64.rpm
-rw-r--r-- 1 root root 15M kubelet-1.31.2-150500.1.1.x86_64.rpm
-rw-r--r-- 1 root root 7.1M kubernetes-cni-1.5.1-150500.1.1.x86_64.rpm
-rw-r--r-- 1 root root 18K libnetfilter_cthelper-1.0.0-11.el7.x86_64.rpm
-rw-r--r-- 1 root root 18K libnetfilter_cttimeout-1.0.0-7.el7.x86_64.rpm
-rw-r--r-- 1 root root 24K libnetfilter_queue-1.0.2-2.el7_2.x86_64.rpm
-rw-r--r-- 1 root root 2.7M runc-1.0.0-70.rc10.el7_9.x86_64.rpm4.3 打包 RPM 包
bash
cd /root/k8s-offline-export
tar -czvf k8s-v1.31.2-offline-rpms.tar.gz k8s-offline-rpms/
ls -lh k8s-v1.31.2-offline-rpms.tar.gz
# -rw-r--r-- 1 root root 54M Jul 13 06:25 k8s-v1.31.2-offline-rpms.tar.gz五、收集二进制文件和配置
5.1 复制 containerd 相关二进制文件
bash
cp /root/containerd-1.6.39-linux-amd64.tar.gz /root/k8s-offline-export5.2 复制 containerd 配置文件和服务文件
bash
# containerd 配置文件
cp /etc/containerd/config.toml /root/k8s-offline-export/containerd-config.toml
# containerd systemd 服务文件
cp /etc/systemd/system/containerd.service /root/k8s-offline-export/
# crictl 配置文件
cp /etc/crictl.yaml /root/k8s-offline-export/5.3 复制 Calico 部署文件
bash
# 如果之前下载过 calico.yaml
cp calico.yaml /root/k8s-offline-export/5.4 下载 nerdctl 二进制(可选)
如果目标服务器没有 nerdctl,可以从 GitHub 下载:
bash
wget -P /root/k8s-offline-export/ \
https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-1.7.6-linux-amd64.tar.gz六、编写离线安装脚本
bash
cat > /root/k8s-offline-export/install.sh << 'EOF'
#!/bin/bash
set -e # 遇到错误立即退出
WORKDIR=$(pwd)
echo "工作目录: $WORKDIR"
echo "=== 1. 解压 RPM 包 ==="
tar -xzvf k8s-v1.31.2-offline-rpms.tar.gz
echo "=== 2. 安装 RPM 包 ==="
cd k8s-offline-rpms
yum localinstall -y *.rpm
cd "$WORKDIR"
echo "=== 3. 配置 crictl ==="
cp crictl.yaml /etc/
echo "=== 4. 安装 containerd ==="
# 解压 containerd 二进制到 /usr/local(注意是 zxvf,不是 zcvf)
tar -xzvf containerd-1.6.39-linux-amd64.tar.gz -C /usr/local/
# 创建配置文件目录
mkdir -p /etc/containerd/
cp containerd-config.toml /etc/containerd/config.toml
# 复制 systemd 服务文件
cp containerd.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable containerd
systemctl start containerd
# 检查 containerd 状态
if systemctl status containerd > /dev/null 2>&1; then
echo "✅ containerd 启动成功"
else
echo "❌ containerd 启动失败,请检查日志"
journalctl -u containerd -n 20 --no-pager
exit 1
fi
echo "=== 5. 导入镜像 ==="
tar -zxvf k8s-v1.31.2-offline-images.tar.gz
ctr --namespace k8s.io image import k8s-core.tar
ctr --namespace k8s.io image import k8s-calico.tar
ctr --namespace k8s.io image import k8s-dashboard.tar
echo "=== 6. 验证镜像 ==="
crictl images
echo "=== 7. 安装 nerdctl 客户端工具 ==="
tar -xzvf nerdctl-1.7.6-linux-amd64.tar.gz -C /usr/local/
echo "=== 8. 初始化集群 ==="
kubeadm init \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.31.2 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12
echo "=== 9. 配置 kubectl ==="
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
echo "=== 10. 安装网络插件 ==="
kubectl apply -f calico.yaml
echo "=== 🎉 离线部署完成! ==="
kubectl get nodes
EOF
chmod +x /root/k8s-offline-export/install.sh七、打包完整离线部署包
bash
cd /root/k8s-offline-export
# 创建最终目录
mkdir -p /root/k8s-v1.31.2-offline-full
# 移动所有文件
mv k8s-v1.31.2-offline-images.tar.gz /root/k8s-v1.31.2-offline-full/
mv k8s-v1.31.2-offline-rpms.tar.gz /root/k8s-v1.31.2-offline-full/
mv containerd-1.6.39-linux-amd64.tar.gz /root/k8s-v1.31.2-offline-full/
mv nerdctl-1.7.6-linux-amd64.tar.gz /root/k8s-v1.31.2-offline-full/
mv containerd-config.toml /root/k8s-v1.31.2-offline-full/
mv containerd.service /root/k8s-v1.31.2-offline-full/
mv crictl.yaml /root/k8s-v1.31.2-offline-full/
mv calico.yaml /root/k8s-v1.31.2-offline-full/
mv install.sh /root/k8s-v1.31.2-offline-full/
# 最终打包
cd /root
tar -czvf k8s-v1.31.2-offline-full.tar.gz k8s-v1.31.2-offline-full/
# 查看最终包大小
ls -lh k8s-v1.31.2-offline-full.tar.gz
# -rw-r--r-- 1 root root 520M Jul 13 07:30 k8s-v1.31.2-offline-full.tar.gz八、离线部署步骤
8.1 将离线包传输到目标服务器
bash
# 使用 scp 或 U 盘拷贝
scp k8s-v1.31.2-offline-full.tar.gz root@目标IP:/root/8.2 解压并执行安装
bash
# 1. 解压离线包
tar -xzvf k8s-v1.31.2-offline-full.tar.gz
# 2. 进入目录
cd k8s-v1.31.2-offline-full
# 3. 执行安装脚本
./install.sh8.3 验证集群状态
bash
kubectl get nodes
kubectl get pods -n kube-system九、离线包内容总览
| 文件 | 大小 | 说明 |
|---|---|---|
k8s-v1.31.2-offline-full.tar.gz | ~520 MB | 完整离线部署包 |
解压后包含:
| 文件 | 说明 |
|---|---|
k8s-v1.31.2-offline-images.tar.gz | 453 MB |
k8s-v1.31.2-offline-rpms.tar.gz | 54 MB |
containerd-1.6.39-linux-amd64.tar.gz | 46 MB |
nerdctl-1.7.6-linux-amd64.tar.gz | 9.5 MB |
containerd-config.toml | 7 KB |
containerd.service | 410 B |
crictl.yaml | 137 B |
calico.yaml | 238 KB |
install.sh | 1 KB |
十、常见问题排查
Q1:导入镜像时报 "digest not found"
bash
# 解决方案:重启 containerd 后重新导入
systemctl restart containerd
ctr --namespace k8s.io image import k8s-v1.31.2-offline-images.tar.gzQ2:kubeadm init 报 "failed to pull image"
检查镜像是否导入成功:
bash
crictl images如果镜像缺失,重新导入:
bash
ctr --namespace k8s.io image import k8s-v1.31.2-offline-images.tar.gzQ3:节点 NotReady
检查 Calico 是否部署成功:
bash
kubectl get pods -n kube-system如果 Calico Pod 异常,重新部署:
bash
kubectl delete -f calico.yaml
kubectl apply -f calico.yamlQ4:containerd 启动失败
查看日志:
bash
journalctl -u containerd -n 50 --no-pager常见原因:
- 配置文件格式错误:检查
/etc/containerd/config.toml - 端口被占用:
ss -tlnp | grep 10000
十一、结语
至此,你已经掌握了:
- 从在线 Kubernetes 集群导出所有资源(镜像 + RPM + 配置)
- 打包成完整的离线部署包
- 在离线服务器上一键完成部署
这套方案适用于所有无法连接互联网的生产环境,无论是政府内网、金融专网还是企业私有云,都能完美适配。
延伸阅读:
附件
离线包在线资源
https://dl.fishfinal.com/kubernetes/k8s-v1.31.2-offline-full.tar.gz
离线包目录结构
k8s-v1.31.2-offline-full/
├── install.sh # 一键安装脚本
├── k8s-v1.31.2-offline-images.tar.gz # 所有容器镜像 (453 MB)
├── k8s-v1.31.2-offline-rpms.tar.gz # 所有 RPM 包 (54 MB)
├── containerd-1.6.39-linux-amd64.tar.gz # containerd 二进制
├── nerdctl-1.7.6-linux-amd64.tar.gz # nerdctl 客户端
├── containerd-config.toml # containerd 配置
├── containerd.service # systemd 服务文件
├── crictl.yaml # crictl 配置
└── calico.yaml # Calico 部署文件离线安装脚本
bash
#!/bin/bash
set -e # 遇到错误立即退出
WORKDIR=$(pwd)
echo "工作目录: $WORKDIR"
echo "=== 1. 解压 RPM 包 ==="
tar -xzvf k8s-v1.31.2-offline-rpms.tar.gz
echo "=== 2. 安装 RPM 包 ==="
cd k8s-offline-rpms
yum localinstall -y *.rpm
cd "$WORKDIR"
echo "=== 3. 配置 crictl ==="
cp crictl.yaml /etc/
echo "=== 4. 安装 containerd ==="
# 解压 containerd 二进制到 /usr/local(注意是 zxvf,不是 zcvf)
tar -xzvf containerd-1.6.39-linux-amd64.tar.gz -C /usr/local/
# 创建配置文件目录
mkdir -p /etc/containerd/
cp containerd-config.toml /etc/containerd/config.toml
# 复制 systemd 服务文件
cp containerd.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable containerd
systemctl start containerd
# 检查 containerd 状态
if systemctl status containerd > /dev/null 2>&1; then
echo "✅ containerd 启动成功"
else
echo "❌ containerd 启动失败,请检查日志"
journalctl -u containerd -n 20 --no-pager
exit 1
fi
echo "=== 5. 导入镜像 ==="
tar -zxvf k8s-v1.31.2-offline-images.tar.gz
ctr --namespace k8s.io image import k8s-core.tar
ctr --namespace k8s.io image import k8s-calico.tar
ctr --namespace k8s.io image import k8s-dashboard.tar
echo "=== 6. 验证镜像 ==="
crictl images
echo "=== 7. 安装 nerdctl 客户端工具 ==="
tar -xzvf nerdctl-1.7.6-linux-amd64.tar.gz -C /usr/local/
echo "=== 8. 初始化集群 ==="
kubeadm init \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.31.2 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/12
echo "=== 9. 配置 kubectl ==="
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
echo "=== 10. 安装网络插件 ==="
kubectl apply -f calico.yaml
echo "=== 🎉 离线部署完成! ==="
kubectl get nodes