K8s 系列 | 第 2 天:手把手搭建你的第一个 K8s 集群(kubeadm 实战)


tags: [Kubernetes, K8s系列, DevOps, kubeadm, 集群搭建]

K8s 系列 | 第 2 天:手把手搭建你的第一个 K8s 集群(kubeadm 实战)

第 2/30 天

引言

上一篇文章我们介绍了 Kubernetes 的核心概念与架构全景,从 Control Plane 到 Worker Node,从 Pod 到 Service,了解了这套容器编排系统的设计哲学。然而,理论再好,不如亲手搭建一个集群来得实在。

很多初学者在尝试搭建 K8s 集群时,往往会被各种”玄学”问题劝退——kubelet 起不来、CNI 网络不通、证书过期、镜像拉不下来……这些问题看似复杂,实则大多有章可循。本文将使用 Kubernetes 官方推荐的 kubeadm 工具,从零开始搭建一个高可用的生产级集群

如果你只有一台机器也不用担心——我们还会介绍单节点(all-in-one)搭建方案,让你用最低成本完成实验环境部署。


核心概念

kubeadm 是什么?

kubeadm 是 Kubernetes 官方提供的集群初始化工具,它的设计目标就是简化集群搭建流程。它不会帮你安装 kubelet 或容器运行时,而是专注于:

  • 生成并签署 TLS 证书
  • 生成 Control Plane 组件的静态 Pod 清单(etcd、apiserver、controller-manager、scheduler)
  • 初始化集群的 bootstrap token
  • 安装 CoreDNS 插件(默认可选)
  • 生成 Node 加入集群所需的令牌

集群角色划分

角色 节点数 核心组件 功能
Control Plane ≥1(推荐 3 奇数) kube-apiserver, etcd, kube-controller-manager, kube-scheduler 管理集群状态、调度工作负载
Worker Node ≥1 kubelet, kube-proxy, 容器运行时 运行用户容器、暴露服务
etcd 节点 可与 CP 共存或独立 etcd 分布式键值存储、集群状态持久化

容器运行时选型

Kubernetes 从 1.24 版本开始移除了 Dockershim,所有容器运行时必须支持 CRI(Container Runtime Interface)。目前主流选择:

运行时 优点 缺点
containerd 轻量、K8s 默认推荐、性能好 CLI 工具较单一
CRI-O 专为 K8s 打造、安全性强 社区相对较小
Docker + cri-dockerd 兼容 Docker CLI 习惯 多一层适配、性能略损耗

推荐:containerd,这也是本文将要使用的运行时。


实战步骤

环境准备

本次实战使用以下环境:

  • 操作系统:Ubuntu 22.04 LTS / Rocky Linux 9(双版本兼容)
  • Kubernetes 版本:v1.30
  • 容器运行时:containerd 1.7+
  • 网络插件:Calico
  • 节点规划:1 台 Control Plane + 2 台 Worker(或单节点 all-in-one)

硬件最低要求

组件 CPU 内存 磁盘
Control Plane 2 核 2 GB 20 GB
Worker Node 1 核 1 GB 20 GB
单节点实验 2 核 2 GB 20 GB

第一步:所有节点基础配置

在所有节点上执行以下配置:

# 1. 关闭 swap(kubelet 强制要求)
sudo swapoff -a
sudo sed -i '/ swap / s/^(.*)$/#1/g' /etc/fstab

# 2. 启用内核模块
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

sudo modprobe overlay
sudo modprobe br_netfilter

# 3. 设置内核参数(桥接流量转发)
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sudo sysctl --system

# 4. 安装必要工具
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg

第二步:安装 containerd 容器运行时

# 安装 containerd
sudo apt-get install -y containerd

# 生成默认配置并修改
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# 关键修改:启用 SystemdCgroup(否则 kubelet 无法正确检测 cgroup)
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

# 修改 sandbox 镜像地址(国内环境加速)
sudo sed -i 's|registry.k8s.io/pause:3.8|registry.aliyuncs.com/google_containers/pause:3.9|' /etc/containerd/config.toml

