Kubernetes离线部署指南:kubeadm+containerd内网集群搭建全流程
2026/9/16 7:12:48 网站建设 项目流程

Kubernetes离线部署这件事,放在开发测试环境里,基本是每个团队迟早都会撞上的一道坎。很多项目的研发网段完全隔离,或者企业内部对系统外联有严格约束,apt、yum、docker pull这些日常操作全被卡死,可是K8s从系统依赖到容器镜像,每一步都在向网络要资源。这篇指南就是冲着这个场景来的,把在断网机器上从零搭一套K8s开发测试集群所需的完整物料、操作步骤、踩坑经验都列清楚,照着做基本能把集群跑起来,中间不会再被“拉不到镜像”这种问题逼疯。

这次分享的目标读者很明确:被内网环境折磨的DevOps、需要自己在测试环境搭建平台的开发同学,还有刚接触K8s想搞一套完整离线实践的新手。内容覆盖制品准备、基础环境配置、kubeadm初始化、常用插件离线安装、以及高频问题排查,整体按“先在线打包、后离线安装”的思路展开,用到什么解释什么。

1. 项目概述与整体设计思路

在动手之前,我先把离线部署的底层逻辑讲透。开发测试环境的离线部署,本质上不是“在没有网络的地方变魔法”,而是把在线环境下原本自动完成的依赖获取动作,提前手动做完,再搬到目标环境里执行。

1.1 为什么开发测试环境需要离线方案

这个问题我在不同团队被问过很多次。真实场景大概有三类:一是涉密研发网或企业内网,物理隔离、外网禁访,这是最严格的;二是托管机房或云上VPC,网络策略只开放白名单端口,公共镜像源根本不通;三是临时搭建的演示、培训或比赛环境,场地网络不稳定,与其现场赌运气不如全部离线。

开发测试环境还有一个容易被忽略的特点:它需要频繁重建。版本升级、环境损坏、人员交接,都可能要求你快速再拉一套集群。如果这套集群的搭建过程高度依赖外网,那么每次重建都是一次完整的外网依赖窗口,这在隔离环境下是不可接受的。离线部署方案把依赖固化成制品包,重建集群只是重复执行,时间成本和失败风险都会大幅下降。

1.2 方案选型:kubeadm还是二进制手动部署

搭建K8s集群的常见路线有三种:kubeadm引导安装、二进制手动部署、以及基于Playbook的自动化工具(比如kubeasz、sealos)。

开发测试环境我建议优先选kubeadm。原因很直接:kubeadm是官方维护的集群引导工具,生产环境大量使用,它的配置文件可审查、可版本化、可重复执行;同时它把etcd、apiserver、controller-manager、scheduler这些组件的静态Pod定义直接生成到集群里,架构清晰,排查问题更容易。二进制手动部署在离线场景下不是不行,但需要自己处理大量systemd单元文件和证书签发,开发测试环境没必要背这个复杂度。

另外要提醒一下,不要一上来就想着用sealos这类封装工具。sealos确实能把离线部署压缩到一条命令,但它的镜像方案相对黑盒,出了问题不好定位。等到你用kubeadm把流程跑通、理解底层逻辑之后,再谈工具化封装也不迟。本指南核心就是kubeadm加containerd的组合。

1.3 离线部署的思路闭环:制品准备、搬运落地、离线安装

离线部署如果拆成三个阶段来看,思路会非常清晰。

第一个阶段是制品准备,在能联网的机器上完成所有依赖的下载和归档。需要准备的制品包含三类:操作系统层依赖(rpm包或deb包)、K8s核心二进制与工具(kubeadm、kubelet、kubectl),还有集群运行所需的所有容器镜像。这一阶段的核心目标是把“网络依赖”彻底固化成“文件依赖”。

第二个阶段是搬运落地,通过U盘、内网传输通道等介质,把制品包拷到目标机器上,再完成解压归档、本地仓库初始化等操作。这个阶段要特别注意目录规划、校验值和版本锁定。

第三个阶段是离线安装,目标机器完全断网状态下,向本地仓库和本地镜像库请求资源,完成K8s集群初始化、节点加入、网络插件安装和应用组件部署。整个过程不需要任何外网请求,这就是离线部署的意义所在。

2. 离线资源准备与制品清单

整个离线部署工程里,资源准备是最枯燥但最关键的环节。前面版本选错一个,后面可能全部推倒重来。

2.1 需要准备的完整制品清单

