AI Infra 训练营
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • Day 0 · 新手接管 Runbook
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
命令手册
HiHuo 主站
GitHub
总览
  • 总览
  • 完整安装
  • 核心 K8s
  • Cilium 网络
  • Longhorn 存储
  • 监控日志
  • CI / GitOps
  • 安全准入
  • Day 0 · 新手接管 Runbook
  • Day 1 · 集群起步 + CNI
  • Day 2 · 控制面 + etcd
  • Day 3 · CRD + Operator + Webhook
  • Day 4 · 存储深度
  • Day 5 · 卷扩容 + 安全
  • Day 6 · 调度 + 可观测
  • Day 7 · Harbor + ArgoCD + Mesh
  • Day 8 · AI Infra
  • Day 9 · Triton + GPU
  • Day 10 · MIG + HPA + 量化
  • Day 11 · AI Agent 端到端
  • Day 12 · 灾备
  • Day 13 · Operator + 联邦 + Mesh + RAG
  • Day 14 · CKA / CKS + 总结
  • LLM 训练手册
  • RAG + Agent 手册
  • 推理优化手册
  • 上下文工程手册
  • Agent 开发手册
  • 面试深度复盘
  • 训练 v2 深度手册
  • 心智模型
  • 看懂命令输出
  • 容器网络底层
  • K8s 网络深入
  • DNS 全套
  • 故障排查方法论
  • 心智模型
  • 容器挂载完整指南
  • K8s Volumes 大全
  • PV/PVC/CSI 深入
  • NFS 深入
  • 分布式存储概览
  • 故障排查 runbook
命令手册
HiHuo 主站
GitHub
  • Day 0 · 环境与硬件

    • Day 0 新手现场接管 Runbook:先看懂,再动手
    • Day 0:5 节点裸 Ubuntu → K8s 装机基线
  • Week 1:K8s 内核 + 周边基础设施

    • Day 1:3 CP HA 集群 + CNI 选型 + DNS 调优
    • Day 2:控制面 deep dive + etcd 内核 + chaos drill
    • Day 3:CRD + Operator (kubebuilder 从 0 写)
    • Day 4:Longhorn 存储 + Cilium 二探(Hubble / NetworkPolicy / L7)
    • Day 5:PVC 在线扩容 + K8s 安全基线(RBAC / PSA / Secret 加密 / Kyverno)
    • Day 6:调度策略 + Prometheus / Loki 观测栈
    • Day 7:Harbor 私有镜像 + ArgoCD GitOps + Cilium WireGuard
  • Week 2:制品 + GitOps + AI Infra + 综合

    • Day 8:k3s 单节点 + NVIDIA Device Plugin + vLLM 跑 Qwen2.5-3B
    • Day 8(attempt 1):跨 WAN GPU 加入主集群(失败复盘)
    • Day 8:AlertManager 真接入 + PrometheusRule 实战
    • Day 8:集群内 CI 闭环 — Gitea + Jenkins + Kaniko
    • Day 9:Triton 多框架推理 + DCGM 跨集群可观测 + vLLM 实测
    • Day 10:MIG 硬切片 + AWQ 量化 + HPA Custom Metrics
    • Day 11:AI 业务端到端 —— chainlit + GitOps + 跨 WAN vLLM
    • Day 12:灾难恢复 + 生产事故注入
    • Day 13:LLM Operator + 多集群联邦 + Ambient Mesh + RAG
    • Day 14:CKA / CKS 真题演练 + 14 天技术栈横向汇总

Day 0 新手现场接管 Runbook:先看懂,再动手

这篇是给完全没接触过 K8s 的人用的现场操作版。目标不是一次把所有组件讲完,而是先学会三件事:

  1. 这 5 台机器分别是什么角色。
  2. 怎么用命令确认集群是否健康。
  3. 出问题时先看哪里、为什么这么看。

本文所有命令都按“先读状态,再改配置”的顺序写。读状态的命令不会改变机器;写配置的命令会明确标出来。


0. 当前真实机器

