跳转至

K8s 1.36.4 集群运行手册(RUNBOOK)

面向接手日常运维与值班的人:拿着就能做,每条操作都给了完整命令与预期输出。 本手册回答"这个集群平时怎么用、怎么查、怎么救";"这次变更改了什么、怎么退"见 k8s_136_cluster_deploy/docs/SOP.md。同一事实只写一处,SOP 需要时链接到本文。

目录

  1. 服务概览 | 2. 接入与凭据 | 3. 日常速查表
  2. 日常操作 | 5. 配置管理 | 6. 备份与恢复
  3. 监控与告警 | 8. 故障处置 | 9. 安全与权限
  4. 容量与性能 | 11. 附录

路径约定:本文命令中的文件路径均相对项目根目录(即本工程所在目录 k8s_ins/)书写; 涉及系统文件(如 /etc/kubernetes/...)时使用绝对路径,因为那是命令本身的参数。

1. 服务概览

项 说明
用途 内部 Kubernetes 学习/测试集群,运行自建工作负载
版本 Kubernetes v1.36.4,容器运行时 containerd 2.3.x
拓扑 单控制面:k8s-master-01;工作节点 k8s-node-01/02/03
控制面入口 VIP 192.168.31.8:16443(haproxy → apiserver 6443),VIP 由 keepalived 持有
网络 Pod 10.244.0.0/16,Service 10.96.0.0/12(Calico 3.32.2,Tigera Operator,IPIPCrossSubnet)
附加组件 metrics-server v0.9.0(kubectl top)、Headlamp v0.45.0(Web 控制台)
已下线 k8s-master-02/03 虚拟机(关机、autostart 禁用、磁盘保留);见 SOP 5.10 可一键扩回
依赖 全部虚拟机位于同一台 KVM 宿主机;宿主机或存储故障将同时影响所有节点
业务影响 控制面不可用时:已有 Pod 继续运行,但无法创建/修改/删除任何资源,kubectl 全部失败
重要性等级 学习环境(非生产);无 SLA,但故障会导致实验中断

组件清单:

组件 位置 作用
kube-apiserver / etcd / controller-manager / scheduler k8s-master-01(静态 Pod,kube-system) 控制面四件套
etcd 数据目录 /var/lib/etcd(独立盘 /dev/vdb,10G xfs) 集群唯一数据存储
keepalived + haproxy k8s-master-01 提供 VIP 192.168.31.8:16443
kubelet / containerd 全部 4 台在线节点 节点代理与运行时
calico-node / typha / kube-controllers calico-system CNI 与网络策略
metrics-server kube-system 资源指标(kubectl top)
Headlamp kube-system Web 控制台(ClusterIP,需端口转发访问)

2. 接入与凭据

项 值 / 位置
管理入口 本机(dell-R620)已装 kubectl v1.36.4,直接 kubectl 即可(context:kubernetes-admin@kubernetes)
集群侧 kubeconfig 各 master 的 /etc/kubernetes/admin.conf;root 的 /root/.kube/config
节点 SSH root@192.168.31.10–.15,端口 22,密钥认证(口令/密钥路径见配置 config/deploy.yaml,不入本文档)
keepalived 口令 cluster.keepalived_auth_pass(k8s_136_cluster_deploy/config/deploy.yaml)
haproxy stats 账号 cluster.haproxy_stats_user / haproxy_stats_password(同文件),仅监听 127.0.0.1:9000
集群凭据查询 grep -E 'keepalived_auth_pass\|haproxy_stats' k8s_136_cluster_deploy/config/deploy.yaml(路径均相对项目根目录,下同)

客户端接入示例(在任意能连到 VIP 的机器上):

mkdir -p ~/.kube
scp root@192.168.31.10:/etc/kubernetes/admin.conf ~/.kube/config
sed -i 's#https://192.168.31.8:16443#https://192.168.31.8:16443#' ~/.kube/config   # 确认 server 指向 VIP
chmod 600 ~/.kube/config
kubectl get nodes                                          # 预期:4 行,均 Ready

Headlamp 控制台访问(当前为 ClusterIP,不对外暴露):