我整理了一份开发测试环境最常用的清单,以CentOS 7.9(或兼容的Rocky Linux 8)加Kubernetes 1.28.x为例,直接按这个清单准备就不会缺东西。

制品类别具体内容版本建议用途说明
操作系统CentOS 7.9/Ubuntu 22.04稳定版统一基座,避免系统差异
容器运行时containerd1.7.xK8s默认CRI运行时
辅助工具crictl与K8s版本匹配命令行查看容器和镜像
K8s组件kubeadm、kubelet、kubectl1.28.x集群引导与日常管理
系统依赖rpmlibseccomp、conntrack等以安装提示为准containerd和kubelet的系统依赖
核心镜像见2.3小节与K8s版本严格对应apiserver、etcd、pause等
网络插件镜像Calico或Flannel与K8s兼容Pod网络方案
辅助组件镜像Dashboard、metrics-server选择稳定版Web管理、资源监控

提示:版本锁定是离线部署的第一原则。K8s镜像与kubeadm版本必须一一对应,etcd和pause版本也不要手动修改,否则初始化时镜像拉取环节校验会直接报错。建议以kubeadm config images list命令在联网机器上输出的结果为准。

2.2 制作离线yum仓库

操作系统和K8s相关的rpm包,在离线机器上必须有一个本地仓库来源。最常用的做法是在联网机器上准备一个目录,把需要的rpm包放进去,然后用createrepo生成仓库元数据,最后通过HTTP或直接拷贝分发到目标机器。

先在一台联网机器上创建目录结构:

mkdir -p /opt/k8s-offline/rpms cd /opt/k8s-offline/rpms # 下载K8s核心组件rpm包(以1.28.2为例) yumdownloader --resolve kubeadm-1.28.2 kubelet-1.28.2 kubectl-1.28.2 # 下载containerd及其依赖 yumdownloader --resolve containerd.io # 加入常见系统依赖 yumdownloader --resolve libseccomp-devel

下载完成后,生成仓库元数据:

yum install -y createrepo createrepo /opt/k8s-offline/rpms

把整个rpms目录拷到离线机器后,在离线机器上创建本地repo文件:

cat > /etc/yum.repos.d/k8s-local.repo <<'EOF' [k8s-local] name=Kubernetes Local Repository baseurl=file:///opt/k8s-offline/rpms enabled=1 gpgcheck=0 EOF yum clean all && yum makecache

注意:gpgcheck设为0在这里是合理的,因为包来源已经通过内网传输链路做了可信保证,继续开启校验反而可能因为缺少GPG公钥导致安装失败。

2.3 获取K8s核心镜像与组件镜像

K8s集群运行所需的镜像,必须在联网机器上提前拉取并导出为tar包。用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 registry.k8s.io/coredns/coredns:v1.10.1

逐一拉取并打tar包:

# 安装docker(仅用于镜像搬运)或使用skopeo、ctr等方式 docker pull registry.k8s.io/kube-apiserver:v1.28.2 # 以此类推,将全部镜像拉取到本地 mkdir -p /opt/k8s-offline/images docker save registry.k8s.io/kube-apiserver:v1.28.2 -o /opt/k8s-offline/images/kube-apiserver.tar

开发测试环境如果还需要Dashboard、metrics-server、Calico等组件,也一并拉取导出。推荐的辅助镜像清单:

组件镜像版本
Dashboardkubernetesui/dashboardv2.7.0
Dashboard metricskubernetesui/metrics-scraperv1.0.8
metrics-serverregistry.k8s.io/metrics-server/metrics-serverv0.6.4
Calicocalico/cni、calico/node、calico/kube-controllersv3.26.1

实操心得:所有tar包导出后顺手生成一个sha256校验文件,传到离线机器后先校验再导入。镜像动辄几百MB甚至上GB,拷贝过程中偶尔会发生文件损坏,没有校验机制你会花大量时间排一个根本不存在的问题。

2.4 目录规划与传递介质安排

我习惯把离线制品包按统一目录结构组织,目标机器直接照抄这个结构,减少出错。

/opt/k8s-offline/ ├── rpms/ # yum仓库目录,含createrepo元数据 ├── images/ # 所有镜像tar包 ├── packages/ # kubeadm、kubelet、kubectl二进制(如果不用rpm) ├── configs/ # kubeadm配置文件、calico yaml等 └── checksum.sha256 # 所有文件的校验文件