公网 IP内网 IPhostname角色说明
154.201.73.3110.0.24.31k8s-cp-1control plane第一个控制面节点,kubeadm init 所在节点
154.201.73.8110.0.24.29k8s-cp-2control plane第二个控制面节点
45.205.31.21410.0.24.32k8s-cp-3control plane第三个控制面节点
45.205.31.18010.0.24.28k8s-w-1worker业务负载节点
45.205.31.1010.0.24.30k8s-w-2worker业务负载节点

control plane 是什么:K8s 的“大脑”。里面跑 apiserver、scheduler、controller-manager、etcd。你用 kubectl 发的命令先进 apiserver,再由控制面决定集群怎么变。

worker 是什么:真正跑业务 Pod 的机器。worker 上最重要的是 kubelet 和 containerd。

etcd 是什么:K8s 的数据库。Deployment、Service、Secret、节点状态都存在 etcd。3 个 control plane 会组成 3 节点 etcd,坏 1 个还能工作。


1. 第一步只做探测

先确认 SSH 能连、机器名是什么、内网 IP 是什么、系统版本是什么。

for ip in 154.201.73.31 154.201.73.81 45.205.31.214 45.205.31.180 45.205.31.10; do
  ssh -o BatchMode=yes -o ConnectTimeout=8 root@$ip '
    echo PUBLIC_IP='"$ip"'
    echo HOSTNAME=$(hostname)
    echo IPS=$(hostname -I)
    . /etc/os-release && echo OS="$PRETTY_NAME"
    echo KERNEL=$(uname -r)
    echo VIRT=$(systemd-detect-virt || true)
    echo CONTAINER=$(systemd-detect-virt --container || true)
  '
done

命令解释:

  • ssh root@$ip '...':登录远端机器并执行引号里的命令。
  • BatchMode=yes:只用密钥登录,不弹密码交互;自动化脚本必须这样写。
  • hostname:看机器名,K8s 节点名通常就用它。
  • hostname -I:看这台机器的所有 IP,重点找 10.0.24.x 内网地址。
  • systemd-detect-virt:确认是不是 KVM/VMware 这种真虚拟机。LXC 容器里跑 K8s 会很痛苦。

2. 看集群是否健康

在任意 control plane 上执行。这里用 k8s-cp-1:

ssh root@154.201.73.31 'kubectl get nodes -o wide'

你应该看到 5 个节点都是 Ready:

NAME       STATUS   ROLES           INTERNAL-IP
k8s-cp-1   Ready    control-plane   10.0.24.31
k8s-cp-2   Ready    control-plane   10.0.24.29
k8s-cp-3   Ready    control-plane   10.0.24.32
k8s-w-1    Ready    <none>          10.0.24.28
k8s-w-2    Ready    <none>          10.0.24.30

命令解释:

  • kubectl:K8s 客户端。你用它跟 apiserver 说话。
  • get nodes:列出集群节点。
  • -o wide:显示更多列,比如节点内网 IP、系统版本、container runtime。
  • Ready:kubelet 正常上报,CNI 网络正常,节点可以调度或运行 Pod。

如果节点是 NotReady,下一步看 kubelet:

ssh root@154.201.73.31 'journalctl -u kubelet --since "10 min ago" --no-pager | tail -80'

kubelet 是什么:每台机器上的 K8s 代理。它负责向 apiserver 汇报节点状态,也负责让 containerd 启动/停止 Pod。


3. 当前集群组件一览

ssh root@154.201.73.31 'helm list -A'

当前集群通过 Helm 安装了这些组件:

releasenamespace组件作用
ciliumkube-systemCNI 网络插件,让 Pod 跨节点通信
harborharbor私有镜像仓库,存放业务镜像
argocdargocdGitOps CD,从 Git 自动同步部署 YAML
giteagitea集群内 Git 服务
jenkinsjenkinsCI 构建服务,配合 Kaniko 构建镜像
kpsmonitoringkube-prometheus-stack,包含 Prometheus/Grafana/Alertmanager
lokimonitoring日志系统,Promtail 采日志,Loki 存和查

Helm 是什么:K8s 的包管理器。类似 Ubuntu 的 apt,但安装对象是 K8s YAML。

常用页面入口:

组件URL说明
Grafanahttp://154.201.73.31:32380监控看板,登录页返回 302 属于正常
Prometheushttp://154.201.73.31:30090指标查询,通常会跳转到 UI 页面
Jenkinshttp://154.201.73.31:30808CI 页面,未登录时可能返回 403
ArgoCDhttp://154.201.73.31:30080GitOps CD 页面
Harborhttp://154.201.73.31:30002私有镜像仓库
Longhornhttp://154.201.73.31:31172分布式存储 UI

NodePort 可以换成任意节点公网 IP 访问,比如 http://45.205.31.214:32380 也应指向 Grafana。如果某个入口浏览器打不开,先查云厂商防火墙/安全组,再查 Service。


4. 看 Pod 是否健康

ssh root@154.201.73.31 \
  'kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded -o wide'

命令解释:

  • get pods -A:列出所有 namespace 的 Pod。
  • --field-selector=status.phase!=Running,status.phase!=Succeeded:只看异常或未完成的 Pod。
  • Running:Pod 正在运行。
  • Succeeded:一次性任务正常结束。
  • CrashLoopBackOff:容器反复崩溃。
  • OOMKilled:容器内存超限被杀。

当前看到的 day12-test/mem-hog 和 mem-hog-v2 是 Day12 故障演练留下的 OOMKilled Pod,不是平台故障。


5. 现场故障:k8s-api 解析丢失

5.1 现象

在 cp-1 上执行:

kubectl get nodes

报错:

Unable to connect to the server:
dial tcp: lookup k8s-api on 127.0.0.53:53: server misbehaving

kubelet 日志也在报:

Unable to register node with API server:
Post "https://k8s-api:16443/api/v1/nodes":
dial tcp: lookup k8s-api on 127.0.0.53:53: server misbehaving

5.2 根因

这个集群没有外部负载均衡器。每台机器本地跑 HAProxy,监听:

127.0.0.1:16443 -> 3 个 apiserver 的 6443

所以 /etc/hosts 必须有:

127.0.0.1 localhost k8s-api

k8s-api 不是 K8s 自动提供的 DNS 名字,它只是我们自己写进 /etc/hosts 的本机别名。

这次 cp-1/cp-2 的 /etc/hosts 被 cloud-init 重写,k8s-api 丢了。kubelet 找不到 apiserver,就停止上报节点状态,节点变成 NotReady。

5.3 修复命令

这是写配置的命令,会修改 5 台机器的 /etc/hosts 和 /etc/cloud/cloud.cfg。执行前会备份。

for ip in 154.201.73.31 154.201.73.81 45.205.31.214 45.205.31.180 45.205.31.10; do
  ssh root@$ip 'set -eu
    cp -a /etc/hosts /etc/hosts.bak.$(date +%Y%m%d-%H%M%S)
    cp -a /etc/cloud/cloud.cfg /etc/cloud/cloud.cfg.bak.$(date +%Y%m%d-%H%M%S) 2>/dev/null || true

    if grep -q "^manage_etc_hosts:" /etc/cloud/cloud.cfg 2>/dev/null; then
      sed -i "s/^manage_etc_hosts:.*/manage_etc_hosts: false/" /etc/cloud/cloud.cfg
    else
      printf "\nmanage_etc_hosts: false\n" >> /etc/cloud/cloud.cfg
    fi

    cat > /etc/hosts <<HOSTS
127.0.0.1 localhost k8s-api
127.0.1.1 $(hostname)
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

10.0.24.31 k8s-cp-1 m1
10.0.24.29 k8s-cp-2 m2
10.0.24.32 k8s-cp-3 m3
10.0.24.28 k8s-w-1  m4
10.0.24.30 k8s-w-2  m5
HOSTS

    getent hosts k8s-api
    getent hosts k8s-cp-1
  '
done

命令解释:

  • cp -a:保留权限/时间戳做备份,出错能回滚。
  • manage_etc_hosts: false:告诉 cloud-init 不要再接管 /etc/hosts。
  • cat > /etc/hosts <<HOSTS ... HOSTS:用固定内容重写 hosts。
  • getent hosts k8s-api:验证系统真实解析结果。比 dig 更适合,因为 /etc/hosts 走的是系统 NSS 解析链。

