Skip to content

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

Kubernetes 离线部署包制作指南示意图

写在前面

很多生产环境是无法连接互联网的——政府内网、金融专网、军工涉密网、企业私有云……在这些场景下,你无法直接从 Docker Hub 或 Google 仓库拉取镜像,也无法通过 yum 在线安装软件包。

唯一的办法就是:在能联网的环境下,把所有东西提前准备好,打包成离线安装包,再拷贝进去。

本文基于上一篇《CentOS 7 手动安装 Kubernetes v1.31.2 完全指南》已经成功运行的集群,完整记录从在线环境导出所有资源,到离线服务器上完成部署的全过程

免责声明

本文中使用的镜像加速地址(如 https://docker.1ms.runhttps://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 + Dashboardctr/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-system

2.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 命名空间问题说明

crictlnerdctlctr 默认使用的命名空间不同:

工具默认命名空间说明
crictlk8s.io直接使用,无需指定
nerdctldefault需要加 --namespace k8s.io
ctrdefault需要加 --namespace k8s.io

因此,在使用 nerdctlctr 操作镜像时,必须指定 --namespace k8s.io

3.2 确认镜像在 k8s.io 命名空间中

bash
nerdctl --namespace k8s.io images

3.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.3

3.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.0

3.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.8

3.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.gz

3.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_queue

4.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.rpm

4.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-export

5.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.sh

8.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.gz453 MB
k8s-v1.31.2-offline-rpms.tar.gz54 MB
containerd-1.6.39-linux-amd64.tar.gz46 MB
nerdctl-1.7.6-linux-amd64.tar.gz9.5 MB
containerd-config.toml7 KB
containerd.service410 B
crictl.yaml137 B
calico.yaml238 KB
install.sh1 KB

十、常见问题排查

Q1:导入镜像时报 "digest not found"

bash
# 解决方案:重启 containerd 后重新导入
systemctl restart containerd
ctr --namespace k8s.io image import k8s-v1.31.2-offline-images.tar.gz

Q2:kubeadm init 报 "failed to pull image"

检查镜像是否导入成功:

bash
crictl images

如果镜像缺失,重新导入:

bash
ctr --namespace k8s.io image import k8s-v1.31.2-offline-images.tar.gz

Q3:节点 NotReady

检查 Calico 是否部署成功:

bash
kubectl get pods -n kube-system

如果 Calico Pod 异常,重新部署:

bash
kubectl delete -f calico.yaml
kubectl apply -f calico.yaml

Q4:containerd 启动失败

查看日志:

bash
journalctl -u containerd -n 50 --no-pager

常见原因:

  • 配置文件格式错误:检查 /etc/containerd/config.toml
  • 端口被占用:ss -tlnp | grep 10000

十一、结语

至此,你已经掌握了:

  1. 从在线 Kubernetes 集群导出所有资源(镜像 + RPM + 配置)
  2. 打包成完整的离线部署包
  3. 在离线服务器上一键完成部署

这套方案适用于所有无法连接互联网的生产环境,无论是政府内网、金融专网还是企业私有云,都能完美适配。

延伸阅读:

附件

离线包在线资源

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
最后更新2026/07/12 17:40
如果你觉得这篇文章有帮助,或者想聊聊技术、工作,欢迎通过下面方式联系我:
contact fishfinal