传递介质建议使用内网共享存储或高速U盘,大镜像文件通过U盘拷贝时注意文件系统格式,建议用exFAT或ext4,避免单文件4GB限制。

3. 基础环境初始化与离线安装准备

制品搬运完成后,离线机器上要开始真正的安装动作。这一阶段以“可重复执行”为原则,所有修改都留有日志和记录。

3.1 主机规划与节点划分建议

开发测试环境我建议至少准备一台控制节点加一台工作节点。如果资源有限,单机All-in-One也可以,但最好在虚拟机里做快照,方便出问题时回滚。推荐的资源基线:

节点角色配置建议用途
控制平面节点4C8G 100GB磁盘运行etcd、apiserver、controller-manager、scheduler
工作节点4C8G 100GB磁盘起运行业务Pod,如果跑大模型推理类应用建议加GPU
单机All-in-One8C16G 200GB磁盘演示、开发联调,注意etcd和业务资源抢占问题

主机名和hosts解析提前配置好,所有节点的主机名都不能重复,并且集群内所有节点都能通过主机名互相访问。

hostnamectl set-hostname k8s-master01 cat >> /etc/hosts <<EOF 192.168.10.11 k8s-master01 192.168.10.12 k8s-node01 EOF

3.2 系统基础配置:内核模块、系统参数、关闭swap

K8s对系统层有一个硬性要求:swap必须关闭,否则kubelet启动会直接报错退出。这是因为K8s的Pod内存管理机制依赖cgroup来控制和统计内存使用,swap的存在会让这种统计失真。执行以下操作:

# 关闭swap并注释/etc/fstab相关行 swapoff -a sed -i '/ swap / s/^/#/' /etc/fstab # 加载K8s所需内核模块 cat > /etc/modules-load.d/k8s.conf <<EOF overlay br_netfilter EOF modprobe overlay modprobe br_netfilter # 设置内核参数 cat > /etc/sysctl.d/k8s.conf <<EOF net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF sysctl --system

这几个内核参数的作用,我用个直观的方式解释:net.ipv4.ip_forward控制着K8s集群内部Pod和Service的流量转发,如果不开启,ClusterIP模式的Service流量无法正确路由到Pod,集群内Pod之间也无法跨节点通信。br_netfilter相关参数是确保经过Linux网桥的流量也能被iptables规则处理,这是K8s网络策略和Service转发的基础。

3.3 安装containerd并处理关键配置

离线机器上安装containerd,首选从离线yum仓库直接安装:

yum install -y containerd.io

安装完成后,初始化配置并调整关键项。containerd的默认配置文件是/etc/containerd/config.toml,先生成默认配置再修改:

mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml

然后修改两个地方。第一是sandbox(pause)镜像地址,确保和K8s版本一致:

[plugins."io.containerd.grpc.v1.cri"] sandbox_image = "registry.k8s.io/pause:3.9"

第二是cgroup驱动,必须改为systemd:

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true

关于cgroup驱动,这里多写几句。Linux系统有两套cgroup管理方式:cgroupfs和systemd。K8s官方强烈建议kubelet使用systemd驱动,因为systemd本身在初始化时就会接管cgroup,如果kubelet用cgroupfs而systemd也在管理cgroup,两者同时控制系统资源分配会出现“双头管理”,轻则资源统计异常,重则节点崩溃。这就是为什么kubelet和containerd的cgroup驱动必须要一致且都为systemd。

修改完成后启动containerd并验证:

systemctl enable containerd && systemctl start containerd ctr version

3.4 安装kubeadm、kubelet、kubectl并锁定版本

K8s三件套的安装同样走本地yum仓库:

yum install -y kubeadm-1.28.2 kubelet-1.28.2 kubectl-1.28.2

安装完成后需要把版本锁定,防止意外升级导致版本漂移:

yum install -y yum-plugin-versionlock yum versionlock kubeadm kubelet kubectl

然后设置kubelet开机启动(先不启动,等初始化完成后才会正常运行):

systemctl enable kubelet

4. 使用kubeadm离线初始化集群

制品和基础环境都就绪后,进入核心的集群初始化环节。这一阶段的操作要注意每一步的校验输出,很多坑在输出日志里其实有明确提示。

4.1 将镜像tar包导入到containerd

离线环境下Crictl的镜像导入方式与docker有很大不同。对containerd来说,需要用到ctr命令,并且必须指定K8s的命名空间k8s.io,否则kubelet无法识别:

