news 2026/9/30 3:30:57

信创离线环境Kubernetes 1.32.11与KubeSphere部署指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
信创离线环境Kubernetes 1.32.11与KubeSphere部署指南

信创项目里最难受的从来不是K8s本身,而是“内网+离线”这四个字。交到你手上的可能是一台刚装好银河麒麟服务器版V11的裸机,要求把K8s 1.32.11集群和KubeSphere全部搭起来,网线只通内网,所有安装包、镜像都得提前拷进去。这套流程我实际走过不止一遍,中间踩过不少坑,所以把整个过程重新整理了一遍,使用containerd 2.1.5作为容器运行时,没有继续沿用docker——K8s 1.32已不再维护dockershim,containerd作为原生CRI运行时更稳、更省资源。这篇内容适合正在做信创环境交付的运维、刚接触离线K8s部署的实施同学参考,照着做完,你会得到一套带KubeSphere可视化控制台的多节点集群。

1. 前期准备:版本选型与离线物料清单

1.1 为什么要用这套组合

先说结论:这套组合最核心的思路是“二进制文件安装,不碰系统软件源”。银河麒麟V11虽然兼容性做得不错,但不同版本自带的软件源、依赖库差异还是存在的,如果走yum install docker或者apt install kubeadm这条路,光依赖解析就能耗掉你半天。直接把官方二进制解压到/usr/local/bin,再写成systemd服务,这样不依赖麒麟自带的包管理器,离线环境里最省心。

K8s版本选了1.32.11,这是当前比较新也比较稳的版本,API兼容性、cgroup v2支持都没什么大问题。containerd则选了2.1.5,比docker更轻,配置项也简单,而且kubeadm从1.26之后就默认对接containerd,不需要再装docker-shim之类的东西。KubeSphere用在交付场景里很加分,客户看到可视化控制台,比单纯给一堆kubectl get pods输出更有说服力,而且它自带监控、日志、多集群管理入口,省得自己额外搭grafana和prometheus。

这套组合里有个容易踩坑的细节:所有组件都要留意CPU架构。信创环境里x86_64和ARM64都可能遇到,下载二进制和镜像时务必先uname -m确认架构,别拿着amd64的包去装ARM的机器。

1.2 离线物料清单

开工前先建一个目录,比如/data/k8s-offline,后面所有物料都放这里。我按如下清单准备:

类别物料说明
容器运行时containerd-2.1.5-linux-amd64.tar.gz解压后包含containerd二进制和依赖
CRI调试工具crictl-v1.32.0-linux-amd64.tar.gz用于调试容器运行时状态
CNI插件cni-plugins-linux-amd64-v1.6.0.tgzCalico等插件运行的基础插件
Kubernetes组件kubeadm、kubelet、kubectl v1.32.11三节点都需要kubelet和kubeadm
控制面镜像etcd、coredns、pause、kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy用kubeadm config images list确认完整列表
网络插件calico.yaml + calico镜像tar包或用cilium,Calico离线部署最简单
KubeSphereks-installer.yaml + cluster-configuration.yaml + 镜像tar包必须有StorageClass支撑

镜像制作是在一台可以联网、且和机房服务器同CPU架构的机器上完成的。先执行kubeadm config images list --kubernetes-version=v1.32.11拿到官方镜像清单,再用skopeo copy docker://<镜像名> docker-archive:/data/images/<镜像名>.tar逐个导出。有人说用docker save也行,但docker save打出来的tar导入containerd时偶尔会出现tag信息不完整的情况,我还是推荐skopeo,干净直接。

所有物料拷进内网后,第一件事是校验sha256。比如sha256sum containerd-2.1.5-linux-amd64.tar.gz,生成一个清单文件随手放在目录里。离线环境没有外网,如果拷进来一个损坏的tar,导入时“archive/tar: invalid tar header”这类报错会把你折磨疯,校验这一步别省。

2. 系统初始化:麒麟V11上的环境配置

2.1 主机规划和基础网络

