Appearance
kubeadm 单主集群
Kubernetes 自建集群常见几种部署方式,差异主要在自动化程度、控制平面高可用和资源占用:
| 部署方式 | 适合场景 | 位置 |
|---|---|---|
| kubeadm 单主 | 结构清楚,适合理解控制平面、节点加入和基础组件关系 | 02 |
| kubeadm 高可用 | 多控制平面和 API Server 高可用入口 | 03 |
| Kubespray | 批量交付、Ansible 管理和更完整的集群参数 | 04 |
| K3s | 小规格环境、边缘场景和轻量 Kubernetes 集群 | 05 |
kubeadm 单主集群保留了标准 Kubernetes 组件形态,控制平面和工作节点关系比较清楚。理解组件关系之后,kubectl 命令、YAML 示例和排错思路在 kubeadm、Kubespray、K3s 等部署方式下都能复用。
Kubernetes 组件不少——apiserver、etcd、scheduler、controller-manager、kubelet、containerd、kube-proxy、CNI。全部手工二进制部署时,每个组件的证书、配置、启动参数、systemd unit 都要自己写,出问题后排查链路也更长。
kubeadm 用一条 init 命令拉起控制平面,一条 join 命令加入节点。它把证书生成、配置分发、静态 Pod manifest 写入、kubeconfig 创建这些事自动化了,同时保留了对每个组件配置文件的查看和修改入口。适合搭建结构清楚、便于理解组件关系的集群。
单控制平面适合实验、测试和内部验证;生产环境需要多控制平面加 API Server 高可用入口(见控制平面高可用)。
环境规划
实验环境用一台控制平面和两台工作节点:
| 主机名 | IP | 角色 |
|---|---|---|
k8s-master01 | 192.168.10.11 | 控制平面 |
k8s-node01 | 192.168.10.12 | 工作节点 |
k8s-node02 | 192.168.10.13 | 工作节点 |
网段提前定好,初始化后改起来成本很高:
| 项目 | 示例 | 说明 |
|---|---|---|
| Node 网段 | 192.168.10.0/24 | 服务器真实网段 |
| Pod 网段 | 10.244.0.0/16 | Pod IP 池,不能和内网、VPN、Docker 网段冲突 |
| Service 网段 | 10.96.0.0/12 | ClusterIP 地址池 |
| API Server | 192.168.10.11:6443 | 单主环境直接用控制平面 IP |
版本用变量管理,避免后面命令里写死版本号:
bash
K8S_VERSION="1.36.0" # kubeadm/kubelet/kubectl 尽量同一补丁版本
K8S_MINOR="v1.36" # 官方仓库按 minor 版本组织
POD_CIDR="10.244.0.0/16" # 和 CNI 插件配置保持一致
SVC_CIDR="10.96.0.0/12" # Service 网段初始化后不适合改系统初始化——所有节点
主机名和解析:
bash
hostnamectl set-hostname k8s-master01 # 每台按实际角色改
cat >> /etc/hosts <<'EOF'
192.168.10.11 k8s-master01
192.168.10.12 k8s-node01
192.168.10.13 k8s-node02
EOF关闭 swap——kubelet 在 swap 开启时无法准确统计内存使用,Pod 的 requests/limits 和 QoS 判断会失效:
bash
swapoff -a
sed -ri '/\sswap\s/s/^/#/' /etc/fstab # 防止重启后 swap 自动挂回来内核模块和参数。br_netfilter 让 bridge 流量经过 iptables——CNI 策略和 kube-proxy 转发都依赖这个:
bash
cat > /etc/modules-load.d/k8s.conf <<'EOF'
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
cat > /etc/sysctl.d/99-kubernetes-cri.conf <<'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system时间同步。节点时间漂移会影响证书校验、Token 有效期、etcd 一致性——看起来像认证失败的问题底层可能只是 NTP 没同步:
bash
systemctl enable --now chronyd
chronyc sources -v安装 containerd
kubelet 通过 CRI 接口调用容器运行时。containerd 的 cgroup 驱动要和 kubelet 一致——两边都用 systemd,否则容器资源统计异常:
RHEL / Rocky / CentOS:
bash
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y containerd.io cri-toolsUbuntu:
bash
apt-get update
apt-get install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
-o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo \"${UBUNTU_CODENAME:-$VERSION_CODENAME}\") stable" \
> /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install -y containerd.io cri-tools生成配置——关键是把 SystemdCgroup 改成 true:
bash
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl enable --now containerd配置 crictl,让它知道容器运行时 socket 在哪:
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
crictl info | head # 能返回运行时信息,说明 CRI 通道正常安装 kubeadm、kubelet、kubectl
RHEL 系列用官方 rpm 仓库:
bash
cat > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/${K8S_MINOR}/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/${K8S_MINOR}/rpm/repodata/repomd.xml.key
EOF
yum install -y kubelet-${K8S_VERSION} kubeadm-${K8S_VERSION} kubectl-${K8S_VERSION} \
--disableexcludes=kubernetes
systemctl enable --now kubelet
# kubeadm 写入配置前 kubelet 缺少 /etc/kubernetes/manifests/ 下的静态 Pod manifest,
# 会反复重启——这是正常的,等 init 完成后就好了Ubuntu 系列:
bash
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gpg
mkdir -p /etc/apt/keyrings
curl -fsSL "https://pkgs.k8s.io/core:/stable:/${K8S_MINOR}/deb/Release.key" \
| gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/${K8S_MINOR}/deb/ /" \
> /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl
systemctl enable --now kubelet初始化控制平面
用配置文件初始化比命令行参数更清楚,也方便留档:
yaml
# kubeadm-init.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: v1.36.0
imageRepository: registry.aliyuncs.com/google_containers
networking:
podSubnet: 10.244.0.0/16
serviceSubnet: 10.96.0.0/12
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemdbash
kubeadm init --config kubeadm-init.yaml --upload-certskubeadm init 实际做了几件事:生成 CA 和组件证书、写 kubeconfig、生成静态 Pod manifest(etcd.yaml、kube-apiserver.yaml、kube-controller-manager.yaml、kube-scheduler.yaml)放入 /etc/kubernetes/manifests/、启动 kubelet 拉起这些静态 Pod。
配置 kubectl:
bash
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown "$(id -u):$(id -g)" $HOME/.kube/config
kubectl get nodes # CNI 安装前,控制平面节点通常是 NotReady——没有 CNI 时 Pod 网络未就绪安装 Calico
Calico 是生产环境常见的 CNI,支持 BGP、VXLAN、IPIP 和 NetworkPolicy:
bash
curl -L -o calico.yaml https://raw.githubusercontent.com/projectcalico/calico/v3.31.0/manifests/calico.yaml
# 如果 kubeadm 的 Pod 网段不是 Calico 默认值 (192.168.0.0/16),需要改 CALICO_IPV4POOL_CIDR
grep -n "CALICO_IPV4POOL_CIDR" calico.yaml
kubectl apply -f calico.yaml
kubectl -n kube-system get pods -l k8s-app=calico-node -o wideCNI 安装完成后,控制平面节点从 NotReady 变为 Ready——CNI Pod 在节点上运行并完成网络初始化。国内环境拉 quay.io 镜像可能很慢,更稳的做法是提前把 Calico 镜像同步到内部 Harbor 再改 manifest 里的镜像地址。
加入工作节点
kubeadm init 成功后会输出 join 命令。在工作节点上执行:
bash
kubeadm join 192.168.10.11:6443 \
--token <token> \
--discovery-token-ca-cert-hash sha256:<hash>join 过程:kubelet 用 token 和 CA hash 向 API Server 注册,获取证书,下载集群配置,启动 kube-proxy 等组件。Token 过期时,在控制平面重新生成:
bash
kubeadm token create --print-join-command节点长时间 NotReady 时,看 kubelet 和容器运行时:
bash
systemctl status kubelet --no-pager
journalctl -u kubelet -n 100 --no-pager
crictl ps -a基础验证
CNI 就绪且所有节点 Ready 后,跑一个测试 Pod 验证调度→拉镜像→Service 转发链路:
bash
kubectl create namespace demo
kubectl -n demo run nginx-test --image=nginx:1.26 --port=80
kubectl -n demo expose pod nginx-test --port=80 --target-port=80
kubectl -n demo get pod,svc -o wide
# 临时访问测试
kubectl -n demo port-forward svc/nginx-test 8080:80
curl http://127.0.0.1:8080/集群 Ready 说明控制面和基础网络大致可用,不代表镜像仓库、存储、Ingress/Gateway 和监控都已经配好。