# 在images目录下执行 for img in *.tar; do ctr -n=k8s.io images import "$img" done

验证一下镜像是否导入成功:

crictl images

注意:crictl默认连接containerd的socket,配置一下/etc/crictl.yaml会更顺手:

runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: false

4.2 编写离线kubeadm配置文件

kubeadm init支持通过配置文件传参,离线场景强烈建议用配置文件而不是纯命令行参数,因为配置可以保存、review、复用。以下是一个基础的控制平面节点配置:

apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: 192.168.10.11 bindPort: 6443 nodeRegistration: criSocket: /run/containerd/containerd.sock --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v1.28.2 controlPlaneEndpoint: 192.168.10.11:6443 networking: dnsDomain: cluster.local podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12

几个关键参数的说明:

  • advertiseAddress:控制节点监听API请求的IP,一定要填内网实际IP,不要填默认路由IP。
  • kubernetesVersion:必须和本地导入的镜像版本完全一致。
  • podSubnet:Pod地址段,我建议用10.244.0.0/16,和Flannel默认保持一致会省很多事。
  • serviceSubnet:Service虚拟IP段,10.96.0.0/12是默认值,没有特殊规划可以不变。

关于Pod网段的选择有个实际经验:开发测试环境经常存在多个集群,如果每个集群的Pod网段都相同,未来做多集群联邦或者集群迁移时冲突会非常明显。建议从一开始就在内网IP段规划中预留不同集群的不同网段,避免后续返工。

4.3 初始化控制平面节点

在控制节点上执行:

kubeadm init --config /opt/k8s-offline/configs/kubeadm-config.yaml --upload-certs

这一步有几个可能的结局:顺利通过,或者卡在等待kubelet启动、拉取镜像失败等位置。如果卡住,不要反复重试同一命令,应该先查kubelet日志:

journalctl -u kubelet -f

初始化成功后会输出一大段提示,其中包含加入工作节点的join命令,一定保存好。然后按提示配置kubectl:

mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config

验证控制平面状态:

kubectl get nodes kubectl get pods -A

此时node状态大概率是NotReady,原因是还没有安装CNI网络插件,这是正常的。

4.4 添加Worker节点到集群

工作节点只需要安装kubeadm、kubelet和containerd,并导入相同的一套镜像,然后执行control plane初始化后输出的join命令:

kubeadm join 192.168.10.11:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx

如果token过期,在控制节点上重新生成:

kubeadm token create --print-join-command

实操心得:开发测试环境经常遇到worker节点重新初始化的情况,旧的K8s残留目录会导致加入失败。重置节点时执行kubeadm reset -f后,记得手动清理/etc/cni/net.d和/var/lib/kubelet等目录。不清理干净,新加入节点的CNI配置会乱,Pod网络会彻底瘫痪。

5. 开发测试常用组件离线安装

集群初步跑起来之后,离真正能用还有一段距离。这一节覆盖开发测试环境最常用的几个组件的离线安装方式,包括CNI网络插件、资源监控、Web管理界面,以及离线业务镜像导入能力。

5.1 安装CNI网络插件(Calico/Flannel)

没有网络插件,集群节点会一直保持NotReady状态。开发测试环境我推荐优先使用Flannel,因为配置简单、资源占用低,适合性能不高的测试机和虚拟机。Calico则适合需要网络策略(NetworkPolicy)的测试场景,比如你想验证Pod级别的访问控制规则。

以Flannel为例,先在联网环境准备镜像和yaml文件:

docker pull flannelcni/flannel:v0.22.0 docker save flannelcni/flannel:v0.22.0 -o /opt/k8s-offline/images/flannel.tar # 下载kube-flannel.yml

离线机器上导入镜像并应用:

ctr -n=k8s.io images import /opt/k8s-offline/images/flannel.tar kubectl apply -f /opt/k8s-offline/configs/kube-flannel.yml

检查Pod状态:

kubectl get pods -A | grep flannel kubectl get nodes

几分钟后节点应该都变为Ready。如果Calico,思路一致:提前下载calico.yaml,替换其中的镜像地址为本地或内网仓库地址,导入镜像后kubectl apply即可。

5.2 安装metrics-server实现资源监控

开发测试环境里,查看Pod和节点的CPU、内存使用情况是一个非常高频的需求,kubectl top命令依赖metrics-server。这个组件在离线安装时有一个常见坑:默认配置下它要求节点间的kubelet连接必须走TLS证书校验,开发测试环境的证书配置很难满足,需要给metrics-server加上--kubelet-insecure-tls参数。

