Appearance
kubeadm 单主集群
kubeadm 适合搭建结构清楚、便于理解组件关系的 Kubernetes 集群。单控制平面适合实验、测试和内部验证;生产环境则需要多控制平面加 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 性能和行为会异常:
bash
swapoff -a
sed -ri '/\sswap\s/s/^/#/' /etc/fstab # 防止重启后 swap 自动挂回来内核模块和参数。br_netfilter 让 bridge 流量经过 iptables,这是 kube-proxy 和 CNI 策略生效的前提:
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 一致性,看起来像认证失败的问题底层可能只是时间不准:
bash
systemctl enable --now chronyd
chronyc sources -v安装 containerd
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生成配置。kubelet 使用 systemd 管理 cgroup,containerd 的 cgroup 驱动也要改成 systemd——两边不一致会导致容器资源统计异常:
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 会反复重启,这是正常的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 # 避免系统升级顺手升级 Kubernetes 组件
systemctl enable --now kubeletkubelet 版本不能高于 kube-apiserver。后面升级集群时,一般先升控制平面,再逐台升工作节点。
初始化控制平面
用配置文件初始化比命令行参数更清楚,也方便留档:
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 # 和后面 CNI 插件保持一致
serviceSubnet: 10.96.0.0/12 # ClusterIP 地址池
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd # 和 containerd SystemdCgroup 保持一致bash
kubeadm init --config kubeadm-init.yaml --upload-certs配置 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/etc/kubernetes/admin.conf 是集群最高权限的 kubeconfig,适合管理节点使用。日常操作更适合单独做 RBAC 和 kubeconfig,按人分配权限。
安装 Calico
Calico 是生产环境常见的 CNI,支持 BGP、VXLAN、IPIP 和 NetworkPolicy。实验环境也可以用 Flannel,概念更少:
bash
curl -L -o calico.yaml https://raw.githubusercontent.com/projectcalico/calico/v3.31.0/manifests/calico.yaml
# 如果 kubeadm 的 Pod 网段不是 Calico 默认值,需要改 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 wide国内环境拉 quay.io 镜像可能很慢。更稳的做法是提前把 Calico 镜像同步到内部 Harbor,再改 manifest 里的镜像地址。
加入工作节点
kubeadm 初始化成功后会输出 join 命令。在工作节点上执行:
bash
kubeadm join 192.168.10.11:6443 \
--token <token> \
--discovery-token-ca-cert-hash sha256:<hash>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基础验证
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 describe pod nginx-test
# 临时访问
kubectl -n demo port-forward svc/nginx-test 8080:80
curl http://127.0.0.1:8080/集群 Ready 说明控制面和基础网络大致可用,不代表镜像仓库、存储、Ingress/Gateway 和监控都已经配好。