Skip to content

Ubuntu 环境离线安装 Kubernetes v1.33.0 三节点集群详细指南

本文档适用于 Ubuntu 20.04/22.04 + containerd 环境。网络插件以 Flannel 为例,其他插件如 Calico 可类似操作。

一、准备工作

1. 三台服务器

  • 主机名建议:master、node1、node2
点击查看更多相关说明

使用 hostnamectl 工具配置主机名,例如,将主节点设置为 master

terminal
shell
hostnamectl set-hostname master

⚠️ 注意:重启后生效,请依次修改三台服务器的主机名!

  • 配置静态 IP
点击查看更多相关说明

通过编辑 /etc/netplan/00-installer-config.yaml 网卡配置文件进行修改,例如:

shell
# This is the network config written by 'subiquity'
network:
  ethernets:
    ens160:
      addresses:
      - 192.168.0.160/24
      gateway4: 192.168.0.1
      nameservers:
        addresses:
          - 8.8.8.8
          - 8.8.4.4
  version: 2

修改之后执行 netplan apply 即可生效!


⚠️ 如果通过 ssh 连接,执行 netplan apply 之后连接将会断开连接,会产生卡死的现象,关闭终端另开启一个即可!

  • 配置静态 IP、主机名、互相 /etc/hosts
  • 关闭防火墙
点击查看更多相关说明
terminal
shell
sudo systemctl disable --now ufw

这将关闭防火墙并禁用开机自动引导启动

  • 永久关闭交换分区
点击查看更多相关说明
terminal
shell
sudo sed -ri 's/.*swap.*/#&/' /etc/fstab

重启之后通过以下命令检查输出是否为空

terminal
shell
swapon --show
  • 如果 没有输出,说明当前没有启用的 Swap。
  • 如果有输出,说明仍有 Swap 设备或文件在运行。
  • 修改内核参数,允许桥接防火墙及IP转发
点击查看更多相关说明

编辑系统配置文件

编写 /etc/sysctl.conf 配置文件,取消 net.ipv4.ip_forward=1 前面的注释保存即可

/etc/sysctl.conf
txt
net.ipv4.ip_forward=1

重新加载配置(无需重启)

terminal
shell
sudo sysctl -p
  • 启用 cgroups 到 v2 版本
点击查看更多相关说明

步骤 1:启用 cgroups v2 并禁用 v1

修改 /etc/default/grub 文件,修改 GRUB_CMDLINE_LINUX 行,添加以下参数

/etc/default/grub
toml
GRUB_CMDLINE_LINUX="systemd.unified_cgroup_hierarchy=1 cgroup_no_v1=all"

更新 GRUB 并重启

terminal
shell
sudo update-grub && sudo reboot

步骤 2:验证切换结果

重启之后进行启用 cgroups v2版本验证

terminal
shell
mount | grep cgroup

预期输出应仅剩 cgroup2 挂载点:

txt
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)

2. SSH 免密登录

  • 写入 dns 记录
点击查看更多相关说明

在 Kubernetes 待安装服务器写入 dns 记录,注意是有几台写入几台!

shell
echo '192.168.0.160 master' >> /etc/hosts
echo '192.168.0.161 node1' >> /etc/hosts
echo '192.168.0.162 node2' >> /etc/hosts

提醒

待安装的 Kubernetes 集群有几台服务器,就在这些服务器上依次操作!

  • 配置免密传输
点击查看更多相关说明

生成 ssh 公私对

terminal
shell
ssh-keygen  #一路回车,不输入密码

在 Kubernetes 待安装服务器写入 dns 记录,有几台服务器就拷贝到几台!

terminal
shell
ssh-copy-id master
ssh-copy-id node1
ssh-copy-id node2

ssh-copy-id

ssh-copy-id 是一个用于将本地用户的公钥(默认是 ~/.ssh/id_rsa.pub)复制到远程目录主机的 ~/.ssh/authorized_keys 文件中的命令。
从而实现无需密码的 SSH 登录,后续通过 ssh node1 登录时,系统会直接使用密钥认证,无需手动输入密码。

提醒

待安装的 Kubernetes 集群有几台服务器,就在这些服务器上依次操作!理论上当前主机无需拷贝当前主机哦!

3. 修改内核参数

允许桥接防火墙及IP转发,否则 Kubernetes 集群可能会遇到网络问题。

点击查看更多相关说明
  1. 手动加载 br_netfilter 模块