先下载metrics-server的yaml(官方components.yaml),修改Deployment部分:

containers: - args: - --cert-dir=/tmp - --secure-port=4443 - --kubelet-insecure-tls - --kubelet-preferred-address-types=InternalIP

离线机器导入镜像并部署:

ctr -n=k8s.io images import /opt/k8s-offline/images/metrics-server.tar kubectl apply -f /opt/k8s-offline/configs/metrics-server-components.yaml kubectl top nodes

5.3 安装Kubernetes Dashboard可视化界面

对于开发测试环境,Dashboard能明显降低团队的使用门槛。一个没接触过K8s的同事,通过网页看Pod日志、看Deployment状态,比教他敲kubectl命令要高效得多。

先导入Dashboard相关镜像:

ctr -n=k8s.io images import /opt/k8s-offline/images/dashboard.tar ctr -n=k8s.io images import /opt/k8s-offline/images/metrics-scraper.tar kubectl apply -f /opt/k8s-offline/configs/dashboard.yaml

创建管理员账号并获取登录token:

apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard
kubectl -n kubernetes-dashboard create token admin-user

访问方式上,开发测试环境最省事的是把Service改成NodePort:

kubectl -n kubernetes-dashboard edit svc kubernetes-dashboard # 将type改为NodePort,保存后查看端口 kubectl -n kubernetes-dashboard get svc

通过节点IP加NodePort就能访问Dashboard,这个方式在断网环境里完全够用。

5.4 镜像导入的通用能力:支撑离线业务部署

开发测试环境里,K8s集群本身不是目的,跑业务才是。很多团队在离线集群上要部署大模型推理服务(比如最近很火的DeepSeek 8B)、开源数据平台、低代码工具等。这类应用的镜像动辄几个GB到几十GB,怎么在离线环境把它变成K8s能用的工作负载,本质还是走镜像导入这条路。

通用流程是这样的:在能联网的环境里docker pull业务镜像,然后docker save成tar包,传导到离线机器后,用ctr命令导入到k8s.io命名空间,再接Deployment或Helm Chart部署。业务镜像导入和K8s系统镜像导入,在流程上没有任何区别,只是体积更大。

# 联网机器上 docker pull deepseek-ai/DeepSeek-R1-Distill-Qwen-8B:latest(示意) docker save deepseek-ai/DeepSeek-R1-Distill-Qwen-8B -o /opt/k8s-offline/images/deepseek-8b.tar # 离线机器上 ctr -n=k8s.io images import /opt/k8s-offline/images/deepseek-8b.tar

注意大镜像导入耗时较长,ctr命令可能看起来像卡住了,实际上是在解包写入。建议先用sha256校验文件确认完整性,再导入。K8s侧只要有GPU驱动(如果需要),就可以通过kubectl apply部署推理服务。

6. 常见问题与排障速查表

离线部署K8s的坑,从操作系统层到Pod运行层都有。我把这几年实际遇到的高频问题整理成一张速查表,每个问题都是排查过的,不是网上抄来的。

问题现象根因分析解决方案
kubeadm init卡在等待kubelet启动镜像没导入或cgroup驱动配置错误检查crictl images确认镜像存在;核对containerd SystemdCgroup配置
初始化后node处于NotReadyCNI网络插件未安装或pause镜像缺失安装Flannel/Calico;确认pause镜像存在且镜像tag与k8s版本一致
Pod状态一直是ContainerCreatingCNI插件没有就绪或镜像拉取失败kubectl describe pod查看事件,确认镜像是否导入到k8s.io命名空间
CoreDNS一直CrashLoopBackOff网络插件与Pod网段冲突检查podSubnet配置,避免与主机网段重叠
kubectl top没有数据metrics-server未安装或安全参数缺失确认metrics-server已启动且配置--kubelet-insecure-tls
工作节点join后无法Readytoken过期或CNI配置残留kubeadm token create重新生成;kubeadm reset后清理/var/lib/kubelet与/etc/cni/net.d
Dashboard无法访问Service类型为ClusterIP改为NodePort或用kubectl proxy访问
容器内时间不准开发测试环境无NTP外网源集群内搭建内网NTP服务,或部署时将宿主时区与time同步挂载进容器

6.1 初始化失败:镜像拉取是最常见的拦路虎