# 重启 containerd
sudo systemctl restart containerd
sudo systemctl enable containerd

第三步:安装 kubeadm、kubelet、kubectl

所有节点安装相同版本的工具链:

# 添加 Kubernetes 官方 APT 仓库(使用国内镜像加速)
sudo curl -fsSL https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.30/deb/Release.key | sudo 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-new/core/stable/v1.30/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubelet=1.30.0-1.1 kubeadm=1.30.0-1.1 kubectl=1.30.0-1.1
sudo apt-mark hold kubelet kubeadm kubectl

为什么要 apt-mark hold Kubernetes 集群升级需要严格按版本步骤,自动升级可能破坏集群兼容性。

第四步:初始化 Control Plane(主节点)

在 Control Plane 节点上执行初始化:

# 创建配置文件(推荐使用配置文件而非命令行参数)
cat > /tmp/kubeadm-config.yaml << 'EOF'
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: "192.168.1.10"  # 替换为你的 CP 节点 IP
  bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: "v1.30.0"
controlPlaneEndpoint: "192.168.1.10:6443"
networking:
  serviceSubnet: "10.96.0.0/12"
  podSubnet: "10.244.0.0/16"
  dnsDomain: "cluster.local"
imageRepository: "registry.aliyuncs.com/google_containers"
EOF

# 拉取镜像(提前拉取可加速初始化)
sudo kubeadm config images pull --config /tmp/kubeadm-config.yaml

# 初始化集群
sudo kubeadm init --config /tmp/kubeadm-config.yaml --upload-certs

初始化成功后,会输出类似如下的关键信息:

Your Kubernetes control-plane has been initialized successfully!

To start using your cluster, you need to run the following as a regular user:

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

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

kubeadm join 192.168.1.10:6443 --token abcdef.0123456789abcdef 
        --discovery-token-ca-cert-hash sha256:...

务必保存 kubeadm join 命令,这是 Worker 节点加入集群的凭证。

# 配置 kubectl 访问权限(普通用户)
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 验证集群状态
kubectl get nodes
kubectl get pods -n kube-system

第五步:安装 CNI 网络插件(Calico)

集群初始化完成后,CoreDNS Pod 会处于 Pending 状态,必须安装 CNI 插件才能使其正常运行:

# 使用 Calico 作为网络插件(推荐生产环境)
# 下载 Calico 清单
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.28/manifests/calico.yaml

# 如果需要自定义 Pod CIDR,编辑 calico.yaml 中的 CALICO_IPV4POOL_CIDR
# 确保与 kubeadm init 时指定的 podSubnet 一致
# - name: CALICO_IPV4POOL_CIDR
#   value: "10.244.0.0/16"

kubectl apply -f calico.yaml

安装完成后,等待所有 Pod 变为 Running 状态:

kubectl get pods -n kube-system -w

第六步:Worker 节点加入集群

在每个 Worker 节点上执行第 1-3 步的基础配置后,运行 Control Plane 初始化时输出的 join 命令:

# Worker 节点加入集群
sudo kubeadm join 192.168.1.10:6443 --token abcdef.0123456789abcdef 
        --discovery-token-ca-cert-hash sha256:...

# 如果 token 过期(默认 24 小时),在 Control Plane 上重新生成
sudo kubeadm token create --print-join-command

在 Control Plane 上验证节点加入状态:

kubectl get nodes
# 预期输出:
# NAME           STATUS   ROLES           AGE   VERSION
# k8s-master     Ready    control-plane   5m    v1.30.0
# k8s-worker-1   Ready    <none>          2m    v1.30.0
# k8s-worker-2   Ready    <none>          1m    v1.30.0

第七步:单节点集群(All-in-One)部署方案

如果你只有一台机器,可以移除 Control Plane 的污点,让 Pod 也能调度到 Master 节点上:

# 允许 Master 节点运行工作负载(开发/测试环境)
kubectl taint nodes --all node-role.kubernetes.io/control-plane-