terminal
shell
sudo modprobe br_netfilter

验证是否加载成功:

terminal
shell
lsmod | grep br_netfilter  # 应返回 br_netfilter 相关行
  1. 修改 /etc/sysctl.conf
terminal
shell
sudo tee /etc/sysctl.d/99-kubernetes.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
  1. 应用配置
terminal
shell
sudo sysctl --system  # 加载所有 sysctl 配置(包括 /etc/sysctl.d/)

验证是否生效:

terminal
shell
sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward

输出应均为 1

4. 配置时间同步

点击查看更多相关说明

如果使用 VMWare ESXi 虚拟化,可以通过 Web 管理界面进行配置时间同步,主机 -> 管理 -> 系统 -> 时间和日期,点击 编辑设置 在弹出的对话框中选择 使用网络时间协议(启用 NTP 客户端)NTP 服务器 输入 pool.ntp.org 点击保存即可!

登录到服务器,输出 timedatectl 命令,查看当前服务器本地时间是否正确

terminal
shell
timedatectl

将输出类似如下的时间信息

text
               Local time: Mon 2025-06-23 13:38:18 UTC
           Universal time: Mon 2025-06-23 13:38:18 UTC
                 RTC time: Mon 2025-06-23 13:38:18
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

可以看到本地时间并不正确,需要修改时区

terminal
shell
timedatectl set-timezone Asia/Shanghai

再输入 timedatectl 验证即可

txt
               Local time: Mon 2025-06-23 21:42:25 CST
           Universal time: Mon 2025-06-23 13:42:25 UTC
                 RTC time: Mon 2025-06-23 13:42:26
                Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

现在本地时间也就对上了!

5. 安装 IPVS

点击查看更多相关说明

安装 IPVS 内核模块

terminal
shell
apt install -y ipset ipvsadm

加载内核模块

terminal
shell
sudo modprobe ip_vs ip_vs_rr ip_vs_wrr ip_vs_sh

查看内核加载 ip_vs

terminal
shell
lsmod | grep ip_vs

检查 IPVS 规则

terminal
shell
sudo ipvsadm -L

提醒

kubernetes 安装完全后,可以使用 kube-proxy 使用 IPVS

shell
kubectl edit cm -n kube-system kube-proxy

修改 proxy-mode 为 ipvs:

yaml
mode: "ipvs"

第一阶段:在有网络的环境中准备离线安装包

1. 设置下载环境

切换到普通用户

shell
su testify

提醒

Ubuntu 系统安装时都有一个默认用户,也就是切换到安装系统时创建的用户,其它用户也可以,只要是非 root 用户即可!如果使用 root 下载软件包会存在权限警告问题!W: Download is performed unsandboxed as root as file

创建工作目录

terminal
shell
mkdir -p ~/k8s-offline/v1.33.0

提醒

可以一直保持在家目录($HOME)完成准备离线安装包的相关操作!

安装必要工具

terminal
shell
sudo apt-get update && sudo apt-get install -y apt-transport-https curl gnupg

2. 添加 Kubernetes apt 源

1. 创建 keyrings 目录(如果不存在)

terminal
shell
sudo mkdir -p /etc/apt/keyrings

2. 下载并添加 GPG 密钥

terminal
shell
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

3. 添加 Kubernetes apt 源

terminal
shell
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

4. 更新 apt 缓存

terminal
shell
sudo apt-get update

3. 下载 Kubernetes 组件

创建下载目录

terminal
shell
DOWNLOAD_DIR="$HOME/k8s-offline/v1.33.0/deb-packages/kubernetes"
mkdir -p $DOWNLOAD_DIR

下载指定版本的 kubeadm, kubelet 和 kubectl

terminal
shell
apt-get download \
  kubelet=1.33.0-1.1 \
  kubeadm=1.33.0-1.1 \
  kubectl=1.33.0-1.1

下载依赖包

terminal
shell
apt-get download \
  conntrack \
  ebtables \
  socat \
  ethtool \
  ipset \
  nfs-common \
  libseccomp2 \
  libltdl7 \
  libnfsidmap2 \
  libipset13 \
  libtirpc3 \
  libtirpc-common \
  rpcbind \
  keyutils \
  cri-tools \
  kubernetes-cni

移动所有 .deb 文件到下载目录

terminal
shell
mv *.deb $DOWNLOAD_DIR