ssh -L 8080:127.0.0.1:8080 root@192.168.31.10            # 本机开隧道(保持不关)
# 另开终端,在 master-01 上执行:
kubectl -n kube-system port-forward svc/headlamp 8080:80
# 浏览器访问 http://localhost:8080

3. 日常速查表

目的 命令 预期
看节点 kubectl get nodes -o wide 4 行全 Ready
看异常 Pod kubectl get pods -A \| grep -Ev 'Running\|Completed' 无输出
看资源用量 kubectl top nodes 输出 CPU/内存使用
看控制面健康 kubectl get --raw='/readyz?verbose' 末尾 readyz check passed
看 etcd 状态 ssh root@192.168.31.10 "crictl exec \$(crictl ps --name etcd -q \| head -1) etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key endpoint status -w table" IS LEADER=true、IS HEALTHY=true
看 kubelet 日志 ssh root@192.168.31.10 "journalctl -u kubelet --since '30 min ago' -p err" 无新增错误
看 Pod 日志 kubectl -n <ns> logs <pod> --tail=100 --since=30m —
备份 etcd 见 第 6 章 生成 .db 快照
扩回 3 控制面 见 SOP 5.10 etcd 成员 1→3
证书到期检查 ssh root@192.168.31.10 "kubeadm certs check-expiration" 各证书 RESIDUAL TIME 充足

维护铁律:当前 etcd 只有 1 个成员,没有冗余。任何时刻只操作一台节点,不要并行重启/关机; 关闭 k8s-master-01 就等于整个控制面下线。

4. 日常操作

4.1 状态检查

# 集群整体
kubectl get nodes -o wide                                  # 预期:4 行 Ready
kubectl get pods -A -o wide | grep -Ev 'Running|Completed' # 预期:无输出
kubectl get --raw='/readyz?verbose' | tail -3              # 预期:readyz check passed

# 控制面四件套(均为静态 Pod,位于 kube-system)
kubectl -n kube-system get pods -l tier=control-plane      # 预期:etcd / kube-apiserver / controller-manager / scheduler 各 1 个 Running

# CNI
kubectl get tigerastatus                                   # 预期:各行 Available=True
kubectl -n calico-system get pods                          # 预期:calico-node×4、typha、kube-controllers 全 Running

# 宿主机层(以 master-01 为例)
ssh root@192.168.31.10 "systemctl is-active kubelet containerd keepalived haproxy"
# 预期:active active active active

输出不符时:节点非 Ready 见 8.2;Pod 异常见 8.3; 控制面 Pod 缺失见 8.1。

4.2 重启组件

# 重启单个节点的 kubelet(安全,先确认该节点不是唯一控制面)
ssh root@192.168.31.13 "systemctl restart kubelet && systemctl is-active kubelet"   # 预期:active

# 重启工作节点上的容器运行时(高危:该节点所有容器会被重启)
ssh root@192.168.31.13 "systemctl restart containerd"                               # 预期:重启后 Pod 自动重建

# 重启控制面某组件(高危):静态 Pod 由 kubelet 管理,移动 manifest 即可重建
ssh root@192.168.31.10 "mv /etc/kubernetes/manifests/kube-scheduler.yaml /tmp/ && sleep 20 && mv /tmp/kube-scheduler.yaml /etc/kubernetes/manifests/"
# 预期:20 秒内 kube-scheduler 新 Pod 出现并 Running

不要用 systemctl restart kube-apiserver 之类的命令——控制面组件由 kubelet 以静态 Pod 方式托管。

4.3 扩缩容

# 控制面缩容到单 master(双向工具,幂等;必须先看预演)
cd k8s_136_cluster_deploy                          # 相对项目根目录
.venv/bin/python control_plane_scale.py --config config/deploy.yaml --expand --dry-run
.venv/bin/python control_plane_scale.py --config config/deploy.yaml --expand   # 扩回 3 master

# 工作节点扩容(新节点需已具备 containerd/kubelet,或先跑部署工程完成基线)
ssh root@192.168.31.10 "kubeadm token create --print-join-command"             # 取 join 命令
ssh root@<新节点IP> "<上一步输出的 kubeadm join 命令>"
kubectl get nodes                                                              # 预期:新节点出现并转为 Ready

4.4 查看日志