我这次用的是三节点结构:一台控制平面,两台工作节点。机器不多,没必要上VIP和负载均衡器,控制平面地址直接写master的IP就行。离线环境里越简单越不容易出错。

节点IP角色配置建议
k8s-master0110.10.10.11control-plane4C8G起
k8s-node0110.10.10.12worker8C16G起
k8s-node0210.10.10.13worker8C16G起

每台机器都执行:

hostnamectl set-hostname k8s-master01

然后修改/etc/hosts:

10.10.10.11 k8s-master01 10.10.10.12 k8s-node01 10.10.10.13 k8s-node02

这里有个原则:所有节点的主机名、IP映射必须一致,不能只改master不改node。K8s集群内部的证书、节点注册都依赖主机名解析,最典型的问题就是kubectl get nodes后节点显示NotReady,因为kubelet的hostname解析到了localhost。

时间同步也要提前处理。内网没有外网NTP的话,至少保证所有节点手动同步一次:date -s "2025-01-20 10:00:00"。K8s对证书时间校验非常敏感,节点时间差超过五分钟,kubelet和apiserver之间的TLS握手就会失败,报错看起来是证书问题,实际是时间差。

2.2 防火墙、SELinux和Swap

麒麟V11默认开着firewalld,先关掉:

systemctl stop firewalld systemctl disable firewalld

如果系统里启用了SELinux,也要处理:

setenforce 0 sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config

Swap必须关闭:

swapoff -a sed -i '/swap/s/^/#/' /etc/fstab

关闭防火墙和SELinux的原因,不是为了省事,而是K8s的Pod网络、NodePort、kube-proxy都会动态创建iptables规则,防火墙策略很容易把这些规则拦掉。SELinux对容器文件系统的权限管理非常严格,后续挂载目录、Conntrack、网络插件都容易触发权限拒绝。生产环境如果要求开启防火墙,就需要梳理大量端口,至少要在每个节点放行6443、2379、2380、10250、30000-32767等端口,离线交付场景我建议先关掉,保证业务能跑起来,验收后再按安全基线加固。

2.3 内核模块、系统参数和CNI插件

加载两个关键内核模块:

modprobe overlay modprobe br_netfilter cat > /etc/modules-load.d/k8s.conf <<EOF overlay br_netfilter EOF

写入系统参数:

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 vm.swappiness = 0 EOF sysctl --system

这几个参数不是随便抄的。net.bridge.bridge-nf-call-iptables必须设为1,原因是K8s的Service通过iptables做DNAT时,如果网桥流量不经过netfilter,Pod跨节点访问Service就会被绕过,表现就是同节点Pod正常、跨节点Pod不通。net.ipv4.ip_forward为1是为了让Pod网段的流量能在节点间转发,Calico或Flannel的IPIP/VXLAN模式都依赖它。

顺便把CNI插件装上,每个节点都要:

mkdir -p /opt/cni/bin tar -C /opt/cni/bin -xzf cni-plugins-linux-amd64-v1.6.0.tgz ls /opt/cni/bin | grep bridge

这一步经常被忽略,Calico虽然会往宿主机拷自己的一套CNI插件,但portmap、loopback这些基础插件还是得有。缺了的话,Pod创建时会卡在SetUpPod,看了半天不知道原因。

3. 安装containerd 2.1.5并导入离线镜像

3.1 安装containerd与调优配置

containerd的安装很简单,解压就行:

tar -C /usr/local -xzf containerd-2.1.5-linux-amd64.tar.gz mkdir -p /etc/containerd containerd config default > /etc/containerd/config.toml

生成的config.toml很长,别慌,只需要关心两个地方。

第一,把SystemdCgroup改成true。找到[plugins.'io.containerd.grpc.v1.cri'.containerd.runtimes.runc]段落,把[plugins.'io.containerd.grpc.v1.cri'.containerd.runtimes.runc.options]下面的SystemdCgroup = false改成true:

sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

