基于 kubeadm 创建 Kubernetes v1.34.1 集群(Ubuntu 22.04 + containerd + Calico + IPVS)
本文详细记录了在 Ubuntu 22.04 LTS 系统上,使用 kubeadm 工具从零开始搭建一个生产级可用的 Kubernetes v1.34.1 高可用集群的完整过程。整个流程涵盖了环境准备、组件安装、集群初始化、网络插件部署、Ingress 配置以及常见问题解决方案,确保每一步都清晰可执行。
📋 集群配置概览
| 项目 | 配置 |
|---|---|
| Kubernetes 版本 | v1.34.1 |
| 操作系统 | Ubuntu 22.04 LTS |
| 容器运行时 | containerd |
| CNI 网络插件 | Calico (自定义 10.244.0.0/16) |
| kube-proxy 模式 | IPVS |
| Pod 网段(podSubnet) | 10.244.0.0/16 ✅ |
| Service 网段 | 10.96.0.0/12 |
| Ingress 控制器 | ingress-nginx |
🖥️ 节点信息
| IP 地址 | Hostname | Role |
|---|---|---|
| 192.168.122.96 | k8s-master | Control-plane |
| 192.168.122.190 | k8s-node1 | Worker |
| 192.168.122.79 | k8s-node2 | Worker |
💡 说明:本教程中所有操作均需以
root或具有sudo权限的用户执行。请根据实际环境调整 IP 和主机名。
✅ 第一步:所有节点通用初始化(3台都执行)
此步骤为所有节点(Master 和 Worker)进行基础环境配置。
1. 设置主机名
分别在对应节点上执行以下命令,设置正确的主机名。
# 在 192.168.122.96 上执行
sudo hostnamectl set-hostname k8s-master
# 在 192.168.122.190 上执行
sudo hostnamectl set-hostname k8s-node1
# 在 192.168.122.79 上执行
sudo hostnamectl set-hostname k8s-node2
🔔 执行后建议重新登录或重启终端以使主机名生效。
2. 配置 hosts(所有节点)
配置本地 DNS 解析,便于节点间通过主机名通信。
sudo tee /etc/hosts << 'EOF'
192.168.122.96 k8s-master
192.168.122.190 k8s-node1
192.168.122.79 k8s-node2
EOF
⚠️ 确保各节点
/etc/hosts文件内容一致。
3. 关闭 Swap
Kubernetes 强制要求关闭 Swap,否则 kubelet 将无法启动。
sudo swapoff -a
sudo sed -i '/swap/s/^\(.*\)$/#\1/g' /etc/fstab
📌
sed命令会注释掉/etc/fstab中所有包含swap的行,防止系统重启后自动挂载 Swap。
4. 加载内核模块(IPVS + 桥接)
加载必要的内核模块,为启用 IPVS 和网络桥接做准备。
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
EOF
sudo systemctl restart systemd-modules-load
✅ 模块说明:
br_netfilter: 启用网桥流量过滤,允许 iptables 处理桥接流量。ip_vs*: IP Virtual Server 内核模块,用于 kube-proxy 的 IPVS 模式。nf_conntrack: 连接跟踪模块,是ip_vs的依赖。
5. 配置网络参数
配置系统网络参数,确保 Kubernetes 网络正常工作。
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
✅ 参数说明:
bridge-nf-call-*: 确保 iptables 能够对桥接的流量进行过滤。ip_forward = 1: 启用 IPv4 路由转发,是 Pod 跨节点通信的基础。
✅ 第二步:安装 containerd(所有节点)
containerd 是 Kubernetes 推荐的容器运行时。
1. 添加 Docker 仓库(使用国内镜像源)
由于 download.docker.com 国内访问困难,我们使用 清华 TUNA 镜像源 替代。
# 备份原有的 docker.list(如果存在)
sudo mv /etc/apt/sources.list.d/docker.list /etc/apt/sources.list.d/docker.list.bak 2>/dev/null || true
# 使用清华镜像源添加 Docker CE APT 源
cat << EOF | sudo tee /etc/apt/sources.list.d/docker.list
deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu jammy stable
EOF
# 下载并安装 GPG 公钥
curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
🔍 为什么这样做?
直接连接download.docker.com常因网络屏蔽或 TLS 握手失败导致apt update失败。使用国内镜像源可大幅提升下载速度和稳定性。
2. 安装 containerd
更新软件包列表并安装 containerd。
sudo apt update && sudo apt install -y containerd.io
3. 配置 containerd(systemd cgroup + 镜像加速)
生成默认配置并进行关键修改。
# 生成默认配置(如果不存在)
sudo mkdir -p /etc/containerd
sudo containerd config default | sudo tee /etc/containerd/config.toml
编辑 /etc/containerd/config.toml,确保以下关键配置:
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true # ✅ 启用 systemd cgroup 驱动
✅ 重要性:Kubernetes v1.22+ 推荐使用
systemd作为 cgroup 驱动,与 kubelet 保持一致,避免资源管理冲突。
配置国内镜像加速
创建镜像仓库重定向配置,解决 registry.k8s.io 拉取慢的问题。
sudo mkdir -p /etc/containerd/certs.d/registry.k8s.io
sudo mkdir -p /etc/containerd/certs.d/k8s.gcr.io
cat > /etc/containerd/certs.d/registry.k8s.io/hosts.toml <<'EOF'
server = "https://registry.k8s.io"
[host."https://registry.aliyuncs.com"]
capabilities = ["pull", "resolve"]
override_path = true
EOF
cat > /etc/containerd/certs.d/k8s.gcr.io/hosts.toml <<'EOF'
server = "https://k8s.gcr.io"
[host."https://registry.aliyuncs.com"]
capabilities = ["pull", "resolve"]
override_path = true
EOF
🔁 原理:当请求
registry.k8s.io/pause:3.8时,containerd 会自动重定向到registry.aliyuncs.com/google_containers/pause:3.8进行拉取。
提前拉取 pause 镜像
# 使用 crictl 拉取(自动进入 k8s.io 命名空间)
crictl pull registry.aliyuncs.com/google_containers/pause:3.8
# 打标签为官方名称
ctr -n k8s.io images tag \
registry.aliyuncs.com/google_containers/pause:3.8 \
registry.k8s.io/pause:3.8
# 【可选】加个 label 防止被误删
ctr -n k8s.io images label registry.k8s.io/pause:3.8 keep=true
⚠️
ctr -n k8s.io中的k8s.io是 Kubernetes 使用的 containerd 命名空间,必须指定。
4. 重启并启用 containerd
sudo systemctl restart containerd
sudo systemctl enable containerd
✅ 第三步:安装 kubeadm、kubelet、kubectl(所有节点)
安装 Kubernetes 核心工具。
1. 添加 Kubernetes v1.34 仓库
# 添加 GPG 密钥
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# 添加 APT 源
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.34/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
# 更新软件包列表
sudo apt update
2. 安装组件
# 安装 ipvsadm(用于验证 IPVS)
sudo apt install -y ipvsadm
# 安装 kubeadm, kubelet, kubectl
sudo apt install -y kubelet kubeadm kubectl
# 锁定版本,防止意外升级
sudo apt-mark hold kubelet kubeadm kubectl
# 启用并启动 kubelet(此时会因缺少配置而报错,正常)
sudo systemctl enable --now kubelet
✅ 第四步:初始化 Master 节点(仅在 k8s-master 执行)
1. 创建 kubeadm 配置文件
创建 kubeadm-config.yaml,启用 Calico 自定义 CIDR 和 IPVS 模式。
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.34.1
controlPlaneEndpoint: "k8s-master:6443"
imageRepository: registry.aliyuncs.com/google_containers
networking:
podSubnet: "10.244.0.0/16" # Calico 使用的 Pod 网段
serviceSubnet: "10.96.0.0/12"
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
ipvs:
excludeCIDRs: null
minSyncPeriod: 0s
scheduler: ""
syncPeriod: 30s
tcpTimeout: 30m
tcpFinTimeout: 30s
✅ 关键配置说明:
imageRepository: 使用阿里云镜像仓库,避免拉取超时。podSubnet: 必须与后续 Calico 配置中的CALICO_IPV4POOL_CIDR一致。mode: ipvs: 显式声明 kube-proxy 使用 IPVS 模式。
2. 其他配置(可选但推荐)
配置 crictl 工具,方便调试。
cat <<EOF | sudo tee /etc/crictl.yaml
runtime-endpoint: unix:///var/run/containerd/containerd.sock
image-endpoint: unix:///var/run/containerd/containerd.sock
timeout: 2
debug: false
EOF
3. 初始化集群
⚠️ 重要提示:如果
kubeadm init卡在[init] Using Kubernetes version: v1.34.1,大概率是镜像拉取失败。请参考文末【常见问题】提前手动拉取镜像。
# 可选:清理旧环境(重新初始化时使用)
sudo kubeadm reset -f
sudo rm -rf /etc/kubernetes/
sudo rm -rf /var/lib/etcd
# 执行初始化
sudo kubeadm init --config kubeadm-config.yaml --node-name k8s-master
🎉 成功后,控制台会输出
kubeadm join命令,请务必保存!
4. 配置 kubectl
让普通用户可以使用 kubectl。
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
5. 验证 kube-proxy 模式
kubectl get configmap kube-proxy -n kube-system -o yaml | grep mode
# 应输出:mode: ipvs
✅ 第五步:安装 Calico CNI(支持自定义 podSubnet)
Calico 是最流行的 CNI 插件之一,支持 BGP 和 IPIP 等多种模式。
1. 下载 Calico YAML
curl https://raw.githubusercontent.com/projectcalico/calico/v3.27.3/manifests/calico.yaml -O
2. 镜像替换(可选)
若发现国外镜像拉取失败,可将镜像地址替换为国内镜像。
# 示例:使用 DaoCloud 镜像
sed -i 's|docker.io/calico/|docker.m.daocloud.io/calico/|g' calico.yaml
然后手动拉取镜像:
crictl pull docker.m.daocloud.io/calico/cni:v3.27.3
crictl pull docker.m.daocloud.io/calico/node:v3.27.3
crictl pull docker.m.daocloud.io/calico/kube-controllers:v3.27.3
3. 修改 Pod 网段
编辑 calico.yaml,找到 CALICO_IPV4POOL_CIDR 并修改为与 kubeadm-config.yaml 一致的值。
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/16" # ✅ 确保与此处一致
⚠️ 切勿修改
IPV4_KUBERNETES_SERVICE_CIDR或其他字段。
4. 部署 Calico
kubectl apply -f calico.yaml
5. 等待 Calico 就绪
watch kubectl get pods -n kube-system -l k8s-app=calico-node
直到所有 calico-node 和 calico-kube-controllers 状态为 Running。
# 示例输出
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-778cf97f-xdk2d 1/1 Running 1 42h
calico-node-5shqz 1/1 Running 1 42h
calico-node-8d2jx 1/1 Running 1 42h
calico-node-vs28z 1/1 Running 1 42h
✅ 第六步:加入 Worker 节点
1. 在 Worker 节点执行 join 命令
在 k8s-node1 和 k8s-node2 上执行 kubeadm init 输出的 kubeadm join 命令。
kubeadm join k8s-master:6443 \
--token <your-token> \
--discovery-token-ca-cert-hash sha256:<your-hash>
🔐 如果忘记,可在 Master 节点重新生成:
kubeadm token create --print-join-command
2. 验证节点状态
在 Master 节点执行:
kubectl get nodes
# 示例输出
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane 42h v1.34.1
k8s-node1 Ready <none> 42h v1.34.1
k8s-node2 Ready <none> 42h v1.34.1
所有节点状态应为 Ready。
✅ 第七步:部署 Ingress-Nginx
为集群提供外部 HTTP(S) 访问能力。
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml
等待启动
kubectl get pods -n ingress-nginx
如需 NodePort 暴露
kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{"spec":{"type":"NodePort"}}'
✅ 第八步:验证 IPVS 和 Pod 网络
1. 验证 IPVS 是否生效
sudo ipvsadm -ln
# 应看到大量 service 的 IPVS 规则
2. 验证 Pod CIDR 分配
kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'
# 输出应类似:10.244.1.0/24 10.244.2.0/24 ...
3. 创建测试 Pod
kubectl run testpod --image=nginx:alpine --restart=Never
kubectl get pod testpod -o wide
# IP 应属于 10.244.x.x 范围
✅ 第九步:测试 Ingress(可选)
部署一个简单的 Nginx 应用并通过 Ingress 访问。
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx-demo
template:
metadata:
labels:
app: nginx-demo
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx-demo
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: nginx.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-svc
port:
number: 80
EOF
在本地电脑的 hosts 文件中添加:
192.168.122.96 nginx.local
访问 http://nginx.local,应能看到 Nginx 欢迎页面。
✅ 常见问题与解决方案
| 问题 | 解决方案 |
|---|---|
| Pod CIDR not assigned | 检查 Calico 是否正常运行,podSubnet 是否与 Calico 的 CALICO_IPV4POOL_CIDR 匹配 |
| IPVS not working | 检查内核模块 (ip_vs, br_netfilter) 是否已加载,kube-proxy ConfigMap 中 mode 是否为 ipvs |
| ImagePullBackOff | 使用国内镜像仓库(如阿里云、DaoCloud)提前拉取镜像并打标签 |
| NodeNotReady | 检查 kubelet、containerd、CNI 插件日志 (journalctl -u kubelet) |
✅ 总结
你已完成以下目标:
✅ 在 Ubuntu 22.04 上成功部署 Kubernetes v1.34.1
✅ 使用 10.244.0.0/16 作为 Pod 网段
✅ 部署 Calico CNI 并正确配置自定义 CIDR
✅ 使用 containerd 作为容器运行时,并启用 systemd cgroup 驱动
✅ 启用 kube-proxy 的 IPVS 模式,提升服务性能
✅ 成功部署 ingress-nginx 对外暴露服务
✅ 所有节点均已加入集群,状态正常
📚 附录:镜像拉取问题深度解析
❌ 为什么 kubeadm init 会“卡住”?
kubeadm init 默认会尝试从 registry.k8s.io 拉取核心组件镜像。该域名在国内访问极不稳定,常导致:
- 拉取过程长时间无响应
- 最终报错:
failed to pull image或context deadline exceeded
✅ 推荐解决方案:手动预拉取镜像
方法:使用脚本一键拉取(推荐)
#!/bin/bash
# =============== 配置变量 ===============
REGISTRY=registry.cn-hangzhou.aliyuncs.com/google_containers
K8S_VERSION=v1.34.1
PAUSE_VERSION=3.8
COREDNS_VERSION=v1.11.3
ETCD_VERSION=3.5.12-0
echo "🎯 开始拉取 Kubernetes ${K8S_VERSION} 镜像..."
IMAGES=(
kube-apiserver
kube-controller-manager
kube-scheduler
kube-proxy
)
for IMAGE in "${IMAGES[@]}"; do
SOURCE=${REGISTRY}/${IMAGE}:${K8S_VERSION}
DEST=registry.k8s.io/${IMAGE}:${K8S_VERSION}
echo "🔽 拉取: ${SOURCE}"
sudo ctr -n k8s.io images pull ${SOURCE} || { echo "❌ 拉取失败: ${SOURCE}"; exit 1; }
echo "🏷️ 打标签: ${DEST}"
sudo ctr -n k8s.io images tag ${SOURCE} ${DEST}
done
# 拉取 pause
echo "🔽 拉取: ${REGISTRY}/pause:${PAUSE_VERSION}"
sudo ctr -n k8s.io images pull ${REGISTRY}/pause:${PAUSE_VERSION}
sudo ctr -n k8s.io images tag ${REGISTRY}/pause:${PAUSE_VERSION} registry.k8s.io/pause:${PAUSE_VERSION}
# 拉取 CoreDNS
echo "🔽 拉取: ${REGISTRY}/coredns:${COREDNS_VERSION}"
sudo ctr -n k8s.io images pull ${REGISTRY}/coredns:${COREDNS_VERSION}
sudo ctr -n k8s.io images tag ${REGISTRY}/coredns:${COREDNS_VERSION} registry.k8s.io/coredns:${COREDNS_VERSION}
# 拉取 etcd
echo "🔽 拉取: ${REGISTRY}/etcd:${ETCD_VERSION}"
sudo ctr -n k8s.io images pull ${REGISTRY}/etcd:${ETCD_VERSION}
sudo ctr -n k8s.io images tag ${REGISTRY}/etcd:${ETCD_VERSION} registry.k8s.io/etcd:${ETCD_VERSION}
echo "✅ 所有镜像准备就绪!"
sudo crictl images
保存为 pull-images.sh,赋予执行权限后运行即可。
✅ 总结表格
| 问题 | 根本原因 | 解决方案 |
|---|---|---|
| 初始化卡住 | 无法从 registry.k8s.io 拉取镜像 | 手动从阿里云等国内源拉取并打标签 |
| 需要哪些镜像 | kubeadm 依赖的核心组件 | kube-apiserver, kube-controller-manager, kube-scheduler, kube-proxy, etcd, pause, coredns |
| 如何解决 | ctr -n k8s.io 命令操作 containerd | 使用脚本批量拉取和标记 |
| 推荐工具 | containerd 原生命令行 | ctr (配合 -n k8s.io 命名空间) |
现在你可以自信地运行镜像拉取脚本,再执行 kubeadm init,整个过程将流畅无比!
更多推荐



所有评论(0)