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 集群搭建:
- 基础环境准备:关闭 swap、加载内核模块、设置转发参数
- 容器运行时安装:使用 containerd 作为 CRI 实现
- K8s 工具链安装:kubeadm、kubelet、kubectl 三件套
- 集群初始化:通过 kubeadm 一键初始化 Control Plane
- CNI 网络插件部署:Calico 实现 Pod 间网络互通
- Worker 节点加入:多节点弹性扩展
- 验证与测试:运行 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 天 | 存储、网络、调度、生产运维、进阶专题 | 🔜 即将发布 |















暂无评论内容