📖 文章目录


什么是 Kubernetes?

Kubernetes(简称 K8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它最初由 Google 设计,现在由云原生计算基金会(CNCF)维护。K8s 提供了一个强大的平台,能够管理跨多个主机的容器化应用,实现应用的自动化部署、弹性伸缩、服务发现和负载均衡等核心功能。

Kubernetes 的核心价值

  1. 自动化运维:自动部署、回滚、扩缩容应用,减少人工干预
  2. 高可用性:支持多副本部署和故障自动恢复,保障业务连续性
  3. 资源优化:智能调度容器到合适的节点,提高资源利用率
  4. 服务治理:内置服务发现、负载均衡和配置管理能力
  5. 生态丰富:拥有庞大的工具链和社区支持

为什么需要离线部署?

在实际生产环境中,特别是金融、政务、军工等对网络安全有严格要求的领域,服务器通常无法直接访问互联网。离线部署成为必须掌握的技能。针对 Kubernetes 1.24+ 版本,详细讲解在完全离线环境下使用 kubeadm 和 containerd 部署生产级集群的全过程。


⚠ 前置认知:docker images 里有 ≠ K8s 能用
从 K8s 1.24 开始,dockershim 被移除,K8s 只通过 CRI 接口跟 containerd 通信,只会去 containerd 的 k8s.io 命名空间里找镜像。而 Docker 和 containerd 是两套独立的存储:
docker images 看到的镜像 → 存在 Docker 自己的存储里
K8s 通过 containerd 找镜像 → 只看 k8s.io 命名空间
所以即使 docker images 里 10 个镜像全齐,K8s 依然会报 ImagePullBackOff,因为它在 containerd 的 k8s.io 命名空间里啥都没看见。简单说:Docker 里的镜像是给 Docker 用的,K8s 看不见。

1.1 kubeadm 部署的核心分层逻辑

kubeadm 将集群部署拆解为四层依赖,自下而上逐层构建,下层出错上层必然卡死:

层级核心组件作用失败现象
第 1 层系统基础环境内核、防火墙、SELinux、Swap、时间同步预检报错、网络异常、节点失联
第 2 层容器运行时 containerd真正创建运行容器,kubelet 通过 CRI 接口调用它静态 Pod 无法启动,6443 端口无监听,初始化超时
第 3 层kubelet + kubeadm节点代理 + 集群安装工具,kubelet 负责启动所有 Podkubelet 循环崩溃,无法注册节点
第 4 层控制平面 + CNI 网络apiserver/etcd 等核心组件 + Pod 跨节点网络节点 NotReady,Pod 无法通信

版本不兼容 → cgroup 驱动不匹配 → 容器创建失败 → 控制平面起不来 → CNI 装不上 → 节点永远 NotReady。上述问题中的任何一个,都足以导致安装失败

1.2 环境规划

表 1-1 Master 节点环境规划

IP主机名角色部署软件(离线包)服务/组件监听端口端口作用
192.168.30.125k8s-master01control-planecontainerd、kubeadm、kubelet、kubectl、etcd、CoreDNS、Calicokube-apiserverTCP 6443Kubernetes API Server
etcdTCP 2379-2380etcd 客户端通信
kube-schedulerTCP 10259调度器自身健康/metrics
kube-controller-managerTCP 10257控制器自身健康/metrics
kubeletTCP 10250Kubelet API
Calico BIRDTCP 179BGP 路由交换(Calico 默认)

表 1-2 Node01 节点环境规划

IP主机名角色部署软件(离线包)服务/组件监听端口端口作用
192.168.30.126k8s-node01workercontainerd、kubeadm、kubelet、kubectl、Calico 镜像、业务镜像kubeletTCP 10250Kubelet API
kube-proxyTCP 10256kube-proxy 健康检查
Calico BIRDTCP 179BGP 路由交换
NodePort ServiceTCP 30000-32767对外暴露的业务服务端口

表 1-3 Node02 节点环境规划

IP主机名角色部署软件(离线包)服务/组件监听端口端口作用
192.168.30.127k8s-node02workercontainerd、kubeadm、kubelet、kubectl、Calico 镜像、业务镜像kubeletTCP 10250Kubelet API
kube-proxyTCP 10256kube-proxy 健康检查
Calico BIRDTCP 179BGP 路由交换
NodePort ServiceTCP 30000-32767对外暴露的业务服务端口

⚠️ 离线部署核心约束:所有节点的镜像都必须提前导入到 containerd 的 k8s.io namespace,否则 kubelet 看不到镜像会陷入 ImagePullBackOff。docker images 里有镜像 ≠ K8s 能用——K8s 1.24 起移除了 dockershim,只通过 CRI 接口在 containerd 的 k8s.io 命名空间里找镜像。


1.3 全流程分步详解(1 主 2 从 + containerd + Calico + 离线环境)

所有操作严格区分「所有节点执行」和「仅 Master 执行」,按顺序操作。

1.3.1 阶段 1:所有节点通用系统初始化(必须先做)

前置
依赖包下载地址:

https://download.csdn.net/download/qq_44769717/93227487

解压到/opt目录下

tar -xvzf k8s-offline-full.tar.gz 

1. 主机名与域名解析

集群内节点名必须唯一,且所有节点能通过主机名互相通信:

# Master 执行
hostnamectl set-hostname k8s-master01
# Node1 执行
hostnamectl set-hostname k8s-node01
# Node2 执行
hostnamectl set-hostname k8s-node02

# 所有节点配置 hosts 解析
cat >> /etc/hosts << EOF
192.168.30.125 k8s-master01
192.168.30.126 k8s-node01
192.168.30.127 k8s-node02
EOF

解读:cat >> /etc/hosts << EOF 以追加方式写入本地 DNS 解析。离线环境没有 DNS 服务器,集群内节点互访(如 etcd 选主、kubelet 注册)全靠 hosts 解析,三条记录每个节点都必须有。

连通性测试脚本(完整版):

# 测试所有节点主机名解析和网络连通性
for node in k8s-master01 k8s-node01 k8s-node02; do
    echo "=== 测试节点: $node ==="

    # 测试主机名解析
    echo -n "主机名解析: "
    if ping -c 1 -W 1 $node > /dev/null 2>&1; then
        echo "✓ 成功"
    else
        echo "✗ 失败"
    fi

    # 获取对应 IP 并显示
    ip=$(grep "$node" /etc/hosts | awk '{print $1}')
    echo "对应 IP: $ip"

    # 测试 IP 连通性
    echo -n "IP 连通性: "
    if ping -c 1 -W 1 $ip > /dev/null 2>&1; then
        echo "✓ 成功"
    else
        echo "✗ 失败"
    fi

    # 显示 hosts 文件中的条目
    echo -n "hosts 记录: "
    grep "$node" /etc/hosts || echo "未找到"
    echo ""
done

# 额外验证:反向测试(从当前节点到各节点)
echo "=== 当前节点到其他节点的连通性 ==="
current_host=$(hostname)
echo "当前节点: $current_host"

for ip in 192.168.30.125 192.168.30.126 192.168.30.127; do
    echo -n "连接到 $ip: "
    if ping -c 1 -W 1 $ip > /dev/null 2>&1; then
        echo "✓ 可达"
    else
        echo "✗ 不可达"
    fi
done

# 验证主机名唯一性
echo ""
echo "=== 验证主机名唯一性 ==="
echo "集群节点主机名:"
for node in k8s-master01 k8s-node01 k8s-node02; do
    echo "$node"
done

解读:ping -c 1 -W 1 表示只发 1 个包、超时 1 秒,适合批量快速探测;脚本依次验证「主机名能否解析 → 解析出的 IP 是否正确 → IP 是否可达」三个层面,任何一环失败都会在后续 kubeadm 预检中暴露。

连通性测试脚本(简化版,更实用):

echo "开始测试集群节点连通性..."
for node in k8s-master01 k8s-node01 k8s-node02; do
  printf "%-15s %-20s" "$node" "$(grep $node /etc/hosts | awk '{print $1}')"
  if ping -c 1 -W 1 $node > /dev/null 2>&1; then
    echo "✓ 连通正常"
  else
    echo "✗ 无法连通"
  fi
done

# 验证 hosts 配置完整性
echo ""
echo "hosts 文件配置验证:"
cat /etc/hosts | grep -E "k8s-master01|k8s-node01|k8s-node02"

故障排查提示:

  1. ping 失败:检查网络接口 ip addr、防火墙 systemctl status firewalld、路由表 ip route
  2. 主机名解析失败:检查 /etc/hosts 文件权限、DNS 配置 cat /etc/resolv.conf

2. 关闭防火墙与 SELinux

# 关闭防火墙并禁用开机自启
systemctl stop firewalld
systemctl disable firewalld

# 临时关闭 SELinux
setenforce 0
# 永久关闭 SELinux
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config

解读:

  • stop 立即停止防火墙,disable 取消开机自启,两条都要执行。firewalld 会拦截节点间 6443、10250、Calico BGP(179)等端口通信,生产环境通常用安全组/iptables 精细管控而非直接开防火墙。
  • setenforce 0 让 SELinux 当前立即进入 permissive 模式(不重启生效);sed 修改配置文件保证重启后依然关闭。SELinux 开启时会阻止 kubelet 读取容器文件、挂载卷,是高频报错源。

3. 永久关闭 Swap

K8s 官方强制要求关闭 Swap,否则 kubelet 无法正常工作(不要用 --ignore-preflight-errors=Swap 跳过,属于隐患):

# 临时关闭
swapoff -a
# 永久关闭(注释 fstab 中的 swap 行)
sed -i '/ swap/ s/^\(.*\)$/#\1/g' /etc/fstab

解读:swapoff -a 关闭当前所有 swap 分区;sed 把 /etc/fstab 中含 swap 的行行首加 # 注释掉,防止重启后 swap 自动挂载。K8s 设计假设内存不足时直接驱逐 Pod 而不是用 swap 硬撑,开 swap 会导致调度器资源计算失真。

4. 加载内核模块与网络参数

这是 CNI 网络、Service 转发的底层基础,没开启会导致 Pod 网络完全不通:

# 加载网桥过滤模块
modprobe br_netfilter
modprobe overlay

# 写入永久配置
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

解读:

  • br_netfilter:让网桥流量能经过 iptables 过滤,是 Service(kube-proxy)转发和 Calico 策略生效的前提;overlay:containerd 使用 overlayfs 存储驱动的依赖。modprobe 仅当前生效,建议配合 /etc/modules-load.d/k8s.conf 持久化。
  • bridge-nf-call-iptables=1:二层网桥流量也走 iptables 规则,否则 Service 的 ClusterIP 转发失效;ip_forward=1:开启 IPv4 路由转发,Pod 跨节点通信必备。
  • sysctl --system 重新加载 /etc/sysctl.d/ 下所有配置文件,使参数立即生效且重启保留。

5. 时间同步

集群证书、etcd 对时间差极度敏感,偏差超过 5 分钟会出现认证失败:

# 启动 chronyd 服务
systemctl start chronyd
# 设置 chronyd 开机自启
systemctl enable chronyd
# 查看服务状态(可选,确认 Active 状态)
systemctl status chronyd --no-pager

解读:所有节点都必须执行,保证开机自启。chrony 是 CentOS 7 默认的 NTP 客户端,--no-pager 直接输出状态不进入分页模式,方便脚本化查看。

6.时区设置

Kubernetes 集群通常要求统一使用 UTC 或统一的本地时区。在中国,通常设置为 Asia/Shanghai:

# 设置系统时区为上海(东八区)
timedatectl set-timezone Asia/Shanghai

# 查看当前时区设置
timedatectl status | grep "Time zone"

解读:统一时区避免日志、证书有效期、CronJob 调度出现时区错乱。

时间同步状态验证——这是最关键的一步,需要确认时间不仅正确,而且确实在同步。

#方法一:使用 chronyc 检查(推荐,最直接的方式)
# 1. 查看时间同步源
chronyc sources -v
# 2. 查看时间同步状态(核心指标)
chronyc tracking        # Leap status 应为 Normal,Last offset 越小越好

关键指标解读(chronyc tracking):

  • Reference ID:显示当前同步的时间服务器地址。如果是 203.107.6.88(阿里云)或 216.239.35.0(Google),说明正在同步公网时间。
  • Stratum:层级。通常显示 3 或 4 是正常的(离基准时钟越近数字越小)。
  • Last offset:最后一次同步的偏移量。这个值越小越好(通常在毫秒级别,如 0.000123)。
  • RMS offset:偏移量的均方根。
  • Leap status:应该是 Normal。
#方法二:使用 timedatectl 检查
timedatectl status      # 必须满足:NTP enabled: yes、NTP synchronized: yes

验证要点(必须全部满足):

  • NTP enabled: yes
  • NTP synchronized: yes(这是最关键的指标,表示已成功同步)
  • System clock synchronized: yes
  • Time zone: Asia/Shanghai
  • RTC in local TZ: no(建议设为 no,避免双系统时间错乱)
#方法三:集群内多节点一致性校验(For 循环)
# 在所有节点上执行,查看时间是否一致
for node in k8s-master01 k8s-node01 k8s-node02; do
	echo -n "$node 时间: "
	ssh $node "date '+%Y-%m-%d %H:%M:%S'"
done

1.3.2 阶段 2:所有节点部署 containerd 容器运行时

在 Kubernetes 集群里,master 和 node 都是"节点",都需要一个符合 CRI 标准的容器运行时来干活:

  • Master:运行 API Server、Scheduler、Controller Manager 等控制面组件(它们本身也是容器)
  • Node:运行业务 Pod + 网络插件(Calico 等)的 Pod

两者都离不开 containerd,所以这套步骤 node 节点要原封不动地再来一遍。

💡 简单理解:K8s 集群里除了 kubeadm init(只在 master 跑一次)和 kubeadm join(node 加入集群)这种"集群级"操作有主次之分外,容器运行时、kubelet 这类"节点级"组件,是每个节点都要独立安装的。

为什么 node 节点一样不能少:

组件Master 需要Node 需要说明
containerd✅✅CRI 运行时,跑容器就离不开
配置 SystemdCgroup=true✅✅kubelet 默认 systemd 驱动,不统一就沙箱创建失败
本地 pause 镜像✅✅每个 Pod 都有一个 pause 沙箱容器
导入离线镜像✅✅Calico 等网络插件的 Pod 会被调度到 node 上跑

"cgroup 驱动不统一导致沙箱创建失败"的坑——node 节点如果不改 SystemdCgroup = true,照样会踩。所以这套配置在 node 上是必选项,不是可选项。

1. 安装 containerd

假设已通过 U 盘/内网仓库把 rpm 包和离线镜像 tar 包拷贝到了/opt节点上并解压(统一放在 /opt/k8s-offline/rpms 目录)。

# 进入离线 rpm 包目录
cd /opt/k8s-offline/rpms

# 本地安装 containerd(yum 自动处理包间依赖)
yum localinstall -y containerd.io-1.6.21-3.1.el7.x86_64.rpm \
                    container-selinux-2.119.2-1.911c772.el7_8.noarch.rpm

解读:

  • 使用 yum localinstall 替代 rpm -ivh,优势是 yum 会自动解析本地 rpm 包之间的依赖关系(containerd.io 依赖 container-selinux),避免 rpm -ivh 手动补依赖时报 Failed dependencies 的麻烦;-y 自动确认,适合批量脚本化。
  • 离线环境下 yum localinstall 只解析命令行中给出的本地包,不会去连公网仓库。

安装后先确认版本:

rpm -qa | grep containerd
containerd --version

预期输出:

[root@k8s-node01 rpms]# rpm -qa | grep containerd
containerd.io-1.6.21-3.1.el7.x86_64
[root@k8s-node01 rpms]# containerd --version
containerd containerd.io 1.6.21 3dce8eb055cbb6872793272b4f20ed16117344f8

解读:

  • 如果输出是 containerd.io-1.6.21-3.1.el7.x86_64,说明版本完全匹配,直接往下走。
  • 如果输出是更高版本(比如 1.6.28、1.6.33 之类),也没问题,containerd 已经在了,同样往下走即可。
  • 只有在版本不对且想严格锁定 1.6.21 时,才需要先卸载再重装。
  • 📌 离线部署 K8s 1.24+ 用 1.6.x 系列的 containerd 都没问题,不必纠结必须是 1.6.21。

2. 生成并修改核心配置(重中之重)

containerd 装好后,/etc/containerd/config.toml 默认是不存在的,需要手动生成:

# 创建配置目录并生成默认配置
mkdir -pv /etc/containerd
containerd config default > /etc/containerd/config.toml

# 关键 1:cgroup 驱动统一为 systemd(不改必踩坑)
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/containerd/config.toml

# 关键 2:指定本地 pause 镜像(离线环境必须改)
sed -i 's#sandbox_image=".*"#sandbox_image="registry.k8s.io/pause:3.7"#g' /etc/containerd/config.toml

# 验证修改生效
grep -E "SystemdCgroup|sandbox_image" /etc/containerd/config.toml
#如果不是3.7 则编辑文件/etc/containerd/config.toml 第61行进行修改

应看到:SystemdCgroup = true 和 sandbox_image="registry.k8s.io/pause:3.7"。

⚠️ pause:3.7 必须和离线导入的 pause 镜像版本完全一致。如果离线包里是 pause:3.6 或 3.8,这里也要跟着改,否则启动 Pod 时会去公网拉镜像导致超时。

3. 启动服务并设置开机自启

systemctl daemon-reload
systemctl restart containerd
systemctl enable containerd

#再次验证修改生效
grep -E "SystemdCgroup|sandbox_image" /etc/containerd/config.toml

4. 导入离线镜像到 k8s.io 命名空间(离线环境专属坑)

# 业务基础镜像
ctr -n k8s.io images import /opt/k8s-offline/k8s-base-images.tar
# Calico 网络插件镜像
ctr -n k8s.io images import /opt/k8s-offline/calico-images.tar

# 验证
ctr -n k8s.io images list

⚠️ -n k8s.io 绝对不能省。省了会导入到 default 命名空间,K8s 看不见;用 docker load 导入同样无效。

5. 确认 containerd 健康

systemctl status containerd   # 应为 active (running)
ctr version                   # 能看到 client 和 server 版本

1.3.3 阶段 3:所有节点安装 K8s 核心三件套

注意:做到这一阶段建议打个快照,以防后续出错

安装 kubelet(节点代理)、kubeadm(集群安装工具)、kubectl(命令行客户端)。kubelet 与控制平面版本偏差不能超过官方支持的 ±1 个小版本。

1. 安装指定版本

cd /opt/k8s-offline/rpms

yum localinstall -y \
    kubernetes-cni-1.1.1-0.x86_64.rpm \
    cri-tools-1.24.0-0.x86_64.rpm \
    *kubelet-1.24.17*.rpm \
    *kubeadm-1.24.17*.rpm \
    *kubectl-1.24.17*.rpm

💡 说明:yum 不支持 --nodeps。如果安装时卡在 kubernetes-cni 依赖上,把离线包里的 kubernetes-cni-*.rpm 放到同一目录一并 yum localinstall(推荐;Calico 后续会自带 CNI 二进制,装上不影响)。

2. 设置 kubelet 开机自启

systemctl enable kubelet

✅ 此时 kubelet 循环重启属于正常现象:它还没有配置文件,在等待 kubeadm 生成配置,集群初始化完成后会自动恢复正常。

3. 验证版本一致性

kubelet --version
kubeadm version
kubectl version --client

三者必须全部为 v1.24.17,差一个版本都不要继续。

1.3.4 阶段 4:仅 Master 节点执行集群初始化

1. 初始化前确认(仅当之前 init 失败过)

必须先重置干净,否则会报端口占用、文件已存在:
注意:ipvsadm -C要安装ipvsadm才可以使用

kubeadm reset -f
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
ipvsadm -C 
rm -rf /etc/kubernetes /var/lib/etcd /var/lib/kubelet $HOME/.kube

2. 执行初始化命令

# 先安装conntrack-tools
cd /opt/k8s-offline/rpms
yum localinstall -y conntrack-tools-1.4.4-7.el7.x86_64.rpm

kubeadm init \
  --apiserver-advertise-address=192.168.30.125 \
  --kubernetes-version=v1.24.17 \
  --service-cidr=10.96.0.0/12 \
  --pod-network-cidr=10.244.0.0/16 \
  --image-repository=registry.k8s.io \
  --cri-socket=unix:///run/containerd/containerd.sock

核心参数说明:

  • --apiserver-advertise-address:apiserver 对外宣告的 IP,必须是节点本机 IP(192.168.30.125)
  • --pod-network-cidr:Pod 的 IP 网段,必须和后续 Calico 配置的网段完全一致。注意:原文档为 192.168.0.0/16,与本次节点网段 192.168.30.0/24 冲突,已改为 10.244.0.0/16
  • --cri-socket:指定 containerd 的 CRI 套接字,不指定会找不到运行时
  • 不要加 --ignore-preflight-errors=all,预检报错就是在提前提醒问题

初始化成功后会输出 kubeadm join 192.168.30.125:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx,请保存好该命令备用。

3. 初始化执行流程拆解

kubeadm init 内部按顺序执行 6 步,卡在哪一步就对应哪一层问题:

  1. 预检阶段:检查系统环境、版本、运行时 → 报错对应阶段 1/2/3
  2. 拉取镜像:拉取控制平面镜像 → 报错对应镜像不存在
  3. 证书生成:生成所有集群证书 → 报错对应主机名/IP 配置错误
  4. 配置 kubelet:写入 /var/lib/kubelet/config.yaml
  5. 启动静态 Pod:kubelet 启动 etcd、apiserver、控制器、调度器
  6. 等待控制平面就绪:等待 6443 端口可用 → 超时 90% 是容器创建失败(cgroup 驱动/镜像问题)

1.3.5 阶段 5:配置 kubectl 与验证控制平面(仅 Master)

1. 配置管理员权限

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

2. 验证控制平面

kubectl get pods -n kube-system

正常输出:etcd、kube-apiserver、kube-controller-manager、kube-scheduler 四个静态 Pod 全部 Running。

✅ 此时节点状态为 NotReady 是正常中间状态:还没有部署 CNI 网络插件,kubelet 认为节点网络未就绪。


1.3.6 阶段 6:部署 Calico CNI 网络插件(最容易卡壳的一步)

⚠️ 死循环坑:节点 NotReady → 自带 node.kubernetes.io/not-ready 污点 → Pod 无法调度 → 装不上 CNI → 永远 NotReady。

1. 破局:移除 Master 节点污点

单主集群推荐直接移除 Master 的调度污点,让网络组件可以调度上去,解开死循环:

kubectl taint nodes k8s-master01 node-role.kubernetes.io/master-

末尾的 - 是固定语法,代表删除该污点。

2. 修改并部署 Calico 配置

离线环境确保:yaml 文件是标准 K8s 资源定义(不能是下载错的 HTML 网页);Calico 镜像已导入 containerd 的 k8s.io 命名空间;网段和 --pod-network-cidr 一致。

# 删除旧的calico.yaml,把新的calico.yaml放在/opt/k8s-offline这个目录当中
# 新的calico.yaml以存放在资源包当中


kubectl apply -f /opt/k8s-offline/calico.yaml

3. 监控启动状态

kubectl get pods -n kube-system -w

等待 calico-node-xxx 和 calico-kube-controllers-xxx 全部变为 Running。

4. 验证节点就绪

kubectl get nodes

正常输出:k8s-master01 状态变为 Ready。


1.3.7 阶段 7:Worker 节点加入集群

Worker 节点必须提前做完「阶段 1 ~ 阶段 3」的所有操作,否则加入会失败。

1. Master 节点生成加入命令

kubeadm token create --print-join-command

2. Worker 节点(192.168.30.126、192.168.30.127)执行加入命令

必须追加 --cri-socket 参数,适配 containerd 运行时(替换为实际的 token 和 hash):

kubeadm join 192.168.30.125:6443 --token xxx \
  --discovery-token-ca-cert-hash sha256:xxx \
  --cri-socket=unix:///run/containerd/containerd.sock

# 直接复制Master生成的Token和sha256(生成的就是以上格式,可以直接使用)到30.126和30.127即可

3. Master 验证节点加入

kubectl get nodes -w

两台 Worker 节点会自动调度 calico-node Pod,随后依次变为 Ready。


1.3.8 阶段 8:集群最终验收

# 1. 所有节点状态为 Ready
kubectl get nodes -o wide

# 2. 所有系统 Pod 正常运行
kubectl get pods -n kube-system

# 3. 创建测试 Pod 验证网络
kubectl run test-nginx --image=nginx
kubectl get pods -o wide

1.4 常见踩坑汇总

序号问题说明
1版本不兼容kubelet 与控制平面版本差超过 ±1 个小版本,直接不兼容
2cgroup 驱动不统一containerd 用 cgroupfs、kubelet 用 systemd,导致 runc 无法创建容器,控制平面静态 Pod 全部启动失败
3镜像命名空间错误离线镜像未导入 k8s.io 命名空间,K8s 识别不到镜像
4Calico 文件错误下载的 yaml 实际是镜像站的 HTML 网页,不是 K8s 资源清单
5调度死循环Master 节点污点 + NotReady 污点,导致 CNI Pod 无法调度,节点永远 NotReady
6中断残留中途 Ctrl+C 终止初始化,端口和文件残留,导致下次 init 直接报错
7未指定 CRI 套接字kubelet 无法自动识别 containerd,对接不上运行时
8Pod 网段与节点网段冲突节点为 192.168.30.0/24 时不能再使用 192.168.0.0/16 作为 Pod 网段

1.5.部署流程步骤预览

下表汇总了从零开始部署一个 1 主 2 从 Kubernetes 集群的核心步骤,便于快速回顾:

阶段步骤名称执行节点核心操作关键产出/验证
阶段 1系统初始化所有节点主机名、hosts、防火墙、Swap、内核参数、时间同步节点间网络互通,系统参数符合 K8s 要求
阶段 2部署容器运行时所有节点安装并配置 containerd,导入离线镜像containerd --version 正常,ctr -n k8s.io images list 有镜像
阶段 3安装 K8s 核心组件所有节点安装 kubelet、kubeadm、kubectl,并设置开机自启kubelet --version、kubeadm version、kubectl version --client 均为 v1.24.17
阶段 4初始化 Master 节点仅 Master执行 kubeadm init,指定 Pod 网段和 CRI 套接字获得 kubeadm join 命令,控制平面 Pod 全部 Running
阶段 5配置 kubectl仅 Master复制 admin.conf 到 ~/.kube/configkubectl get pods -n kube-system 可列出控制平面 Pod
阶段 6部署 CNI 网络插件仅 Master移除 Master 污点,应用 Calico YAMLkubectl get nodes 显示 Master 状态为 Ready
阶段 7Worker 节点加入集群仅 Worker在各 Worker 节点执行 kubeadm join 命令kubectl get nodes 显示所有节点状态为 Ready
阶段 8集群验收仅 Master检查节点状态、系统 Pod 并创建测试应用测试 Pod 可正常调度、运行并具备网络通信能力

提示:此表格为快速指引,具体操作细节、命令参数及避坑要点请参考上文各章节详细说明。

更多推荐