📘 Day 02:多节点集群与节点管理
🎯 今日目标
🧠 理论精讲(30 分钟)
Join 流程
1 2 3 4 5 6 7 8 9 10
| Worker 节点 Master 节点 │ │ │── kubeadm join ────────────→│ token 验证 │ (token + discovery-hash) │ TLS bootstrap │ │ 颁发客户端证书 │←── 下发 kubeconfig ────────│ │ │ │── kubelet 启动 ────────────→│ 上报 Node 资源 │ │ │←── 分配 Pod (CNI IP) ──────│
|
关键参数:
--token:集群加入凭证,默认有效期 24 小时
--discovery-token-ca-cert-hash:CA 证书 hash,防中间人攻击
Node 生命周期
1 2 3 4 5
| Register ──→ Ready ──→ NotReady(>5min) ──→ Pod 驱逐 │ ├── cordon(标记不可调度,已有 Pod 不动) │ └── drain(驱逐 Pod + cordon)
|
Taint / Toleration
| 概念 |
说明 |
类比 |
| Taint(污点) |
打在节点上,排斥 Pod |
“这节点只有特定 Pod 能用” |
| Toleration(容忍) |
配置在 Pod 上,容忍节点污点 |
“我可以忍受这个节点的污点” |
🔧 动手实操(120 分钟)
练习 2.1:搭建 3 节点集群
在所有 3 台服务器上执行 Day 01 的环境准备(不需要 kubeadm init):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
sudo swapoff -a sudo sed -i '/ swap / s/^/#/' /etc/fstab
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter
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
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install -y containerd.io sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl enable containerd
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/ enabled=1 gpgcheck=1 gpgkey=https://pkgs.k8s.io/core:/stable:/v1.29/rpm/repodata/repomd.xml.key EOF sudo dnf install -y kubelet kubeadm kubectl sudo dnf install -y dnf-plugins-core sudo dnf versionlock kubelet kubeadm kubectl
|
在 Master 上获取 join 命令:
1 2 3 4
| kubeadm token create --print-join-command
|
在 Worker 1 和 Worker 2 上执行 join:
1 2
| sudo kubeadm join 10.0.0.1:6443 --token abc123.xxx --discovery-token-ca-cert-hash sha256:yyy
|
在 Master 上验证集群完整:
练习 2.2:节点标签管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| kubectl get nodes --show-labels
kubectl label node k8s-node1 role=worker kubectl label node k8s-node2 role=worker kubectl label node k8s-node1 disk=ssd kubectl label node k8s-node2 disk=hdd
kubectl get nodes -l role=worker kubectl get nodes -l disk=ssd --show-labels
kubectl label node k8s-node1 disk=nvme --overwrite
kubectl label node k8s-node1 disk-
kubectl get nodes k8s-node1 --show-labels
|
练习 2.3:cordon 与 uncordon
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| kubectl create deploy nginx --image=nginx:alpine --replicas=6 kubectl get pod -o wide
kubectl cordon k8s-node1
kubectl get nodes
kubectl scale deploy/nginx --replicas=10 kubectl get pod -o wide
kubectl uncordon k8s-node1 kubectl get nodes
|
练习 2.4:drain 节点排空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| kubectl get pod -o wide | grep k8s-node1
kubectl drain k8s-node1 --ignore-daemonsets --delete-emptydir-data
kubectl get pod -o wide -w
kubectl get nodes
kubectl uncordon k8s-node1
|
练习 2.5:Taint 与 Toleration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| kubectl taint node k8s-node1 db=only:NoSchedule
kubectl create deploy web --image=nginx:alpine --replicas=3 kubectl get pod -o wide
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: db-pod spec: tolerations: - key: "db" operator: "Equal" value: "only" effect: "NoSchedule" containers: - name: db image: nginx:alpine EOF
kubectl get pod db-pod -o wide
kubectl taint node k8s-node2 test=evict:NoExecute
kubectl taint node k8s-node1 db- kubectl taint node k8s-node2 test-
kubectl describe node k8s-node1 | grep -A5 Taints kubectl describe node k8s-node2 | grep -A5 Taints
|
练习 2.6:节点删除与重新加入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| kubectl drain k8s-node2 --ignore-daemonsets --delete-emptydir-data
kubectl delete node k8s-node2
sudo kubeadm reset -f sudo rm -rf /etc/cni/net.d
kubeadm token create --print-join-command
kubectl get nodes
|
🐛 排错练习(30 分钟)
场景 1:Token 过期
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
kubeadm token list
sudo kubeadm token create
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | \ openssl rsa -pubin -outform der 2>/dev/null | \ openssl dgst -sha256 -hex | sed 's/^.* //'
|
场景 2:节点 NotReady — CNI 未初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
kubectl describe node k8s-node2 | grep -A10 Conditions
sudo journalctl -u kubelet -n 50 --no-pager
kubectl get pods -n kube-system -l k8s-app=calico-node -o wide
ls /etc/cni/net.d/
|
🏆 赛题模拟(40 分钟)
⚠️ 严格限时 40 分钟完成下述全部操作
题目:节点管理与高可用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 【初始环境】 1 master(k8s-master)+ 2 worker(k8s-node1, k8s-node2)集群就绪
【操作要求】 1. 给 node1 添加标签 env=production、zone=cn-east 2. 给 node2 添加标签 env=staging、zone=cn-east 3. 创建 Deployment app-prod(3副本),用 nodeSelector 限制到 env=production 4. 创建 Deployment app-staging(2副本),用 nodeSelector 限制到 env=staging 5. 对 node1 执行 drain 排空,要求: - 忽略 DaemonSet - 删除 emptyDir 数据 - 观察 app-prod Pod 迁移到哪个节点(预期迁移到 node2,但 node2 标签不匹配会怎样?) 6. 排空后 uncordon 恢复 node1 7. 给 node1 添加污点 maintenance=true:NoSchedule 8. 修改 app-prod Deployment,添加 Toleration 使之仍能调度到 node1 9. 移除 node1 污点 10. 验证全部 Pod 正常运行
【评分标准】 - 标签操作正确(10 分) - nodeSelector 调度正确(25 分) - drain 操作正确(20 分) - uncordon 恢复(10 分) - 污点与容忍配置正确(25 分) - 最终验证全部 Running(10 分)
|
📋 命令速查
| 命令 |
功能 |
注解 |
kubeadm token create --print-join-command |
生成 Worker 节点加入命令 |
Token 默认 24h 有效,过期需重新生成 |
kubeadm token list |
查看现有 Token |
无可用 Token 时 Worker 无法加入集群 |
kubeadm join <master-ip>:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash> |
Worker 加入集群 |
在 Worker 节点上执行,自动安装 kubelet 并注册节点 |
kubectl get nodes -o wide |
节点列表 + 详细信息 |
显示内网 IP、OS、内核版本、容器运行时 |
kubectl describe node <node-name> |
节点详细信息 |
查看 Conditions(MemoryPressure/DiskPressure/PIDPressure)、Taints、已分配资源 |
kubectl label node <node> key=value |
给节点打标签 |
配合 nodeSelector/nodeAffinity 控制调度 |
kubectl label node <node> key- |
删除节点标签 |
标签名后加 - 即可删除 |
kubectl taint node <node> key=value:NoSchedule |
添加污点 |
无对应 Toleration 的 Pod 无法调度到此节点 |
kubectl taint node <node> key=value:NoSchedule- |
移除污点 |
末尾加 - 删除对应 Taint |
kubectl taint node <node> node-role.kubernetes.io/control-plane- |
去除 Master 污点 |
3 节点以下集群可让 Master 也调度 Pod(学习环境常用) |
kubectl cordon <node> |
标记节点不可调度 |
不会驱逐已有 Pod,仅阻止新 Pod 调度 |
kubectl uncordon <node> |
恢复节点可调度 |
取消 cordon 标记 |
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data |
安全驱逐节点上所有 Pod |
节点维护/下线前必执行;DaemonSet Pod 需 –ignore-daemonsets |
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data --force |
强制驱逐(含不受控制器管理的 Pod) |
裸 Pod(无 ownerReference)需 –force |
kubectl delete node <node> |
删除节点对象 |
节点失联后从集群移除;需先 drain |
systemctl status kubelet |
查看 kubelet 状态 |
节点 NotReady 时首要排查命令 |
journalctl -u kubelet -f |
实时查看 kubelet 日志 |
Pod 启停失败的根因通常在 kubelet 日志 |
journalctl -u kubelet --since "10 min ago" |
查看最近 10 分钟 kubelet 日志 |
时间范围过滤,定位近期异常 |
📚 参考来源
📝 今日笔记模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 日期:____年____月____日 用时:____小时____分
✅ 完成项: □ 3 节点集群搭建 □ 练习 2.1-2.6 □ 排错练习 1-2 □ 赛题模拟
❓ 遇到的问题与解决方案: 1. 2.
📌 关键收获: 1. cordon vs drain 的区别 2. Taint/Toleration 的使用场景 3.
|