离线机器上执行kubeadm init,如果在输出中看到Failed to pull image、EOF等字样,不用慌,这基本就是两种原因:镜像没有导入到containerd,或者导入时没有指定k8s.io这个命名空间。有一种情况是镜像明明导入了,crictl images也能看到,但kubeadm还是提示拉取失败,原因是tag不一致。你本地导入的是v1.28.2,但kubeadm配置里写的kubernetesVersion是v1.28.1,它会按照v1.28.1去找镜像,自然找不到。

规避方法是先执行一遍:

kubeadm config images list --image-repository registry.k8s.io --kubernetes-version v1.28.2

逐行对比本地crictl images,确保tag完全一致,再改配置执行init。

6.2 节点NotReady的排查思路

如果你确认CNI插件已经安装,但节点还是NotReady,按这个顺序排查:先看系统组件Pod是否正常运行,再看网络插件Pod日志,最后检查主机防火墙和节点IP配置。开发测试环境很多NotReady的根因不是K8s本身,而是系统防火墙没有放行Pod网段流量。

systemctl status firewalld # 开发测试环境可以直接关闭,或者放行必要端口 systemctl disable firewalld --now

注意:关闭防火墙后要确认主机本身没有单独的安全组或网络安全策略,比如虚拟化平台的security group。Pod的Overlay网络走的是VXLAN或host-gw模式,如果底层网络策略限制UDP端口,flannel流量会被丢弃,表现为跨节点Pod不通但单节点内正常。

6.3 证书有效期与Token过期问题

K8s的kubeadm默认签发的证书有效期是一年。开发测试环境里集群用一年以上很常见,一旦证书过期,kubectl会直接报证书过期或Unauthorized。解决办法是每年续期一次:

kubeadm certs renew all systemctl restart kubelet

如果是生产级高可用环境,还需要替换kubeconfig文件。开发测试环境在证书到期前几天处理就行,续期后重启各控制组件,通常不会影响已有数据。如果发现apiserver等静态Pod没有被更新,可以直接删除对应的Pod让kubelet重建:

kubectl -n kube-system delete pod kube-apiserver-$(hostname)

6.4 大镜像导入变慢与存储空间不足

开发测试环境跑大模型相关应用时,镜像导入动辄几十GB,整个过程对磁盘空间要求很高。ctr导入镜像会先解包到本地,再写入到containerd的存储目录,因此需要的临时空间是镜像tar包的1.5到2倍。建议先检查磁盘空间:

df -h /var/lib/containerd

如果空间不够,先把tar包放在独立磁盘或从共享存储读取,导入完成后删除tar包释放空间。另外,containerd的snapshotter对空间占用比较敏感,如果频繁导入删除大镜像导致空间不回收,可以执行gc:

ctr -n=k8s.io content gc ctr -n=k8s.io snapshots gc

这个操作在业务低峰期做,gc过程会占用一些CPU和磁盘IO。

7. 实操心得与后续扩展建议

最后聊一些我自己的经验总结。多次离线部署K8s之后,我最大的体会是:离线部署最难的不是安装过程本身,而是版本一致性管理。镜像版本、kubeadm版本、系统依赖版本、网络插件版本,任何一个环节的版本漂移都会导致连锁失败。所以强烈建议把制品清单做成一个版本化文件,放进Git仓库,每次迭代都记录变更。这样哪怕半年后需要重建一套集群,翻一下仓库历史就能按当时的版本完整复原。

另外一个实操心得是:把重复的安装过程写成脚本。虽然kubeadm命令本身不复杂,但准备镜像、导入镜像、配内核参数这些环节完全适合脚本化。建议至少把镜像导入、基础环境配置、离线yum仓库配置这三部分写成Shell脚本,传到离线机器上一条命令执行,能大幅减少人工操作失误。

后续如果有余力,可以往这几个方向扩展:一是搭建内网Harbor镜像仓库,配合containerd的registry配置,让离线机器从内网镜像仓库拉取镜像,比反复导入tar包更贴近生产使用方式;二是引入GitLab Runner实现离线环境下的CI/CD;三是把Chart包离线化,让团队通过Helm快速部署中间件。这些都是在“离线K8s集群可用”之后,开发测试环境真正发挥价值的方向。

这套流程做完之后,你会发现离线部署K8s没有想象中那么玄学,核心就是三件事:把依赖准备好、把版本锁住、把日志看仔细。做到这三点,任何断网环境里你都能从容地搭出一套可用的Kubernetes开发测试环境。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询