《云原生从0到1:4台华为云ECS搭建Kubernetes 1.28集群实录(上)------环境与踩坑全记录》
作者:云原生学习者 | 系列:云原生工程师实战之路
一句话导读:本文记录了用 4 台华为云 ECS(Ubuntu 24.04,8C16G)从零搭建 Kubernetes 1.28.2 集群的完整过程。其中最大的"惊喜"是 Ubuntu 24.04 自带的 containerd 2.2.1 配置体系与网上 99% 教程完全不同,本文会把每个坑的报错、根因、修复方案全部摊开讲清楚。文章适合所有准备亲手搭建 K8s 集群的开发者,建议收藏。
0. 写在前面
云原生时代,Kubernetes 已经成为事实上的"操作系统"。无论你是想转行云原生工程师、考 CKA/CKS 证书,还是想在公司内部落地容器化,亲手从零搭建一套 K8s 集群都是绕不开的第一课。
本次实操,我准备了 4 台华为云 ECS 服务器,规划为经典的 1 Master + 3 Worker 拓扑。机器配置如下:
| 角色 | 主机名 | 公网 IP | 私网 IP | 配置 | 系统 |
|---|---|---|---|---|---|
| Master | master | 114.116.250.152 | 192.168.0.114 | 8 vCPU / 16 GiB | Ubuntu 24.04 Server |
| Worker | node1 | 113.44.249.32 | 192.168.0.71 | 8 vCPU / 16 GiB | Ubuntu 24.04 Server |
| Worker | node2 | 116.205.105.142 | 192.168.0.178 | 8 vCPU / 16 GiB | Ubuntu 24.04 Server |
| Worker | node3 | 113.44.154.124 | 192.168.0.25 | 8 vCPU / 16 GiB | Ubuntu 24.04 Server |
💡 同可用区部署,私网互通,K8s 集群组件间通信走内网,速度快且不消耗公网流量。
技术选型(重点!)
| 组件 | 版本 | 说明 |
|---|---|---|
| Kubernetes | v1.28.2 | 稳定、资料多、考试覆盖 |
| 容器运行时 | containerd 2.2.1 | Ubuntu 24.04 apt 自带,注意不是 1.7.x! |
| 网络插件 | Calico v3.26.1 | 业界主流 CNI,支持 BGP/IPIP |
| Pod 网段 | 10.244.0.0/16 | 避开华为云 VPC 私有网段 192.168.0.0/16,防止冲突 |
1. 架构设计与部署规划
scss
┌─────────────────────────────────────────────────────────┐
│ 公网 (弹性IP) │
│ 114.116.250.152 113.44.249.32 116.205.105.142 │
│ 113.44.154.124 │
└──────────────┬──────────────────────────────────────────┘
│ 华为云 VPC 私有网络 192.168.0.0/24
┌──────────────▼──────────────────────────────────────────┐
│ master (192.168.0.114) ← API Server :6443 / etcd │
│ node1 (192.168.0.71 ) ← kubelet + kube-proxy │
│ node2 (192.168.0.178) ← kubelet + kube-proxy │
│ node3 (192.168.0.25 ) ← kubelet + kube-proxy │
│ Pod 网段: 10.244.0.0/16 (Calico) │
└─────────────────────────────────────────────────────────┘
部署清单(四步走):
- ✅ 所有节点基础环境:内核参数、swap 关闭、containerd 配置、K8s 组件安装
- ⏳ Master 初始化:kubeadm init 生成控制面与 join token
- ⏳ Worker 加入:kubeadm join 批量接入
- ⏳ 网络打通:Calico CNI 部署,节点 Ready
2. 环境准备:从零配置 4 台机器
2.1 基础工具与内核参数
首先登录所有节点(本文使用 SSH 免密 + 批量脚本管理 4 台机器,大幅提升效率),安装基础工具并配置内核:
bash
# 基础工具
apt-get update && apt-get install -y curl wget vim net-tools jq \
apt-transport-https ca-certificates gnupg lsb-release
# 关闭 swap(K8s 1.28 要求)
swapoff -a && sed -i '/swap/d' /etc/fstab
# 加载内核模块
cat > /etc/modules-load.d/k8s.conf <<'EOF'
overlay
br_netfilter
EOF
modprobe overlay && modprobe br_netfilter
# 内核网络参数(iptables 桥接流量、IP 转发)
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=1是容器网络通信的基础,缺失会导致 Pod 间无法跨节点通信。
2.2 主机名与 hosts 解析
bash
hostnamectl set-hostname master # node1/node2/node3 同理
cat >> /etc/hosts <<'EOF'
192.168.0.114 master
192.168.0.71 node1
192.168.0.178 node2
192.168.0.25 node3
EOF
配置内网 hostname 解析后,join 时可以直接用 master:6443,证书也能正确匹配。
3. 🚨 第一大坑:Ubuntu 24.04 的 containerd 2.2.1,配置体系全变了!
这是本次部署最值得写的一节。网上绝大多数教程(包括很多付费课程)都在讲 containerd 1.7.x 时代的配置:
toml
# 老版本写法(网上 99% 教程)
sandbox_image = "registry.k8s.io/pause:3.8"
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
但 Ubuntu 24.04 通过 apt 安装的 containerd 是 2.2.1,配置格式发生了革命性变化:
toml
# 新版本(containerd 2.x)
version = 3
[plugins.'io.containerd.cri.v1.images']
[plugins.'io.containerd.cri.v1.images'.pinned_images]
sandbox = 'registry.k8s.io/pause:3.10.1' # ← 字段名从 sandbox_image 变成 sandbox!
[plugins.'io.containerd.cri.v1.images'.registry]
config_path = '/etc/containerd/certs.d:/etc/docker/certs.d' # ← 推荐用 hosts.toml 而非 mirrors
3.1 坑 1.1:sandbox_image 配置不生效
我按老教程执行 sed -i 's#sandbox_image = "..."#...#',结果 grep 出来根本没有这个字段!运行 kubelet 后日志狂报:
css
error="failed to get sandbox image \"registry.k8s.io/pause:3.10.1\":
failed to pull image ... dial tcp 74.125.195.82:443: i/o timeout"
根因 :containerd 2.x 中沙箱镜像配置在 pinned_images.sandbox,且默认指向 registry.k8s.io(国内不可达),必须替换。
修复:
bash
sed -i "s#sandbox = 'registry.k8s.io/pause:3.10.1'#sandbox = 'registry.aliyuncs.com/google_containers/pause:3.9'#" /etc/containerd/config.toml
💡 K8s 1.28 对应 pause:3.9,别用错版本。
3.2 坑 1.2:mirrors 与 config_path 互斥,CRI 插件直接加载失败
我在老位置追加了镜像加速配置后,containerd 日志出现致命错误:
ini
level=warning msg="failed to load plugin"
error="unable to load CRI image service plugin dependency:
invalid cri image config: `mirrors` cannot be set when `config_path` is provided"
根因 :containerd 2.x 默认启用 config_path(指向 /etc/containerd/certs.d)时禁止 同时使用 mirrors。CRI 插件加载失败 → crictl 报 CRI v1 image API is not implemented。
修复(官方推荐方式:hosts.toml):
bash
mkdir -p /etc/containerd/certs.d/docker.io /etc/containerd/certs.d/registry-1.docker.io
cat > /etc/containerd/certs.d/docker.io/hosts.toml <<'EOF'
server = "https://docker.io"
[host."https://docker.m.daocloud.io"]
capabilities = ["pull", "resolve"]
[host."https://docker.1ms.run"]
capabilities = ["pull", "resolve"]
[host."https://hub-mirror.c.163.com"]
capabilities = ["pull", "resolve"]
EOF
修复后验证 CRI 正常、镜像可拉:
bash
$ systemctl restart containerd
$ crictl pull registry.aliyuncs.com/google_containers/pause:3.9
Image is up to date for sha256:e6f1816883972d4be47bd48879a08919b96afcd344132622e4d444987919323c
$ crictl images
IMAGE TAG IMAGE ID SIZE
registry.aliyuncs.com/google_containers/pause 3.9 e6f1816883972 322kB
3.3 坑 1.3:crictl 默认连 dockershim 端点
arduino
FATA[0000] validate service connection: ... dial unix /var/run/dockershim.sock: connect: no such file or directory
修复 :配置 /etc/crictl.yaml 指向 containerd:
bash
cat > /etc/crictl.yaml <<'EOF'
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF
3.4 别忘了 SystemdCgroup
containerd 2.x 的 config default 生成的配置里 SystemdCgroup = false,而 kubeadm 默认要求 kubelet 与运行时统一使用 systemd cgroup 驱动,必须改:
bash
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd
4. 安装 K8s 组件(kubeadm / kubelet / kubectl)
国内环境必须用阿里云镜像源 ,官方源 packages.cloud.google.com 不可达:
bash
# 添加阿里云 K8s 源
install -d /etc/apt/keyrings
curl -fsSL https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg \
| gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] \
https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main" \
> /etc/apt/sources.list.d/kubernetes.list
apt-get update
# 安装 1.28.2 并锁定版本
apt-get install -y kubelet=1.28.2-00 kubeadm=1.28.2-00 kubectl=1.28.2-00
apt-mark hold kubelet kubeadm kubectl
安装完成确认版本:
text
kubeadm version: v1.28.2 (GitCommit: 89a4ea3e1e4ddd7f7572286090359983e0387b2f)
Kubernetes v1.28.2 (Client Version)
5. Master 节点初始化(kubeadm init)
在 master 上执行初始化。核心参数说明:
bash
kubeadm init \
--image-repository=registry.aliyuncs.com/google_containers \ # 国内镜像仓库,必须!
--kubernetes-version=v1.28.2 \
--pod-network-cidr=10.244.0.0/16 \ # 与 Calico 网段保持一致
--apiserver-advertise-address=192.168.0.114 \ # Master 私网 IP
--cri-socket=unix:///run/containerd/containerd.sock
⚠️ 注意
--image-repository只影响 kubeadm 拉取的组件镜像(apiserver/etcd 等),沙箱镜像 pause 由 containerd 的 pinned_images 决定------这就是上面坑 1.1 必须解决的原因。
初始化成功后,控制台会输出关键信息(务必保存!):
text
Your Kubernetes control-plane has been initialized successfully!
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.0.114:6443 --token 6ju96d.f633yienwrluzp27 \
--discovery-token-ca-cert-hash sha256:0a6d6ff34a117c1e1f8f6936f04be153994a09266bbed6f3ba0cdf3981b8a457
💡 token 有效期默认 24 小时,若过期可执行
kubeadm token create --print-join-command重新生成。
5.1 配置 kubectl
bash
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
kubectl get nodes
6. 小结与下期预告
本文完成了云原生集群搭建的前半程:4 台 ECS 环境准备 + containerd 2.2.1 三连坑修复 + kubeadm init 控制面初始化。
核心收获:
- Ubuntu 24.04 的 containerd 2.x 配置体系完全不同 :
sandbox替代sandbox_image、hosts.toml替代mirrors、CRI 插件路径从grpc.v1.cri改为cri.v1.*; - 国内环境镜像源三件套:阿里云 K8s apt 源 + 阿里云容器镜像仓库 + hosts.toml 加速;
- cgroup 驱动必须统一:kubelet 与 containerd 都要用 systemd。
下期预告:《3 个 Worker 节点批量加入集群 + Calico 网络插件部署 + 集群健康检查实战》,敬请期待!
本文为原创实操记录,基于真实环境一步步跑通。欢迎转载,请注明出处。