# 控制面组件(静态 Pod 日志)
kubectl -n kube-system logs etcd-k8s-master-01 --tail=50
kubectl -n kube-system logs kube-apiserver-k8s-master-01 --tail=50
# 仅看最近 30 分钟的错误
kubectl -n kube-system logs kube-apiserver-k8s-master-01 --since=30m | grep -Ei 'error|fail|timeout|deadline'

# 节点代理日志(journald)
ssh root@192.168.31.10 "journalctl -u kubelet --since '1 hour ago' | tail -50"
ssh root@192.168.31.10 "journalctl -u containerd --since '1 hour ago' -p err | tail -30"

# CNI
kubectl -n calico-system logs -l k8s-app=calico-node --tail=50 --since=30m

4.5 进入容器与主机排障

# 进入 Pod
kubectl -n <ns> exec -it <pod> -- sh
# 节点上的容器运行时排查(需先装 cri-tools,已装)
ssh root@192.168.31.13 "crictl ps -a | head -20"            # 容器清单(含已退出)
ssh root@192.168.31.13 "crictl logs <container-id> | tail -50"
ssh root@192.168.31.13 "crictl inspect <container-id> | grep -A3 exitCode"

5. 配置管理

配置 位置 修改方式 生效方式
部署工程参数 k8s_136_cluster_deploy/config/deploy.yaml 编辑后重跑工程(幂等) 重跑 main.py,仅差异项被变更
kubelet 参数 /var/lib/kubelet/config.yaml(各节点) 不要手改,由 kubeadm 生成 systemctl restart kubelet
控制面参数 /etc/kubernetes/manifests/*.yaml 编辑后 kubelet 自动重建该静态 Pod 保存即生效(约 20–60 秒)
集群级配置 ConfigMap kubeadm-config(kube-system) kubectl -n kube-system edit cm kubeadm-config 影响后续 kubeadm join/upgrade
keepalived /etc/keepalived/keepalived.conf(master) 手工编辑或由工程重跑覆盖 systemctl restart keepalived
haproxy /etc/haproxy/haproxy.cfg(master) 同上 systemctl restart haproxy
SELinux(haproxy 入口依赖) 策略存储:semanage port -l \| grep 16443、getsebool haproxy_connect_any semanage port -a -t http_port_t -p tcp 16443、setsebool -P haproxy_connect_any on 立即生效并随重启保留(-P 持久)。Enforcing 下缺这两项会让 haproxy 启动失败(第 8 章场景 1)
Calico CRD:kubectl get installation.operator.tigera.io default -o yaml kubectl edit(改 IPPool 等) Operator 自动 reconcile

易错点:

  • baseline.disable_selinux 已于 2026-09-29 由 true 改为 false(原值会在重跑时执行 setenforce 0 并把 /etc/selinux/config 写成 SELINUX=disabled,见 k8s-deploy-yaml-selinux-20260929/SOP.md)。若改回 true 再重跑,本机 haproxy 等依赖 SELinux 策略的服务会失去约束基础
  • 重跑本工程会按 config/deploy.yaml 中全部 role=master 节点重写 haproxy 后端列表——当前定义 3 台,其中 .11/.12 虚机已关闭,故重跑会把已被手工清理掉的后端写回(_write 为哈希比对后覆盖);缩容/扩回工具 control_plane_scale.py 不写此文件,不受影响
  • 改 config/deploy.yaml 里的 VIP / 网卡 / 节点 IP 后重跑,会触发 keepalived/haproxy 重写与重启(高危,会短暂中断 VIP)
  • Calico 的 ipPools[0].cidr 不要随意改;改池会导致已有 Pod IP 失效(需重建 Pod)
  • kubeadm-config 里若残留过期 ClusterStatus,会让 kubeadm join --control-plane 误判成员已存在——扩回工具已自动处理

6. 备份与恢复

6.1 备份策略

对象 方式 位置
etcd 数据 etcdctl snapshot save 远端 /var/lib/etcd/snapshot_*.db,再下载到工程 backups/<时间戳>/
宿主配置 部署/变更前自动打包 各节点 /root/k8s_backup_<时间戳>/host_config.tgz
覆盖前的单文件 自动 .bak.<时间戳> 原文件同目录(工程 --rollback 依赖此约定)

完整台账与清理时机见 k8s_136_cluster_deploy/backup/README.md。

6.2 手工备份 etcd(随时可做,只读)

ssh root@192.168.31.10 'cid=$(crictl ps --name etcd -q | head -1); \
  crictl exec "$cid" etcdctl --endpoints=https://127.0.0.1:2379 \
    --cacert=/etc/kubernetes/pki/etcd/ca.crt \
    --cert=/etc/kubernetes/pki/etcd/server.crt \
    --key=/etc/kubernetes/pki/etcd/server.key \
    snapshot save /var/lib/etcd/snapshot_manual_$(date +%Y%m%d_%H%M%S).db'
# 预期:输出 "Snapshot saved at /var/lib/etcd/snapshot_manual_<时间戳>.db"
ssh root@192.168.31.10 "ls -lh /var/lib/etcd/snapshot_manual_*.db | tail -3"

6.3 恢复 etcd(高危,须停机,影响整个控制面)

# 1) 停控制面(移开 etcd 与 apiserver 的静态 Pod 清单)
ssh root@192.168.31.10 "mkdir -p /tmp/manifests_off && \
  mv /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/manifests_off/"
ssh root@192.168.31.10 "crictl pods | grep -c etcd || true"      # 预期:0(已停)

# 2) 备份现有数据目录并执行恢复
ssh root@192.168.31.10 "mv /var/lib/etcd /var/lib/etcd.bak.$(date +%Y%m%d-%H%M%S)"
ssh root@192.168.31.10 'cid=$(crictl ps -a --name etcd -q | head -1); \
  crictl exec "$cid" etcdctl snapshot restore /var/lib/etcd/<快照文件> --data-dir /var/lib/etcd'
# 预期:输出 "2026-xx-xx ... restored snapshot" 且无报错

# 3) 恢复控制面
ssh root@192.168.31.10 "mv /tmp/manifests_off/*.yaml /etc/kubernetes/manifests/"
kubectl get --raw='/readyz'                                      # 预期:ok
kubectl get nodes                                                # 预期:4 行

恢复后验证:kubectl get nodes、kubectl get pods -A | grep -v Running、kubectl get --raw='/readyz?verbose'。 注意:快照是某一时点的数据,恢复后该时点之后的所有变更(含新建 Pod/Service)会丢失。

演练记录:本环境尚未做过完整的快照恢复演练(待补)。

7. 监控与告警

项 查看方式 关注阈值
节点资源 kubectl top nodes CPU/内存持续 > 80%
Pod 资源 kubectl top pods -A --sort-by=memory \| head 单 Pod 接近 limit
etcd 数据量 ssh root@192.168.31.10 "du -sh /var/lib/etcd" 当前 ~300MB;后端配额默认 2GiB
etcd 盘水位 ssh root@192.168.31.10 "df -h /var/lib/etcd" > 80% 需处理(盘仅 10G)
证书余期 ssh root@192.168.31.10 "kubeadm certs check-expiration" 余期 < 90 天需续期
节点 Ready kubectl get nodes 出现非 Ready 立即处置
控制面可用 curl -sk https://192.168.31.8:16443/healthz 非 ok 立即处置
宿主机资源 free -h; nproc(宿主机) 内存/CPU 紧张会影响全部节点

当前未接入任何监控告警系统(无 Prometheus/Grafana/Altertingmanager)。Headlamp 仅提供只读的控制台视图。 如需监控,可沿用 monitoring_upgrade/ 目录中的 kube-prometheus-stack 工程(本次未部署)。

8. 故障处置

场景 1:kubectl 无法连接 apiserver

症状:kubectl get nodes 报 Unable to connect to the server / TLS handshake timeout / context deadline exceeded / connect: connection refused / EOF; curl -sk https://192.168.31.8:16443/healthz 不通。

诊断

# 1) VIP 是否存在(在 master-01 上执行)
ssh root@192.168.31.10 "ip -4 -o addr show | grep 192.168.31.8"     # 预期:有 ens2 上的一条 /32
# 2) 控制面静态 Pod 是否在跑
ssh root@192.168.31.10 "crictl ps --name etcd,kube-apiserver"        # 预期:两个容器 Running
# 3) apiserver 最近是否 Fatal 退出(关键证据)
ssh root@192.168.31.10 "journalctl -u kubelet --since '30 min ago' | grep -Ei 'apiserver|etcd|Fatal' | tail -20"
# 4) etcd 自身状态与成员数
ssh root@192.168.31.10 'cid=$(crictl ps -a --name etcd -q | head -1); crictl logs "$cid" 2>&1 | tail -30'
# 预期:无 "lost the lead" / "failed to commit" / "is starting a new election"
# 5) 入口代理 haproxy 与其 SELinux 约束(宿主机重启后最易踩:SELinux 拦截会让 haproxy 起不来)
ssh root@192.168.31.10 "systemctl is-active haproxy; journalctl -u haproxy --since '-30min' --no-pager | tail -5"
# 预期:active。若为 failed 且含 "cannot bind socket (Permission denied) for [0.0.0.0:16443]" → 见下方 SELinux 分支
ssh root@192.168.31.10 "getenforce; grep 'type=AVC' /var/log/audit/audit.log | grep 'comm=\"haproxy\"' | tail -5"
# 预期:Enforcing 且无 haproxy 的 AVC;出现 name_bind / name_connect 拒绝即为根因

处置(按诊断结果分支)

  • 若 etcd 报反复选举 / no route to host:说明成员数不足(曾有 3 成员,现单成员则不会发生)。 历史对策:启动其他 master 虚机恢复多数派,再重启本机 kubelet 触发静态 Pod 重建: bash sudo virsh start k8s-master-02 # 宿主机上执行 ssh root@192.168.31.10 "systemctl restart kubelet" # 触发静态 Pod 重建
  • 若 apiserver 容器不存在(kubelet 未拉起): bash ssh root@192.168.31.10 "ls /etc/kubernetes/manifests/ && systemctl restart kubelet"
  • 若 VIP 丢失: bash ssh root@192.168.31.10 "systemctl restart keepalived haproxy && ip -4 -o addr show | grep 192.168.31.8"
  • 若 haproxy 为 failed,且日志含 cannot bind socket (Permission denied) for [0.0.0.0:16443]: SELinux 拦截。Enforcing 下 haproxy_t 既不能绑 16443,也不能连后端 6443;restart 无效,须补策略(持久): bash ssh root@192.168.31.10 "dnf -q install -y policycoreutils-python-utils" # 提供 semanage(缺失时) ssh root@192.168.31.10 "semanage port -a -t http_port_t -p tcp 16443" # 允许绑定入口端口 ssh root@192.168.31.10 "setsebool -P haproxy_connect_any on" # 允许连接后端 6443 ssh root@192.168.31.10 "systemctl restart haproxy" 回滚:semanage port -d -t http_port_t -p tcp 16443 与 setsebool -P haproxy_connect_any off。

验证:curl -sk https://192.168.31.8:16443/healthz 返回 ok,且 kubectl get nodes 正常。 完整根因与证据见 k8s_136_cluster_deploy/docs/INCIDENT-20260916-etcd-quorum-lost.md(etcd quorum 场景) 与 k8s-restart-16443-selinux-20260929/SOP.md(SELinux 场景)。

场景 2:节点 NotReady

症状:kubectl get nodes 中某节点 NotReady;其上 Pod 变为 Unknown/停止调度。

诊断

NODE_IP=192.168.31.13                                             # 换成故障节点 IP
kubectl describe node k8s-node-01 | grep -A5 Conditions           # 看 Ready 条件与 Reason
ssh root@$NODE_IP "systemctl is-active kubelet containerd"        # 预期:active active
ssh root@$NODE_IP "journalctl -u kubelet --since '30 min ago' -p err | tail -20"
ssh root@$NODE_IP "df -h /var/lib/kubelet; free -m"               # 磁盘满或内存耗尽会导致 NotReady
ssh root@$NODE_IP "crictl ps | wc -l"                             # containerd 是否有响应

处置

  • kubelet 未运行 → ssh root@$NODE_IP "systemctl restart kubelet",等 30 秒复查
  • 磁盘/内存耗尽 → 清理空间或重启节点(先 kubectl drain 迁走业务): bash kubectl drain k8s-node-01 --ignore-daemonsets --delete-emptydir-data # 高危:会驱逐该节点业务 Pod ssh root@$NODE_IP "reboot" kubectl uncordon k8s-node-01
  • containerd 无响应 → ssh root@$NODE_IP "systemctl restart containerd"

验证:kubectl get nodes 中该节点回到 Ready;kubectl get pods -A -o wide | grep <node> 无异常。

场景 3:Pod 无法调度或持续 Pending

症状:kubectl get pods -A 出现 Pending;describe 事件里有 Insufficient cpu/memory 或 0/4 nodes are available。

诊断

kubectl -n <ns> describe pod <pod> | tail -20                     # 看 Events 段的失败原因
kubectl describe nodes | grep -A5 "Allocated resources"           # 看各节点已分配资源
kubectl get nodes --show-labels | grep -v control-plane           # 确认可调度节点
kubectl get pods -A --field-selector status.phase=Pending         # 全局 Pending 清单

处置

  • 资源不足 → 扩容节点或调低 requests;确认工作节点未被 cordon(kubectl get nodes 若含 SchedulingDisabled,用 kubectl uncordon <node>)
  • 污点阻拦 → kubectl describe node <node> | grep Taints,必要时 kubectl taint nodes <node> <key>-
  • 镜像拉取失败(ImagePullBackOff)→ 见场景 5

验证:Pod 转为 Running(或 Completed),kubectl get pods -A | grep -v Running 无输出。

场景 4:Pod 之间网络不通

症状:跨节点 Pod 无法互访;kubectl exec 内 ping/curl 超时;DNS 解析失败。

诊断

kubectl get tigerastatus                                          # 预期:Available=True(若 False 即 CNI 异常)
kubectl -n calico-system get pods -o wide | grep -v Running       # 是否有 calico-node 未 Running
kubectl get ippools.crd.projectcalico.org -o yaml | grep cidr     # 预期:10.244.0.0/16
kubectl -n calico-system logs -l k8s-app=calico-node --tail=50 --since=30m | grep -Ei 'error|fail'
# DNS 专项
kubectl -n kube-system get pods -l k8s-app=kube-dns               # 预期:coredns 2 个 Running
kubectl run dnstest --rm -it --image=registry.k8s.io/e2e-test-images/agnhost:2.45 -- \
  /agnhost dns-check kubernetes.default                              # 预期:解析出 ClusterIP

处置

  • calico-node 异常 → kubectl -n calico-system rollout restart daemonset/calico-node
  • IPPool 与实际不符 → 不要随意改池,需评估后重建受影响 Pod
  • CoreDNS 异常 → kubectl -n kube-system rollout restart deploy/coredns,并检查其上游 (kubectl -n kube-system get cm coredns -o yaml | grep forward,本环境上游为 192.168.31.2)
  • 节点间隧道异常(IPIP 模式)→ 确认 ipip 模块已加载:ssh root@<node> "lsmod | grep ipip"

验证:kubectl run 的临时 Pod 能解析并连通 kubernetes.default;业务 Pod 互访恢复。

场景 5:镜像拉取失败

症状:Pod 处于 ImagePullBackOff / ErrImagePull。

诊断

kubectl -n <ns> describe pod <pod> | grep -A3 Events              # 看具体错误:超时 / 401 / not found
# 在目标节点上直接测拉取
ssh root@192.168.31.13 "crictl pull <镜像地址>"                    # 预期:成功;失败会给出明确原因
# 外网通路(本环境经旁路网关访问海外)
ssh root@192.168.31.13 "curl -sI --max-time 20 -o /dev/null -w '%{http_code}\n' https://quay.io/v2/"   # 预期:401

处置

  • 网络不通 → 检查节点 DNS(应为 192.168.31.2)与旁路通路;本环境海外直连带宽仅 300–450KB/s,大镜像需等待
  • 镜像地址错 → 用 kubectl set image 或改清单后重新 apply
  • 私有仓库需凭据 → kubectl -n <ns> create secret docker-registry ... 并在 Pod 中引用

验证:Pod 转为 Running;ssh root@<node> "crictl images | grep <镜像>" 能看到镜像。

9. 安全与权限

项 说明
认证 kubeconfig 中的客户端证书(kubernetes-admin,属 system:masters 组)
授权 集群内置 RBAC;未启用审计日志与 PodSecurity 强制策略
证书位置 /etc/kubernetes/pki/(CA、apiserver、etcd、front-proxy 等),权限 644/600,仅 root 可读私钥
证书有效期 非 CA 证书 1 年、CA 10 年(kubeadm 显式设置);到期前须续期
kubeconfig /etc/kubernetes/admin.conf(权限 600),含集群管理员权限——等同集群 root,勿外传
haproxy stats 仅监听 127.0.0.1:9000 且启用认证
SELinux / firewalld 已禁用(学习环境取舍),见 SOP 第 8 章风险表
SSH root 密钥登录(口令为空时不启用密码登录),密钥由使用者保管

证书续期(到期前 90 天执行,高危:会重启控制面组件):

ssh root@192.168.31.10 "kubeadm certs check-expiration"            # 先看余期
ssh root@192.168.31.10 "kubeadm certs renew all"                   # 续期
ssh root@192.168.31.10 "systemctl restart kubelet"                 # 重建静态 Pod 使新证书生效
ssh root@192.168.31.10 "kubeadm certs check-expiration"            # 复查余期
# 注意:续期后需同步更新 ~/.kube/config(客户端证书也变了)
ssh root@192.168.31.10 "cat /etc/kubernetes/admin.conf" > ~/.kube/config && chmod 600 ~/.kube/config

10. 容量与性能

当前水位基线(2026-09-16 实测):

项 数值
在线节点 4 台:master-01(4 vCPU / 8GiB)、node-01/02/03(各 8 vCPU / 16GiB)
控制面用量 CPU ~0.5 核、内存 ~0.9–1.6 GiB
etcd 数据目录 /var/lib/etcd(独立盘 10G xfs),当前占用约 300MB
etcd 后端配额 默认 2 GiB(超限即只读告警)
宿主机 32 vCPU / 117 GiB,已用约 18 GiB
海外拉取带宽 300–450 KB/s(大镜像需耐心)

扩容触发条件与操作

  • 工作负载资源不足 → 新增工作节点(见 4.3)
  • 需要控制面冗余 → control_plane_scale.py --expand 扩回 3 master(etcd 恢复 3 成员)
  • etcd 盘使用率 > 80% → 先确认是否为历史快照堆积(ls -lh /var/lib/etcd/snapshot_*.db), 清理旧快照;仍不足则需扩容盘(高危,须停控制面)
  • 宿主机资源紧张 → 全部节点都在这台宿主机上,扩容应先在宿主机加资源

已知瓶颈

  1. 单控制面:k8s-master-01 故障即控制面全停(无冗余)
  2. 单宿主机:宿主机宕机则 4 台虚机同时不可用
  3. etcd 单成员:数据无副本,仅依赖快照备份
  4. etcd 盘仅 10G:快照堆积会挤占空间
  5. 海外镜像拉取慢:大镜像首次拉取耗时长

11. 附录

术语表

术语 含义
VIP 虚拟 IP 192.168.31.8,控制面统一入口,由 keepalived 持有
quorum etcd 多数派;单成员集群 quorum=1,无冗余
静态 Pod 由 kubelet 直接从 /etc/kubernetes/manifests/ 托管的 Pod(控制面四件套)
母机 执行部署与集群操作的节点,本环境为 k8s-master-01

相关文档与交付物

文档 用途
k8s_136_cluster_deploy/docs/SOP.md 部署与缩容的变更档案(怎么改、怎么验、怎么退)
k8s_136_cluster_deploy/docs/INCIDENT-20260916-etcd-quorum-lost.md etcd 失多数派故障复盘
k8s_136_cluster_deploy/backup/README.md 备份台账(含清理时机)
k8s_136_cluster_deploy/config/deploy.yaml.example 全部可配置项与注释

修订记录

日期 修改人 变更内容
2026-09-16 运维(AI 辅助) 初版:集群由 3 master HA 缩容为单 master,按 writing-ops-change-sop 规范补建本手册

来源:/home/rain/Documents/k8s_ins/k8s_136_cluster_deploy/docs/RUNBOOK.md | 最后更新:2026-09-29 20:54(由 build/sync.py 同步,请勿在站点侧修改)