# 验证 Pod 可以调度到单节点上
kubectl run test-pod --image=nginx
kubectl get pods -o wide

验证集群

运行一个测试应用,验证集群功能完整:

# 部署一个测试 Nginx
kubectl create deployment nginx-test --image=nginx:alpine --replicas=3
kubectl expose deployment nginx-test --port=80 --type=NodePort

# 获取暴露的端口
kubectl get svc nginx-test

# 通过任意节点 IP + NodePort 访问
curl http://192.168.1.10:$(kubectl get svc nginx-test -o jsonpath='{.spec.ports[0].nodePort}')

常见问题

Q1: kubeadm init 时卡在拉取镜像阶段怎么办?

原因:默认镜像仓库 registry.k8s.io 在中国大陆地区访问缓慢或被墙。

解决:使用阿里云镜像仓库替代,在 InitConfiguration 中设置 imageRepository: "registry.aliyuncs.com/google_containers"。或者手动拉取所有镜像:

sudo kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers

Q2: kubelet 一直报错 “failed to find container runtime”

原因:kubelet 无法与 containerd 通信,常见于 containerd 的 CRI 插件未启用。

解决:确保 /etc/containerd/config.toml 中包含:

disabled_plugins = []  # 而不是 disabled_plugins = ["cri"]

然后重启:

sudo systemctl restart containerd
systemctl status kubelet

Q3: CoreDNS Pod 一直处于 Pending 状态

原因:未安装 CNI 网络插件,集群网络未就绪。

解决:确认 Pod CIDR 配置一致,然后安装 Calico 或 Flannel:

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28/manifests/calico.yaml

Q4: Node 加入时提示 “token is invalid”

原因:bootstrap token 默认有效期 24 小时,过期后无法使用。

解决:在 Control Plane 上重新生成 join 命令:

kubeadm token create --print-join-command

Q5: kubectl get nodes 显示 NotReady 且 kubelet 日志有 “cgroup driver” 错误

原因:kubelet 使用 systemd cgroup driver,但 containerd 配置了 cgroupfs,两者不一致。

解决:修改 containerd 配置,确保 SystemdCgroup = true,重启 containerd:

sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd

总结

通过本文,我们从零开始完成了一个完整的 Kubernetes 集群搭建:

  1. 基础环境准备:关闭 swap、加载内核模块、设置转发参数
  2. 容器运行时安装:使用 containerd 作为 CRI 实现
  3. K8s 工具链安装:kubeadm、kubelet、kubectl 三件套
  4. 集群初始化:通过 kubeadm 一键初始化 Control Plane
  5. CNI 网络插件部署:Calico 实现 Pod 间网络互通
  6. Worker 节点加入:多节点弹性扩展
  7. 验证与测试:运行 Nginx 验证集群功能

下期预告

第 3 天:Pod 详解——K8s 最小的调度单元与生命周期管理

集群搭好了,接下来我们深入最核心的抽象——Pod。你会学到 Pod 的设计理念、Sidecar 模式、生命周期各阶段(Pending → Running → Succeeded/Failed)、静态 Pod 与 Init Container 的使用场景,以及健康检查(livenessProbe、readinessProbe)的配置细节。


📚 K8s 系列目录(持续更新中)**

天数 标题 状态
第 1 天 Kubernetes 是什么?核心概念与架构全景解析 ✅ 已发布
第 2 天 手把手搭建你的第一个 K8s 集群(kubeadm 实战) 📝 本文
第 3 天 Pod 详解:K8s 最小的调度单元与生命周期管理 🔜 即将发布
第 4 天 Deployment 与 ReplicaSet:声明式应用管理 🔜 即将发布
第 5 天 Service 与网络基础:ClusterIP、NodePort、LoadBalancer 详解 🔜 即将发布
第 6 天 Namespace 与资源配额:多租户隔离基础 🔜 即将发布
第 7 天 ConfigMap 与 Secret:配置管理最佳实践 🔜 即将发布
第 8-30 天 存储、网络、调度、生产运维、进阶专题 🔜 即将发布
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容