本文详细记录了在 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 地址HostnameRole
192.168.122.96k8s-masterControl-plane
192.168.122.190k8s-node1Worker
192.168.122.79k8s-node2Worker

💡 说明:本教程中所有操作均需以 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-nodecalico-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-node1k8s-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检查 kubeletcontainerd、CNI 插件日志 (journalctl -u kubelet)

✅ 总结

你已完成以下目标:

✅ 在 Ubuntu 22.04 上成功部署 Kubernetes v1.34.1
✅ 使用 10.244.0.0/16 作为 Pod 网段
✅ 部署 Calico CNI 并正确配置自定义 CIDR
✅ 使用 containerd 作为容器运行时,并启用 systemd cgroup 驱动
✅ 启用 kube-proxyIPVS 模式,提升服务性能
✅ 成功部署 ingress-nginx 对外暴露服务
✅ 所有节点均已加入集群,状态正常


📚 附录:镜像拉取问题深度解析

❌ 为什么 kubeadm init 会“卡住”?

kubeadm init 默认会尝试从 registry.k8s.io 拉取核心组件镜像。该域名在国内访问极不稳定,常导致:

  • 拉取过程长时间无响应
  • 最终报错:failed to pull imagecontext 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,整个过程将流畅无比!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