这个必须改。Kubelet默认的cgroup驱动是systemd,containerd如果还保持cgroupfs,两边看到的cgroup路径就对不上,kubelet会报failed to run Kubelet: failed to validate the kubelet's cgroup configuration against the runtime,节点直接NotReady。

第二,修改sandbox_image。这个就是pause镜像,K8s每个Pod启动都要靠它先拉起一个沙箱容器。默认值可能是registry.k8s.io/pause:3.10,我们离线环境里只要保证本地导入的镜像tag和这里一致就行,我统一改成了:

sed -i 's#sandbox_image = "registry.k8s.io/pause:3.8"#sandbox_image = "registry.k8s.io/pause:3.10"#' /etc/containerd/config.toml

如果你离线包里的pause版本不是3.10,以你实际镜像为准,关键是config.toml里的名字要和后面导入到containerd里的tag一模一样。

然后创建systemd服务:

cat > /etc/systemd/system/containerd.service <<'EOF' [Unit] Description=containerd container runtime After=network.target local-fs.target [Service] Type=notify ExecStart=/usr/local/bin/containerd --config /etc/containerd/config.toml Restart=always RestartSec=5 LimitNOFILE=1048576 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable --now containerd systemctl status containerd

确认containerd起来了再往下走。这里有个经验:Type=notify必须保留,containerd启动后通过sd_notify通知systemd自己就绪,kubelet如果等不到containerd的socket,会一直报“container runtime is down”。

3.2 把镜像导入k8s.io命名空间

镜像从离线目录拷贝到每个节点后,批量导入:

for img in /data/k8s-offline/images/*.tar; do ctr -n k8s.io images import --all-platforms "$img" done

这个-n k8s.io是全文最关键的一个参数,请务必记住。ctr默认命名空间是default,但K8s通过CRI调用containerd时,使用的是k8s.io命名空间。如果你用ctr images import不带-n k8s.io,镜像会被导到default命名空间里,K8s那边永远看不见,随后kubelet开始疯狂拉镜像,离线环境下又拉不到,最终状态就是节点NotReady。

导入完成后,验证一下:

ctr -n k8s.io images list | grep -E 'pause|etcd|kube-apiserver'

如果发现镜像tag和kubeadm config images list输出的不一致,用ctr -n k8s.io images tag补一个tag。例如:

ctr -n k8s.io images tag docker.io/library/pause:3.10 registry.k8s.io/pause:3.10

为了方便调试CRI,再配置一个crictl客户端:

cat > /etc/crictl.yaml <<EOF runtime-endpoint: unix:///run/containerd/containerd.sock image-endpoint: unix:///run/containerd/containerd.sock timeout: 10 debug: false EOF

这样后面排查问题时,直接crictl ps、crictl images,比每次打一长串ctr -n k8s.io要省事得多。

4. 用kubeadm初始化Kubernetes 1.32.11

4.1 安装kubelet、kubeadm、kubectl

三个二进制文件都放到/usr/local/bin下,然后赋权:

chmod +x /usr/local/bin/kubeadm /usr/local/bin/kubelet /usr/local/bin/kubectl kubeadm version

工作节点也需要这几个二进制,至少kubeadm和kubelet要一致。

给kubelet写一个systemd服务。有一个容易被误导的地方:kubeadm init之前,kubelet其实还没有正确的启动配置,所以服务启动失败是正常的,但systemd服务必须先存在,否则kubeadm初始化阶段无法帮你拉起kubelet。

cat > /etc/systemd/system/kubelet.service <<'EOF' [Unit] Description=Kubernetes Kubelet Documentation=https://github.com/kubernetes/kubernetes After=containerd.service Requires=containerd.service [Service] ExecStart=/usr/local/bin/kubelet Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable --now kubelet

这里先不用纠结--kubeconfig这些参数,kubeadm init后会在/var/lib/kubelet下生成config.yaml、bootstrap-kubelet.conf,并通过drop-in文件把kubelet的实际启动参数补全。我们这里只给systemd一个最简启动入口。

4.2 初始化控制平面

在master节点执行:

kubeadm init \ --kubernetes-version=v1.32.11 \ --control-plane-endpoint=10.10.10.11:6443 \ --pod-network-cidr=192.168.0.0/16 \ --service-cidr=10.96.0.0/12 \ --image-repository=registry.k8s.io \ --image-pull-policy=IfNotPresent \ --cri-socket=unix:///run/containerd/containerd.sock

参数含义过一遍:

  • --kubernetes-version:明确指定版本,防止kubeadm去外网探测最新版。
  • --control-plane-endpoint:控制平面的统一入口,这里直接用master IP。如果不指定,它会默认当前节点的hostname,之后如果多控制平面会麻烦。
  • --pod-network-cidr:Pod网段,必须和后面Calico配置保持一致。
  • --service-cidr:Service网段,只要和物理网络不冲突就行。
  • --image-repository:统一走registry.k8s.io前缀。所有镜像已经离线导入,这一步更多是确保名字标准。
  • --image-pull-policy=IfNotPresent:这是离线环境的关键兜底。告诉kubeadm,本地已有镜像就不要再去远程拉取。少这个参数的话,有些版本即便本地有镜像也会尝试访问远程仓库,然后卡在waiting for control plane。

初始化成功后会输出一大段提示,记得保存最后面的kubeadm 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

这时master节点大概率是NotReady,因为还没有安装CNI网络插件,这是正常的,继续往下走。

4.3 安装Calico网络插件

先把Calico的镜像导入,这里我不再演示导入命令,和前面一样的套路。关键是把calico.yaml里的Pod网段改成和初始化时一致。Calico默认是192.168.0.0/16,如果初始化时用的就是这个,可以直接apply:

kubectl apply -f calico.yaml kubectl get pods -n kube-system -w

正常情况下,calico-node、coredns等Pod在一两分钟内变为Running。如果卡在Init/CrashLoopBackOff,优先看日志:

kubectl logs -n kube-system -l k8s-app=calico-node

我最常遇到的是calico-node报Error: unknown flag: --cluster-type这类版本不匹配,多半是Calico版本和K8s版本兼容问题,换一个更新版本的Calico就好。

4.4 工作节点加入集群

在master节点生成加入命令:

kubeadm token create --print-join-command

输出的命令类似:

kubeadm join 10.10.10.11:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx

在每台工作节点上,先完成上面第2、3步的系统配置和containerd配置,导入同样的K8s镜像、Calico镜像,然后执行join命令。注意工作节点不需要执行kubeadm init,不要搞混。

节点加入后,在master上验证:

kubectl get nodes

所有节点都应显示Ready。如果节点一直NotReady,查看kubelet日志:

journalctl -u kubelet -f

有一种情况比较隐蔽:工作节点上hosts文件和master不一致,join时报could not find the requested Kubernetes endpoint,检查/etc/hosts里的10.10.10.11映射是否写了正确的master hostname。

5. 离线部署KubeSphere可视化平台

5.1 前置准备:StorageClass必须先解决

KubeSphere不是简单一个Deployment,它会有metrics-server、监控组件、审计组件等一大堆要用PVC的东西。如果没有默认StorageClass,大量Pod会在PVC那一步卡住,状态永远是Pending,安装日志里全是waiting for a volume to be created。

离线环境最省事的方案是装一个local-path-provisioner,给每个节点指定一个目录当作本地卷,把local-path设置为默认StorageClass。这个组件只有一个镜像,导出导入都很方便。部署完确认一下:

kubectl get sc

看到local-path的PROVISIONER正常,且storageclass.kubernetes.io/is-default-class: true状态,再继续。

5.2 ks-installer与镜像导入

KubeSphere在已有K8s集群上的安装,通常走ks-installer这条路。提前在联网机器上下载好kubesphere-installer.yaml和cluster-configuration.yaml,这两个文件里的镜像引用很多,最好先提取镜像清单,再逐一把镜像做成tar包:

grep -rh "image:" kubesphere-installer.yaml cluster-configuration.yaml | awk '{print $2}' | sort -u > /data/kubesphere-images.txt

然后在可以联网的机器上循环拉取并导出:

while read img; do skopeo copy docker://$img docker-archive:/data/kubesphere/images/$(basename $img).tar done < /data/kubesphere-images.txt

KubeSphere版本和K8s的兼容性,以官方支持矩阵为准。我在1.32.11上用的是官方离线包里那一版,运行正常,如果你遇到组件版本冲突,优先看官方release说明。

将所有镜像tar包拷入内网后,导入操作还是那句老话:

for img in /data/kubesphere/images/*.tar; do ctr -n k8s.io images import --all-platforms "$img" done

5.3 执行安装并验证

导入完成、StorageClass准备就绪后,依次apply两个yaml:

kubectl apply -f kubesphere-installer.yaml kubectl apply -f cluster-configuration.yaml

安装过程比较长,直接看安装日志:

kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') -f

日志里能看到它在逐项创建CRD、依赖组件、监控组件。等全部安装完成后,访问控制台:

kubectl get svc -n kubesphere-system kubesphere-console

默认端口是30880,访问形如http://10.10.10.11:30880。初始账号一般是admin/P@88w0rd,首次登录会强制改密。如果访问不了,先确认节点防火墙已关闭,再检查kubectl get svc是否绑定了所有IP,NodePort没变化就是端口问题。

KubeSphere安装完成后,看下所有相关Pod:

kubectl get pods -A | grep kubesphere

我建议这一步多留出10分钟观察,不要因为控制台能打开就觉得完成。有些组件还在CrashLoop,比如ks-apiserver内存不足反复重启,就需要调大master节点内存或给系统组件设置requests。

6. 高频故障与排查实录

6.1 containerd和镜像导入问题

镜像导入最常见的错误是archive/tar: invalid tar header,基本是tar包损坏或不是标准docker-archive格式,重新用skopeo导出一次即可。另一个经典问题是K8s报了“Failed to pull image X”但镜像明明已导入过,这时先看ctr -n k8s.io images list | grep X,如果没有结果,说明导入命名空间不对;如果有结果但tag带docker.io/library/前缀,和yaml里写的registry.k8s.io/xxx对不上,用ctr -n k8s.io images tag补一个标准tag。

还有个问题要注意:相同镜像名但digest不同。K8s 1.32默认如果镜像带digest引用,即使tag匹配也可能触发重新拉取。离线场景下尽量确保导入的镜像digest与官方一致,所以制作tar包时用skopeo默认行为就行,不要手动打tag覆盖。

6.2 kubelet与CRI状态异常

节点NotReady时,我基本按这个顺序排查:

kubectl describe node <node-name> journalctl -u kubelet -n 50 -f crictl ps

如果crictl ps报cannot connect to unix:///run/containerd/containerd.sock,多半是containerd崩了或没起来,systemctl status containerd看一眼,然后journalctl -u containerd -e。如果kubelet日志里有failed to pull pause image,回到镜像导入那一步。

cgroup驱动不一致的报错也要记一下:kubelet日志里会有failed to derive cgroup或用kubeadm init时直接提示kubelet cgroup driver=systemd与runtime的cgroup driver不匹配。解决办法就是我上面说的,把containerd的SystemdCgroup=true。这个坑我甚至在线上见过,重新检查完配置、重启containerd就好了。

6.3 网络和KubeSphere问题

Calico Pod起来了但节点仍NotReady,优先看kubectl get pods -n kube-system里calico-node是否Ready。如果Calico报IPv4 address is not configured,说明/etc/hosts没配好或主机名不对。如果跨节点Pod不通,检查sysctl net.ipv4.ip_forward是否为1,防火墙是否彻底关闭。

KubeSphere安装卡住时,先看PVC:

kubectl get pvc -A

除非已经部署了StorageClass,否则这里一定有一堆Pending。另外KubeSphere的配置里可以把一些组件开启或关闭,如果只需要最小可用平台,在cluster-configuration.yaml里把监控、DevOps这些组件关掉,可以省很多资源。组件全开的话,光KubeSphere相关Pod就可能吃掉4G以上内存,节点内存紧张就会各种OOM,表现是ks-console反复重启。

节点token过期是另一个很常见的问题。kubeadm token create --print-join-command生成的新token默认有效期24小时。如果之前是控制平面节点需要加入,证书key也要重新上传:

kubeadm init phase upload-certs --upload-certs

这条命令会打印新的certificate key,配合kubeadm join --control-plane --certificate-key一起用。

在实际操作中我更倾向于把离线部署当作一条“车间流水线”:所有节点先统一跑完系统初始化脚本,再统一安装containerd并导入镜像,最后master先init、节点再join。每一步都单独验证,不要等到最后再一起查问题。这套流程我复用过很多次,只要物料齐、tag对、cgroup一致,基本一遍就能通。装完KubeSphere后再做一次快照,后续重复交付就会非常轻松。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 3:30:45

Node-RED深度魔改:企业级SSO、全链路追踪与自定义节点实战

1. 为什么值得对Node-RED动刀1.1 先给不熟悉的朋友补个背景Node-RED这个名字&#xff0c;玩物联网和自动化的人应该都不陌生。它是IBM开源的一个基于Node.js的流程编排工具&#xff0c;核心操作就是在一个网页编辑器里&#xff0c;把不同类型的节点拖到画布上&#xff0c;用连线…

作者头像 李华
网站建设 2026/9/30 3:30:40

人体姿态估计模型怎么选?9大常用模型对比与选型指南

干这行做人体姿态估计&#xff0c;最常被问到的问题不是"哪个模型最准"&#xff0c;而是"我到底该用哪个"。然后给对方甩一张 COCO 榜单&#xff0c;结果人家根本下不了手。因为榜单上的模型和真正能跑进你业务里的模型&#xff0c;往往不是一回事。我过去…

作者头像 李华
网站建设 2026/9/30 3:30:17

导波光学基础精讲:模式、色散与仿真实践,从理论到代码

简介&#xff1a;《北京理工大学导波光学基础.ppt》是一份面向光学工程、电子信息及物理专业本科高年级或研究生阶段的技术教学课件&#xff0c;系统讲解光波在晶体中传播的核心理论。内容完整覆盖晶体的几何特性与数学描述方法、电光效应与电光调制原理、声光效应与衍射机理、…

作者头像 李华
网站建设 2026/9/30 3:30:16

DeepSeek 当“第二双眼”:小微企业信贷审批交叉验证与动态调分实践

简介&#xff1a;面向银行信贷审批、风控建模与小微金融数字化相关从业者的专业参考文档。围绕 DeepSeek 大模型如何切入小微企业信贷审批优化场景&#xff0c;系统性拆解多维度交叉验证体系、信用评分动态调整机制、非结构化经营数据解析、时序异常检测、特征工程与行业特征嵌…

作者头像 李华
网站建设 2026/9/30 3:30:09

Docker容器内连接数据库删除数据全流程指南与避坑实践

搞过 Docker 部署的朋友应该都有这种经历&#xff1a;项目跑在容器里好好的&#xff0c;突然业务方提了个需求——"帮我把这张表清空一下"、"这个模块的数据要重置"。你第一反应可能是&#xff1a;直接进容器删&#xff1f;然后发现容器删了、镜像重建了&a…

作者头像 李华
网站建设 2026/9/30 3:29:52

HarmonyOS 6图像处理实战:Image Kit与PixelMap全流程指南

1. 先从多媒体处理说起&#xff1a;为什么HarmonyOS 6要把图像处理独立成Kit搞鸿蒙开发这两年&#xff0c;我最大的一个感受是&#xff1a;从HarmonyOS 3到HarmonyOS 6&#xff0c;系统对"能力"的封装方式一直在变。早期的API分散在各种子系统里&#xff0c;开发者想…

作者头像 李华