4. 下载容器运行时组件

创建下载目录

terminal
shell
DOWNLOAD_DIR="$HOME/k8s-offline/v1.33.0/deb-packages/cri"
mkdir -p $DOWNLOAD_DIR

下载指定版本的 docker.io

shell
apt-get download docker.io=26.1.3-0ubuntu1~20.04.1

提醒

Kubernetes v1.33.0 默认使用 containerd 作为容器运行时并不需要安装 docker.io 即可。

下载指定版本的 containerd

shell
apt-get download containerd=1.7.24-0ubuntu1~20.04.2

下载依赖包

terminal
shell
apt-get download runc

移动所有 .deb 文件到下载目录

terminal
shell
mv *.deb $DOWNLOAD_DIR

5. 下载网络插件(Calico)配置文件

指定下载目录

terminal
shell
DOWNLOAD_DIR="$HOME/k8s-offline/v1.33.0/manifests"
mkdir -p $DOWNLOAD_DIR
terminal
shell
wget -c https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/calico.yaml \
 -O $DOWNLOAD_DIR/calico.yaml

6. 下载容器镜像

先安装 kubeadm(在线环境)

terminal
shell
sudo apt-get install -y kubelet=1.33.0-1.1 kubeadm=1.33.0-1.1 kubectl=1.33.0-1.1
sudo apt-mark hold kubelet kubeadm kubectl  # 锁定版本

安装 Docker

terminal
shell
sudo apt-get install -y docker.io
sudo systemctl start docker

配置 Docker 国内镜像源

点击查看更多相关说明
  1. 创建或修改 Docker 配置文件 如果不存在 /etc/docker/daemon.json,vim 自动创建它;如果已存在,直接编辑:

    bash
    sudo vim /etc/docker/daemon.json
  2. 添加镜像源配置 将以下内容写入文件(以阿里云镜像为例,其他源见附录):

    json
    {
      "registry-mirrors": ["https://<your-mirror-url>.mirror.aliyuncs.com"]
    }
  3. 重启 Docker 服务

    bash
    sudo systemctl daemon-reload
    sudo systemctl restart docker
  4. 验证配置

    bash
    sudo docker info | grep "Registry Mirrors" -A 1

    如果看到配置的镜像地址,说明成功。

可尝试是否可用的镜像源

配置 Docker 使用代理

点击查看更多相关说明

如果配置了上面的国内镜像源还是行的话直接配置代理

创建或编辑 Docker 服务配置

创建配置目录

terminal
shell
sudo mkdir -p /etc/systemd/system/docker.service.d

添加配置文件

terminal
shell
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=http://192.168.0.23:7890"
Environment="HTTPS_PROXY=http://192.168.0.23:7890"
Environment="NO_PROXY=localhost,127.0.0.1,.docker.io,.aliyuncs.com"
EOF

重新加载并重启 Docker

terminal
shell
sudo systemctl daemon-reload && sudo systemctl restart docker

测试下载镜像

shell
sudo docker pull nginx:latest

列出 Kubernetes v1.33.0 所需镜像

terminal
shell
sudo kubeadm config images list --kubernetes-version=v1.33.0

这将输出 Kubernetes v1.33.0 所需的所有镜像版本

txt
registry.k8s.io/kube-apiserver:v1.33.0
registry.k8s.io/kube-controller-manager:v1.33.0
registry.k8s.io/kube-scheduler:v1.33.0
registry.k8s.io/kube-proxy:v1.33.0
registry.k8s.io/coredns/coredns:v1.12.0
registry.k8s.io/pause:3.10
registry.k8s.io/etcd:3.5.21-0

拉取 Kubernetes v1.33.0 镜像

terminal
shell
images=(
  registry.k8s.io/kube-apiserver:v1.33.0
  registry.k8s.io/kube-controller-manager:v1.33.0
  registry.k8s.io/kube-scheduler:v1.33.0
  registry.k8s.io/kube-proxy:v1.33.0
  registry.k8s.io/coredns/coredns:v1.12.0
  registry.k8s.io/pause:3.10
  registry.k8s.io/etcd:3.5.21-0
)

for image in "${images[@]}"; do
  sudo docker pull $image
done

保存 Kubernetes v1.33.0 镜像为 tar 文件

创建镜像存储目录

terminal
shell
mkdir -p $HOME/k8s-offline/v1.33.0/images

导出镜像到归档文件