5.4 修复后验证

ssh root@154.201.73.31 'kubectl get nodes -o wide'

5 个节点应恢复 Ready。

再看控制面核心 Pod:

ssh root@154.201.73.31 \
  'kubectl get pods -n kube-system -o wide | grep -E "kube-apiserver|kube-scheduler|cilium-|node-local"'

应该看到 apiserver、scheduler、Cilium、node-local-dns 都是 1/1 Running。


6. CNI / DNS / HAProxy 分别是什么

CNI:Container Network Interface。K8s 自己不负责 Pod 网络,交给 CNI 插件。本集群用 Cilium。没有 CNI,Pod 可以被创建,但跨节点通信和 Service 基本不可用。

ssh root@154.201.73.31 'cilium status --wait=false'

CoreDNS:集群 DNS。Pod 访问 harbor.harbor.svc、kubernetes.default.svc 这种名字时靠它解析。

node-local-dns:每台节点本地的 DNS 缓存。Pod 先问本机 169.254.20.10,减少跨节点 DNS 往返。

HAProxy:本集群没有云厂商 LoadBalancer,所以每台机器本地跑 HAProxy:

ssh root@154.201.73.31 'ss -tlnp | grep 16443'

127.0.0.1:16443 是本地入口,后端转发到 3 个 apiserver 的 :6443。


7. Longhorn 存储怎么看

Longhorn 是当前集群的分布式块存储。PVC 创建出来后,Longhorn 负责在多台机器上放副本。

ssh root@154.201.73.31 'kubectl get volumes.longhorn.io -n longhorn-system'

关键列:

  • STATE=attached:卷已经挂到某个节点使用。
  • ROBUSTNESS=healthy:副本健康。
  • ROBUSTNESS=degraded:副本数不足,通常是节点刚恢复、正在重建,先观察。
  • STATE=attaching + ROBUSTNESS=unknown:需要继续查 Longhorn manager 日志和 UI。

刚修复 cp-1/cp-2 后,部分卷可能短时间 degraded,等 Longhorn 重建副本后会恢复。


8. Grafana 常见故障:datasource 重复

Grafana 是监控页面。Prometheus 提供指标数据,Loki 提供日志数据,它们都可以作为 Grafana 的 datasource。

如果 Grafana 反复重启,先看日志:

ssh root@154.201.73.31 \
  'kubectl logs -n monitoring -l app.kubernetes.io/name=grafana -c grafana --tail=80'

如果看到:

Only one datasource per organization can be marked as default

说明有两个 datasource 都写了 isDefault: true。检查:

ssh root@154.201.73.31 \
  'kubectl get configmap -n monitoring -l grafana_datasource=1 -o yaml | grep -n "name:\|isDefault"'

本集群应保留 Prometheus 为默认 datasource,Loki 的 datasource 必须是 isDefault: false。

Grafana 还挂了一个 Longhorn RWO PVC。RWO 的意思是同一时间只能挂到一个节点。如果 Grafana 只有 1 个副本,Deployment 发布策略应使用 Recreate,不要用默认 RollingUpdate,否则新旧 Pod 会争同一个卷,事件里会看到 Multi-Attach error。

ssh root@154.201.73.31 \
  'kubectl get deploy -n monitoring kps-grafana -o jsonpath="{.spec.strategy.type}"'

期望输出:

Recreate

9. 每次操作后的最小验收

ssh root@154.201.73.31 'kubectl get nodes'

ssh root@154.201.73.31 \
  'kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded'

ssh root@154.201.73.31 'cilium status --wait=false'

ssh root@154.201.73.31 'helm list -A'

这 4 条够你回答:

  1. 节点是否活着。
  2. 是否有异常 Pod。
  3. 网络插件是否正常。
  4. 集群装了哪些大组件。

不要一上来就改 YAML。先用这 4 条判断“是节点问题、网络问题、存储问题、还是应用问题”。

在 GitHub 上编辑此页
Next
Day 0:5 节点裸 Ubuntu → K8s 装机基线