terminal
shell
sudo docker save -o $HOME/k8s-offline/v1.33.0/images/k8s-images.tar \
  registry.k8s.io/kube-apiserver:v1.33.0 \
  registry.k8s.io/kube-controller-manager:v1.33.0 \
  registry.k8s.io/kube-scheduler:v1.33.0 \
  registry.k8s.io/kube-proxy:v1.33.0 \
  registry.k8s.io/coredns/coredns:v1.12.0 \
  registry.k8s.io/pause:3.10 \
  registry.k8s.io/etcd:3.5.21-0

下载网络插件 Calico 镜像

terminal
shell
images=(
  calico/node:v3.26.0
  calico/cni:v3.26.0
  calico/kube-controllers:v3.26.0
)

for image in "${images[@]}"; do
  sudo docker pull $image
done

导出网络插件 Calico 镜像为归档文档

terminal
shell
sudo docker save -o $HOME/k8s-offline/v1.33.0/images/calico-images.tar \
  calico/node:v3.26.0 \
  calico/cni:v3.26.0 \
  calico/kube-controllers:v3.26.0

7. 准备安装脚本

创建安装脚本

terminal
shell
cat > $HOME/k8s-offline/v1.33.0/install.sh << 'EOF'
#!/bin/bash

# 安装 Kubernetes 组件
sudo dpkg -i ./deb-packages/kubernetes/*.deb

# 安装容器运行时CRI组件
sudo dpkg -i ./deb-packages/cri/*.deb
systemctl start containerd
# sudo systemctl start docker

# 加载 Kubernetes 镜像到 Docker
# docker load -i ./images/k8s-images.tar
# 加载 Kubernetes 镜像到 Contained
sudo ctr -n=k8s.io images import ./images/k8s-images.tar

# 加载 Calico 镜像 Docker
# docker load -i ./images/calico-images.tar
# 加载 Calico 镜像 Contained
sudo ctr -n=k8s.io images import ./images/calico-images.tar

# 锁定 Kubernetes 版本
sudo apt-mark hold kubelet kubeadm kubectl

# 拷贝网络插件配置文件到 Kubernetes 默认的 /etc/kubernetes/manifests/
cp ./manifests/calico.yaml /etc/kubernetes/manifests/
EOF

添加可执行权限

terminal
shell
chmod +x $HOME/k8s-offline/v1.33.0/install.sh

8. 打包所有文件

shell
sudo tar -czvf k8s-offline-v1.33.0.tar.gz -C $HOME/k8s-offline/v1.33.0 .

第二阶段:在离线环境中安装集群

1. 传输文件到所有节点

k8s-offline-v1.33.0.tar.gz 传输到所有三台节点服务器。

提示

可以通过 scp 命令进行方便、快捷的传输文件。

2. 在所有节点上执行基础安装

解压离线安装包资源归档文件

创建解压目标目录

terminal
shell
mkdir -p /opt/k8s-install

解压到解压目标目录

terminal
shell
tar -xzvf k8s-offline-v1.33.0.tar.gz -C /opt/k8s-install

进入到解压目标目录

terminal
shell
cd /opt/k8s-install

运行安装脚本

terminal
shell
sudo ./install.sh

验证安装

查看 kubeadm 版本信息

terminal
shell
kubeadm version

查看 kubectl 客户端版本信息

terminal
shell
kubectl version --client

查看 kubelet 版本信息

terminal
shell
kubelet --version

查看容器镜像

terminal
shell
# 查看 contained 查看容器镜像
# sudo docker images
# 查看 contained 查看容器镜像
sudo ctr -n=k8s.io images ls -q

查看 rpcbind 服务状态

terminal
shell
systemctl status rpcbind.service

查看 containerd 服务状态

terminal
shell
systemctl status containerd.service

查看 kubelet 服务状态

terminal
shell
systemctl status kubelet

警告

当前 kubelet 应该是未启动状态,即使使用 systemctl restart kubelet 也不会启动成功,只有 初始化控制平面 之后才会拉起 kubelet 服务!

当然,如果初始化控制平台之后 kubelet 应该正常启动,并且可以通过 http://127.0.0.1:10248/healthz 这个端点查看服务状态。

3. 在主节点上初始化集群

3.1. 初始化 containerd 配置

通过 file 命令检测 /etc/containerd/config.toml 文件是否存在

shell
file /etc/containerd/config.toml

如果未初始化过 containerd 配置文件,正常情况下应该输出

txt
/etc/containerd/config.toml: cannot open `/etc/containerd/config.toml' (No such file or directory)

初始化 containerd 默认配置文件

terminal
shell
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

提醒

该操作会将 containerd 默认配置信息写入到 /etc/containerd/config.toml 文件!

🍔 确认 cri 沙箱镜像版本是否与 containerd 镜像版本一致

查看 cri 沙箱镜像版本信息

/etc/containerd/config.toml
toml
// other config ......
[plugins]

  [plugins."io.containerd.gc.v1.scheduler"]
    deletion_threshold = 0
    mutation_threshold = 100
    pause_threshold = 0.02
    schedule_delay = "0s"
    startup_delay = "100ms"

  [plugins."io.containerd.grpc.v1.cri"]
    cdi_spec_dirs = ["/etc/cdi", "/var/run/cdi"]
    device_ownership_from_security_context = false
    disable_apparmor = false
    disable_cgroup = false
    disable_hugetlb_controller = true
    disable_proc_mount = false
    disable_tcp_service = true
    drain_exec_sync_io_timeout = "0s"
    enable_cdi = false
    enable_selinux = false
    enable_tls_streaming = false
    enable_unprivileged_icmp = false
    enable_unprivileged_ports = false
    ignore_deprecation_warnings = []
    ignore_image_defined_volumes = false
    image_pull_progress_timeout = "5m0s"
    image_pull_with_sync_fs = false
    max_concurrent_downloads = 3
    max_container_log_line_size = 16384
    netns_mounts_under_state_dir = false
    restrict_oom_score_adj = false
    sandbox_image = "registry.k8s.io/pause:3.8"
    selinux_category_range = 1024
    stats_collect_period = 10
    stream_idle_timeout = "4h0m0s"
    stream_server_address = "127.0.0.1"
    stream_server_port = "0"
    systemd_cgroup = false
    tolerate_missing_hugetlb_controller = true
    unset_seccomp_profile = ""
// other config ......

执行以下命令,列出 containerd 镜像列表

terminal
shell
ctr -n=k8s.io images ls -q

将输出类似如下的 containerd 镜像列表数据

txt
docker.io/calico/cni:v3.26.0
docker.io/calico/kube-controllers:v3.26.0
docker.io/calico/node:v3.26.0
registry.k8s.io/coredns/coredns:v1.12.0
registry.k8s.io/etcd:3.5.21-0
registry.k8s.io/kube-apiserver:v1.33.0
registry.k8s.io/kube-controller-manager:v1.33.0
registry.k8s.io/kube-proxy:v1.33.0
registry.k8s.io/kube-scheduler:v1.33.0
registry.k8s.io/pause:3.10
sha256:1cf5f116067c67da67f97bff78c4bbc76913f59057c18627b96facaced73ea0b
sha256:1d579cb6d696709ea7c8613023cbc1204ac2af295477fe577c8fa741a76efa02
sha256:44f52c09dececf0d842450cfbdcf6f1ce1e6eaf2d7183d643b9fbf77dde03a38
sha256:45ae357729e3a6db7de47d4efb04453ac384d5cfec2f062a86523f3482cb1cdb
sha256:499038711c0816eda03a1ad96a8eb0440c005baa6949698223c6176b7f5077e1
sha256:5d6f5c26c655486ee59f7c517dbd383336f4ce2c0db77f7d5ffd015395deee6f
sha256:6ba9545b2183ef722d7e8a7f9e9c2abfaf483cd980bc378480631699413d9cf4
sha256:873ed75102791e5b0b8a7fcd41606c92fcec98d56d05ead4ac5131650004c136
sha256:8d72586a76469984dc4c5c7c36b24fbe4baed63056998c682f07b591d5e0aba4
sha256:f1184a0bd7fe53a4c7098147f250b1f8b287a0e4f8a4e1509ef1d06893267c68

可以看到沙箱镜像指定的镜像版本与 containerd 镜像列表中的 pause 版本匹配不上!

需要将 containerd 配置文件 /etc/containerd/config.toml 中的沙箱镜像校正为 registry.k8s.io/pause:3.10,也就是说该值必须与 containerd 镜像列表中的 pause 版本保持一致!

⚠️修改之后记得重启 containerd

terminal
shell
systemctl restart containerd

警告

这个应该是 Kubernetes v1.33.0 版本的一个 BUG,在下载离线资源的过程中通过执行 sudo kubeadm config images list --kubernetes-version=v1.33.0 命令得到的 pause 版本确实是 3.10,而现在 containerd 默认配置为 3.8 这明显是有问题的,如果不进行沙箱镜像版本确认,在初始化控制平面操作过程中就会出现问题!

3.2. 创建 crictl.yaml 配置文件

terminal
shell
cat <<EOF | sudo tee /etc/crictl.yaml
runtime-endpoint: unix:///var/run/containerd/containerd.sock
image-endpoint: unix:///var/run/containerd/containerd.sock
timeout: 10
debug: false
EOF

如果未创建该配置文件,初始化控制平面之后通过,通过执行 crictl ps -a 命令时将到一个警告信息

txt
WARN[0000] Config "/etc/crictl.yaml" does not exist, trying next: "/usr/bin/crictl.yaml"
WARN[0000] runtime connect using default endpoints: [unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
WARN[0000] Image connect using default endpoints: [unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
CONTAINER           IMAGE               CREATED              STATE               NAME                      ATTEMPT             POD ID              POD                               NAMESPACE
be6c9ad389276       f1184a0bd7fe5       38 seconds ago       Running             kube-proxy                1                   165cdc961d1bf       kube-proxy-4hg8c                  kube-system
5fc516e787ee8       f1184a0bd7fe5       39 seconds ago       Exited              kube-proxy                0                   08c97bca72201       kube-proxy-4hg8c                  kube-system
c988838d71433       1d579cb6d6967       About a minute ago   Running             kube-controller-manager   1                   324e2bf77651d       kube-controller-manager-testify   kube-system
975a48e4e3ef2       499038711c081       About a minute ago   Running             etcd                      1                   c9c4da99fc922       etcd-testify                      kube-system
143f7444e674c       6ba9545b2183e       About a minute ago   Running             kube-apiserver            1                   d001ac7718052       kube-apiserver-testify            kube-system
88dafa6cc3b63       8d72586a76469       About a minute ago   Running             kube-scheduler            1                   d16427a51cb45       kube-scheduler-testify            kube-system
8d4b1eb629996       6ba9545b2183e       About a minute ago   Exited              kube-apiserver            0                   4ae4675ab1514       kube-apiserver-testify            kube-system
687077efcc7bc       8d72586a76469       About a minute ago   Exited              kube-scheduler            0                   da34d839bc256       kube-scheduler-testify            kube-system
cf06d312b77dc       1d579cb6d6967       About a minute ago   Exited              kube-controller-manager   0                   67ccddd02f0a9       kube-controller-manager-testify   kube-system
ae9f3da58d14d       499038711c081       About a minute ago   Exited              etcd                      0                   c7afacdc52760       etcd-testify                      kube-system

3.3. 初始化控制平面

设置临时节点IP变量,方便下面的初始化参数指定

terminal
shell
node_address=<master节点IP>

使用 kubeadm 初始化控制平面

terminal
shell
sudo kubeadm init \
  --kubernetes-version v1.33.0 \
  --pod-network-cidr=192.168.0.0/16 \
  --apiserver-advertise-address=$node_address \
  --control-plane-endpoint=$node_address
点击查看更多相关说明

例如,您的控制平面主节点 IP 为 192.168.0.160,那么上面命令替换后应该为

terminal
shell
node_address=192.168.0.160

kubeadm 初始化控制平面命令为

terminal
shell
sudo kubeadm init \
  --kubernetes-version v1.33.0 \
  --pod-network-cidr=192.168.0.0/16 \
  --apiserver-advertise-address=$node_address \
  --control-plane-endpoint=$node_address

可能会出现容器运行时的沙盒镜像与kubeadm使用的沙盒镜像不一致问题,具体表现如下

txt
[preflight] You can also perform this action beforehand using 'kubeadm config images pull'
W0617 16:13:21.203208   47633 checks.go:846] detected that the sandbox image "registry.k8s.io/pause:3.8" of the container runtime is inconsistent with that used by kubeadm.It is recommended to use "registry.k8s.io/pause:3.10" as the CRI sandbox image.

如果遇到该问题可以参考 解决容器运行时的沙盒镜像与kubeadm使用的沙盒镜像不一致问题 相关文档中的具体说明,解决该问题后再次执行上面的初始化命令进行操作验证即可!


可能还会遇到 cgroups v1 support is in maintenance mode, please migrate to cgroups v2 问题,可以参考 解决 kubeadm 初始化时提示 cgroups v1 support is in maintenance mode, please migrate to cgroups v2 问题 相关文档中的具体说明!


可能还会遇到 A control plane component may have crashed or exited when started by the container runtime. To troubleshoot, list all containers using your preferred container runtimes CLI. 的问题

以下是使用 crictl 列出所有正在运行的 Kubernetes 容器的一个示例:

terminal
shell
crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock ps -a | grep kube | grep -v pause

根据日志进行问题分析排查,以下是一个可以会存在的问题输出

txt
WARN[0000] Config "/etc/crictl.yaml" does not exist, trying next: "/usr/bin/crictl.yaml"

设置 kubectl 配置

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

在主节点上安装网络插件(Calico)

Kubernetes V1.33.0 离线安装资源包已提供离线 Calico 配置文件

terminal
shell
kubectl apply -f /opt/k8s-install/calico.yaml --validate=false

提醒

只有 kube-apiserver Pod 启动之后上面的操作才能操作成功!可以通过 crictl ps 查看 kube-apiserver 状态是否是 Running,为 Running 时执行上面的命令!

如果节点可以连接到外网的情况下可以使用互联网线上资源
terminal
shell
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/calico.yaml

查看节点状态

terminal
shell
kubectl get nodes

将输出类似如下的节点状态数据信息

txt
NAME      STATUS     ROLES           AGE     VERSION
testify   NotReady   control-plane   5m10s   v1.33.0
完全重置集群点击查看更多相关说明

重置集群

terminal
shell
sudo kubeadm reset -f
sudo rm -rf /etc/kubernetes/ /var/lib/etcd/ /etc/cni/net.d/ ~/.kube/

重新初始化 再次执行 在主节点上初始化集群 相关操作以修复问题

好的,为您补充 加入工作节点验证集群状态 两个章节的完整内容:


markdown
### 4. 加入工作节点

在主节点初始化控制平面成功后,kubeadm 会输出类似如下的 join 命令:

```txt
You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

  kubeadm join 192.168.0.160:6443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:7e5a3f9c2b8d1a6e4f7c3b9a2d5e8f1c4a7b2d9e6f3c8a1b5e7d9f2c4a6b8e0f \
    --control-plane

Then you can join any number of worker nodes by running the following on each as root:

  kubeadm join 192.168.0.160:6443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:7e5a3f9c2b8d1a6e4f7c3b9a2d5e8f1c4a7b2d9e6f3c8a1b5e7d9f2c4a6b8e0f

4.1. 在工作节点上执行 join 命令

登录到每个工作节点(node1、node2),执行 worker 节点的 join 命令:

terminal
bash
sudo kubeadm join 192.168.0.160:6443 --token abcdef.0123456789abcdef \
  --discovery-token-ca-cert-hash sha256:7e5a3f9c2b8d1a6e4f7c3b9a2d5e8f1c4a7b2d9e6f3c8a1b5e7d9f2c4a6b8e0f

提示

如果您忘记或丢失了初始化时输出的 join 命令,可以在主节点上重新生成:

terminal
bash
# 查看现有 token 列表
sudo kubeadm token list

# 如果 token 已过期或不存在,创建新 token
sudo kubeadm token create

# 获取 CA 证书的哈希值
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

# 完整的 join 命令(可组合使用)
kubeadm token create --print-join-command

4.2. 验证工作节点 join 成功

在工作节点上执行 join 命令后,预期输出如下:

txt
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Starting the kubelet
[preflight] Activating the kubelet service
[post-start] The kubelet is now running

4.3. 在主节点确认节点加入

terminal
bash
kubectl get nodes

预期输出:

txt
NAME     STATUS     ROLES           AGE     VERSION
master   NotReady   control-plane   10m     v1.33.0
node1    NotReady   <none>          30s     v1.33.0
node2    NotReady   <none>          30s     v1.33.0

注意

此时节点的 STATUS 仍然是 NotReady,这是正常的,因为网络插件(Calico)正在配置 Pod 网络。等待 1-2 分钟后再查看,STATUS 应变为 Ready


5. 验证集群状态

5.1. 查看所有节点状态

terminal
bash
kubectl get nodes -o wide

预期输出(所有节点均为 Ready 状态):

txt
NAME     STATUS   ROLES           AGE   VERSION   INTERNAL-IP    OS-IMAGE             KERNEL-VERSION
master   Ready    control-plane   15m   v1.33.0   192.168.0.160  Ubuntu 22.04.3 LTS   5.15.0-91-generic
node1    Ready    <none>          5m    v1.33.0   192.168.0.161  Ubuntu 22.04.3 LTS   5.15.0-91-generic
node2    Ready    <none>          5m    v1.33.0   192.168.0.162  Ubuntu 22.04.3 LTS   5.15.0-91-generic

5.2. 查看所有 Pods 状态(特别是 kube-system 命名空间)

terminal
bash
kubectl get pods -n kube-system

预期输出(所有 Pod 状态应为 Running):

txt
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-7d9b5b5b5f-xyz12   1/1     Running   0          12m
calico-node-abc12                          1/1     Running   0          12m
calico-node-def34                          1/1     Running   0          10m
calico-node-ghi56                          1/1     Running   0          10m
coredns-5d4d8b9c9f-abc12                   1/1     Running   0          15m
coredns-5d4d8b9c9f-def34                   1/1     Running   0          15m
etcd-master                                1/1     Running   0          15m
kube-apiserver-master                      1/1     Running   0          15m
kube-controller-manager-master             1/1     Running   0          15m
kube-proxy-abc12                           1/1     Running   0          15m
kube-proxy-def34                           1/1     Running   0          5m
kube-proxy-ghi56                           1/1     Running   0          5m
kube-scheduler-master                      1/1     Running   0          15m

5.3. 查看所有命名空间的 Pods

terminal
bash
kubectl get pods --all-namespaces

5.4. 检查集群健康状态

terminal
bash
kubectl get cs

预期输出:

txt
NAME                 STATUS    MESSAGE   ERROR
scheduler            Healthy   ok
controller-manager   Healthy   ok
etcd-0               Healthy   ok

提示

较新版本的 Kubernetes 中 kubectl get cs 可能返回 unhealthy,这是已知问题,不影响集群正常运行。建议使用 kubectl get componentstatuses 或直接检查核心 Pod 状态。

5.5. 检查 kubelet 服务状态(在所有节点上)

terminal
bash
systemctl status kubelet

预期输出应包含 active (running)

5.6. 验证 DNS 解析是否正常

创建一个临时 Pod 用于测试 DNS:

terminal
bash
kubectl run -it --rm --restart=Never busybox --image=busybox:1.28 -- nslookup kubernetes.default

预期输出:

txt
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes.default
Address 1: 10.96.0.1

5.7. 验证 Pod 网络通信

创建一个测试 Nginx Pod:

terminal
bash
kubectl create deployment nginx --image=nginx:alpine
kubectl expose deployment nginx --port=80 --type=ClusterIP
kubectl get svc nginx

预期输出:

txt
NAME    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
nginx   ClusterIP   10.96.123.45    <none>        80/TCP    10s

5.8. 查看集群资源使用情况(如果已安装 metrics-server)

terminal
bash
kubectl top nodes
kubectl top pods --all-namespaces

说明

如果未安装 metrics-server,kubectl top 命令会报错。这是正常的,metrics-server 需要单独安装。


6. 安装验证清单

检查项验证命令预期结果
节点状态kubectl get nodes所有节点 Ready
核心 Podskubectl get pods -n kube-system所有 Pod Running
DNS 解析nslookup kubernetes.default返回正确的 ClusterIP
Pod 网络创建测试 Nginx PodPod 能正常启动并访问
kubelet 服务systemctl status kubeletactive (running)

7. 常见问题排查

如果节点状态一直为 NotReady,按以下顺序排查:

  1. 检查网络插件是否正常安装

    bash
    kubectl get pods -n kube-system | grep calico
  2. 查看节点详细信息

    bash
    kubectl describe node <node-name>
  3. 查看 kubelet 日志

    bash
    journalctl -u kubelet -f --lines=50
  4. 检查 CNI 配置

    bash
    ls /etc/cni/net.d/
  5. 检查容器运行时状态

    bash
    systemctl status containerd
    ctr -n=k8s.io containers ls

至此,Kubernetes v1.33.0 离线三节点集群已安装完成!🎉

最后更新2026/06/09 05:35
如果你觉得这篇文章有帮助,或者想聊聊技术、工作,欢迎通过下面方式联系我:
contact fishfinal