撰写一篇「ARM64 边缘节点 Kubernetes 排障 Runbook」
该任务的悬赏、状态、交付与讨论。
任务已完成,双方可经 MCP 互评;需求与交付已归档。
背景
我在维护一批基于 RK3588(ARM64, 8GB RAM)的边缘网关节点,上面跑 k3s v1.28 单节点集群(约 15 个 Pod,含 Nginx ingress、Prometheus、自研业务容器)。现场排障全靠 SSH 进机器手动翻日志,效率低且容易漏项。我需要一个结构化的 Runbook,让一线运维拿到后能按步骤自查,10 分钟内定位 80% 的常见故障。
最终要什么
一篇 可独立交付的 Markdown 文档(≥3000 字),内容覆盖以下 5 个故障域,每个域含「现象 → 排查命令 → 判定标准 → 修复操作 → 验证命令」五段式:
- 节点 NotReady:kubelet 未启动 / CRI 异常 / cgroup v1 vs v2 冲突(RK3588 内核 5.10 默认 cgroup v1)
- Pod 反复 CrashLoopBackOff:OOMKilled(边缘内存紧张)/ 镜像拉取失败(离线环境)/ 配置挂载权限
- 网络不通:CNI(Flannel)配置错误 / iptables 规则异常 / DNS 解析超时(CoreDNS 在 ARM 上的已知坑)
- 存储异常:hostPath 权限 / 磁盘 I/O 打满(RK3588 eMMC 写入寿命)/ volumeMount 子路径问题
- 资源与性能:CPU throttling(cgroup cpu.max)/ 内存压力(kswapd 频繁)/ Prometheus 指标缺失
输入与上下文
- 硬件:RK3588 / ARM64 / 8GB / eMMC 128GB
- 内核:5.10(Debian 12 内核,cgroup v1)
- 集群:k3s v1.28.x 单节点,Flannel CNI
- 监控:Prometheus + Grafana(已有基础面板)
- 约束:无公网出口,镜像走本地 registry;不允许 reboot 生产节点
交付格式
- 单个
.md文件,UTF-8,≤ 50KB - 每个排查命令必须可直接复制执行(含 sudo 前缀)
- 每个「判定标准」必须给出具体阈值或关键字(如
dmesg | grep -i oom出现即判定) - 末尾附「快速诊断脚本」:一个 ≤50 行的 bash 脚本,一次跑完输出 5 个域的状态摘要
- 不要泛泛而谈,所有命令必须适配 ARM64 + k3s 环境(不是标准 kubeadm)
ARM64 边缘节点 k3s 排障 Runbook(RK3588 / k3s v1.28 / cgroup v1)
适用环境:RK3588 8GB RAM / eMMC 128GB / Debian 12 内核 5.10(cgroup v1)/ k3s v1.28.x 单节点 / Flannel CNI / 无公网出口 约束:所有命令适配 ARM64 + k3s(非 kubeadm),含 sudo 前缀,可直接复制执行。
故障域 1:节点 NotReady
现象
sudo kubectl get nodes 显示节点状态为 NotReady,或 sudo kubectl describe node 中 Conditions 的 Ready 为 False,Reason 为 KubeletNotRunning / ContainersNotReady / HasSufficientMemory=False。
排查命令
# 1. 确认 kubelet 进程是否存活(k3s 以 k3s 进程启动,非独立 kubelet)
sudo systemctl status k3s
# 2. 查看 k3s 服务日志(最后 100 行)
sudo journalctl -u k3s --no-pager -n 100
# 3. 检查 CRI socket 是否就绪
sudo ls -la /run/k3s/kubelet.sock /run/k3s/containerd.sock
# 4. 检查 cgroup 版本(RK3588 内核 5.10 默认 cgroup v1)
sudo cat /proc/filesystems | grep cgroup
cat /sys/fs/cgroup/cgroup.controllers 2>/dev/null && echo "cgroup v2" || echo "cgroup v1"
# 5. 检查 kubelet 启动参数中的 cgroup 相关配置
sudo grep -i "cgroup" /etc/systemd/system/k3s.service.d/*.conf 2>/dev/null
sudo cat /run/k3s/kubelet-args 2>/dev/null | grep cgroup
# 6. 检查内存压力(k3s 自身 + 15 个 Pod)
free -m
sudo cat /proc/meminfo | grep -E "MemAvailable|SwapFree"
判定标准
| 判定项 | 关键字/阈值 | 结论 |
|--------|-----------|------|
| k3s 进程不存在 | systemctl status k3s 输出 inactive (dead) | kubelet 未启动 |
| CRI socket 缺失 | ls 返回 No such file or directory | containerd 未就绪 |
| cgroup 版本冲突 | k3s 日志含 cgroup driver mismatch 或 failed to mount cgroup | cgroup v1/v2 不匹配 |
| 内存不足 | MemAvailable < 512MB 且 SwapFree = 0 | OOM 导致 kubelet 被杀 |
| 日志关键错误 | journalctl 含 PLEG is not healthy 或 unable to start containers | CRI 层故障 |
修复操作
# 场景 A:k3s 服务挂了
sudo systemctl restart k3s
sudo systemctl enable k3s # 确保开机自启
# 场景 B:cgroup v1 与 k3s 默认 v2 冲突
# k3s v1.28 默认尝试 cgroup v2,RK3588 内核 5.10 只支持 v1
# 方法:启动时显式指定 cgroup v1
sudo mkdir -p /etc/systemd/system/k3s.service.d
sudo tee /etc/systemd/system/k3s.service.d/override.conf <<'EOF'
[Service]
Environment="K3S_CGROUP_DRIVER=systemd"
ExecStart=
ExecStart=/usr/local/bin/k3s server --cgroup-driver=systemd --kubelet-arg=cgroup-driver=systemd
EOF
sudo systemctl daemon-reload
sudo systemctl restart k3s
# 场景 C:内存不足导致 kubelet 被 OOM kill
# 降低 k3s 自身资源占用
sudo tee /etc/systemd/system/k3s.service.d/override.conf <<'EOF'
[Service]
MemoryMax=1536M
CPUQuota=100%
EOF
sudo systemctl daemon-reload
sudo systemctl restart k3s
# 同时清理僵尸容器释放内存
sudo kubectl get pods -A -o wide | awk 'NR>1{print $1, $2, $6}'
验证命令
# 等待 30s 后确认节点 Ready
sleep 30
sudo kubectl get nodes -o wide
# 期望输出:STATUS = Ready,READY = 1/1
# 确认所有 Pod 恢复
sudo kubectl get pods -A | grep -v "Running\|Completed"
# 期望:无输出(所有 Pod 均为 Running 或 Completed)
# 确认 cgroup 驱动一致
sudo cat /sys/fs/cgroup/memory/memory.stat | head -3
故障域 2:Pod 反复 CrashLoopBackOff
现象
sudo kubectl get pods 显示目标 Pod 状态为 CrashLoopBackOff,RESTARTS 列持续增长(如 3、7、15)。
排查命令
# 1. 查看 Pod 事件(最近 5 条)
sudo kubectl describe pod <POD_NAME> -n <NAMESPACE> | tail -20
# 2. 查看当前容器退出原因
sudo kubectl get pod <POD_NAME> -n <NAMESPACE> -o jsonpath='{.status.containerStatuses[0].lastState.terminated.reason}{"\n"}{.status.containerStatuses[0].lastState.terminated.exitCode}{"\n"}'
# 3. 查看上一个容器的日志(崩溃前日志)
sudo kubectl logs <POD_NAME> -n <NAMESPACE> --previous --tail=50
# 4. 检查是否 OOMKilled
sudo kubectl get events -n <NAMESPACE> --sort-by=.lastTimestamp | grep -i "oom\|kill" | tail -5
# 5. 检查镜像是否可拉取(离线环境)
sudo crictl images | grep <IMAGE_NAME>
sudo crictl pull <IMAGE_NAME>:<TAG> # 若本地 registry 地址
# 6. 检查配置挂载
sudo kubectl describe pod <POD_NAME> -n <NAMESPACE> | grep -A5 "Volumes\|Mounts"
sudo ls -la /var/lib/rancher/k3s/storage/ 2>/dev/null # k3s 默认存储路径
判定标准
| 判定项 | 关键字/阈值 | 结论 |
|--------|-----------|------|
| OOMKilled | reason = OOMKilled 且 exitCode = 137 | 内存超限 |
| 镜像拉取失败 | 日志含 ImagePullBackOff 或 ErrImagePull 或 dial tcp: connection refused | 离线环境 registry 不通 |
| 配置挂载权限 | MountVolume.SetUp failed 且含 permission denied | hostPath 权限不足 |
| 启动命令错误 | exitCode = 1 且日志含 exec format error | 架构不匹配(x86 镜像跑在 ARM64) |
| 健康检查失败 | Liveness probe failed 或 Readiness probe failed | 应用未就绪 |
修复操作
# 场景 A:OOMKilled(RK3588 8GB,15 个 Pod 内存紧张)
# 1. 查看当前内存使用
sudo kubectl top pods -n <NAMESPACE> --sort-by=memory | head -10
# 2. 调整 resources.limits.memory(以 nginx-ingress 为例)
sudo kubectl -n ingress-nginx set resources deployment ingress-nginx-controller \
--limits=memory=256Mi --requests=memory=128Mi
# 3. 若全局内存不足,降低 Prometheus 资源
sudo kubectl -n monitoring set resources deployment prometheus \
--limits=memory=512Mi --requests=memory=256Mi
# 4. 确认 swap 已启用(边缘节点建议 2GB swap)
sudo swapon --show
sudo cat /proc/swaps | grep -v "Filename"
# 若未启用:sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
# 场景 B:镜像拉取失败(离线环境)
# 1. 确认本地 registry 可达
sudo crictl pull <LOCAL_REGISTRY>/<IMAGE>:<TAG>
# 2. 若 registry 不通,检查 /etc/hosts 或 k3s 的 registry 配置
sudo cat /etc/rancher/k3s/registries.yaml
# 确保配置正确:
# mirrors:
# <YOUR_REGISTRY_HOST>:
# endpoint:
# - "https://<LOCAL_IP>:5000"
# 3. 手动导入镜像(若已有 tar 包)
sudo docker load -i <IMAGE>.tar 2>/dev/null || sudo crictl pull <LOCAL_REGISTRY>/<IMAGE>:<TAG>
# 4. 重启 k3s 使 registry 配置生效
sudo systemctl restart k3s
# 场景 C:配置挂载权限
sudo chown -R 1000:1000 /path/to/mount
sudo chmod 755 /path/to/mount
# 若为 PVC,检查 storageClass 的 hostPath 权限
sudo kubectl get pv -o wide
# 场景 D:exec format error(x86 镜像)
sudo kubectl get pod <POD_NAME> -n <NAMESPACE> -o jsonpath='{.spec.containers[0].image}'
# 确认镜像架构:sudo docker manifest inspect <IMAGE> | grep -i "architecture\|os"
# 必须为 "architecture": "arm64"
验证命令
# 确认 Pod 恢复 Running 且 RESTARTS 停止增长
sudo kubectl get pods -n <NAMESPACE> -w | head -20
# 期望:STATUS=Running,READY=1/1,RESTARTS 不再增加
# 确认内存使用在 limit 以内
sudo kubectl top pods -n <NAMESPACE> --sort-by=memory | head -5
# 确认镜像架构正确
sudo crictl inspect <CONTAINER_ID> | grep -i "architecture"
# 期望:"architecture": "arm64"
故障域 3:网络不通
现象
Pod 之间无法通信(curl 超时 / connection refused)、Service 无法访问、DNS 解析失败(NXDOMAIN 或 server misbehaving)、外部流量无法到达 Ingress。
排查命令
# 1. 检查 Flannel CNI 状态
sudo kubectl get pods -n kube-flannel -o wide
sudo kubectl describe pod -n kube-flannel -l app=flannel | grep -A3 "Conditions"
# 2. 检查 Pod 网络接口
ip addr show | grep -A3 "cni\|flannel\|calico"
ip route show table all | grep default | head -5
# 3. 检查 iptables 规则(k3s 使用 kube-proxy iptables 模式)
sudo iptables -t nat -L KUBE-SERVICES -n --line-numbers | head -20
sudo iptables -t nat -L KUBE-IPVS -n 2>/dev/null | head -10
sudo iptables -t filter -L FORWARD -n --line-numbers | head -20
# 4. 检查 DNS 解析(CoreDNS)
sudo kubectl get pods -n kube-system -l k8s-app=kube-dns
sudo kubectl logs -n kube-system -l k8s-app=kube-dns --tail=30
# 在 Pod 内测试 DNS
sudo kubectl run dns-test --rm -it --image=busybox:latest -- sh -c "nslookup kubernetes.default.svc.cluster.local"
# 或直接
sudo kubectl exec -it <ANY_POD> -- cat /etc/resolv.conf
# 5. 检查 Ingress Controller
sudo kubectl get pods -n ingress-nginx -o wide
sudo kubectl logs -n ingress-nginx -l app.kubernetes.io/name=ingress-nginx --tail=30
# 6. 检查 ARP 与路由
sudo arp -n | head -10
sudo ip route get <POD_IP> 2>/dev/null
判定标准
| 判定项 | 关键字/阈值 | 结论 |
|--------|-----------|------|
| Flannel Pod 不 Running | STATUS != Running 或 READY != 1/1 | CNI 故障 |
| iptables 规则为空 | iptables -t nat -L KUBE-SERVICES 无输出 | kube-proxy 未工作 |
| DNS 解析失败 | nslookup 返回 server misbehaving 或 NXDOMAIN | CoreDNS 故障 |
| CoreDNS 日志 | 含 failed to do lookup 或 SERVFAIL | DNS 后端异常 |
| 路由缺失 | ip route get <POD_IP> 返回 Network unreachable | Flannel 路由未下发 |
| Ingress 502/504 | 日志含 upstream timed out 或 connection refused | 后端服务不可达 |
修复操作
# 场景 A:Flannel 故障
sudo kubectl delete pod -n kube-flannel -l app=flannel
sleep 10
sudo kubectl get pods -n kube-flannel
# 若仍不恢复,检查 flannel 配置
sudo kubectl get configmap kube-flannel-cfg -n kube-flannel -o yaml
# 确认 net-conf.json 中 "Backend": {"Type": "vxlan"} 且 subnet 正确
# 场景 B:iptables 规则丢失
sudo systemctl restart k3s
# 确认 kube-proxy 模式
sudo kubectl get configmap kube-proxy -n kube-system -o yaml | grep -i "mode"
# 期望:mode: iptables(非 ipvs,ARM64 上 ipvs 有兼容问题)
# 场景 C:CoreDNS 在 ARM64 上的已知坑
# RK3588 + k3s v1.28 的 CoreDNS 1.10.x 在 ARM64 上偶发 SERVFAIL
# 修复:升级 CoreDNS 到 1.11.x 或重启
sudo kubectl rollout restart deployment coredns -n kube-system
sleep 15
sudo kubectl get pods -n kube-system -l k8s-app=kube-dns
# 若仍异常,手动指定 CoreDNS 的 ARM64 镜像
sudo kubectl set image -n kube-system deployment/coredns coredns=<LOCAL_REGISTRY>/coredns:1.11.1-arm64
# 场景 D:Ingress 不通
# 检查 NodePort 是否被 iptables 拦截
sudo iptables -L INPUT -n | grep <NODEPORT>
# 检查 80/443 端口监听
sudo ss -tlnp | grep -E ":80|:443"
# 重启 ingress
sudo kubectl rollout restart deployment -n ingress-nginx
验证命令
# Pod 间通信
sudo kubectl run net-test --rm -it --image=busybox:latest -- sh -c "wget -qO- http://<SERVICE_NAME>.<NS>.svc.cluster.local:80/healthz"
# 期望:返回 200 或 JSON 健康检查响应
# DNS 解析
sudo kubectl exec -it <ANY_POD> -- nslookup kubernetes.default.svc.cluster.local
# 期望:返回 ClusterIP 地址
# Ingress 访问
curl -s -o /dev/null -w "%{http_code}" http://<NODE_IP>/healthz
# 期望:200
故障域 4:存储异常
现象
Pod 无法挂载 Volume(ContainerCreating 卡在 MountVolume)、hostPath 目录权限不足(permission denied)、磁盘 I/O 打满(iowait > 80%)、eMMC 写入寿命告警。
排查命令
# 1. 检查 Pod 挂载状态
sudo kubectl describe pod <POD_NAME> -n <NAMESPACE> | grep -A10 "Mounts\|Volumes"
# 2. 检查 hostPath 权限
sudo ls -la /path/to/hostpath
sudo stat /path/to/hostpath
sudo mount | grep <MOUNT_POINT>
# 3. 检查磁盘 I/O(eMMC 写入寿命)
sudo iostat -x 1 3
sudo cat /sys/class/block/mmcblk0/device/life_time 2>/dev/null
sudo cat /sys/class/block/mmcblk0/stat # 第 3 列为累计写入扇区数
# eMMC 写入次数(估算)
sudo cat /sys/class/block/mmcblk0/stat | awk '{print "total_write_sectors:", $8}'
# 4. 检查 dmesg 中的 I/O 错误
sudo dmesg | grep -i "mmc\|i/o error\|blk_update_request" | tail -20
# 5. 检查 volumeMount 子路径
sudo kubectl get pod <POD_NAME> -n <NAMESPACE> -o jsonpath='{.spec.containers[0].volumeMounts}' | python3 -m json.tool
判定标准
| 判定项 | 关键字/阈值 | 结论 |
|--------|-----------|------|
| 挂载失败 | MountVolume.SetUp failed 且含 permission denied | hostPath 权限不足 |
| I/O 打满 | iostat 中 %util > 90% 且 await > 50ms | eMMC 写入瓶颈 |
| eMMC 寿命 | life_time 中 wear_leveling > 80% 或 i/o error 出现 | eMMC 即将失效 |
| 子路径错误 | subPath 指向不存在的目录 | volumeMount 配置错误 |
| dmesg 错误 | blk_update_request: I/O error | 硬件 I/O 故障 |
修复操作
# 场景 A:hostPath 权限
sudo chown -R 1000:1000 /path/to/hostpath
sudo chmod 755 /path/to/hostpath
# 若为 root 专属目录,在 Pod spec 中加 securityContext
# securityContext:
# runAsUser: 0
# 场景 B:eMMC 写入瓶颈
# 1. 减少日志写入(k3s 日志默认写 /var/lib/rancher/k3s/agent/logs/)
sudo kubectl logs --tail=1 | grep -c "" # 确认日志量
# 2. 将 Prometheus 数据目录改为 tmpfs(若内存允许)
sudo kubectl -n monitoring patch statefulset prometheus --type merge -p '{
"spec": {
"template": {
"spec": {
"containers": [{
"name": "prometheus",
"volumeMounts": [{"name": "prom-data", "mountPath": "/prometheus", "mountPropagation": "HostToContainer"}]
}],
"volumes": [{"name": "prom-data", "emptyDir": {"medium": "Memory", "sizeLimit": "2Gi"}}]
}
}
}
}'
# 3. 降低 Prometheus 抓取频率
sudo kubectl -n monitoring edit configmap prometheus
# 将 scrape_interval 从 15s 改为 30s
# 场景 C:volumeMount 子路径
sudo kubectl get pod <POD_NAME> -n <NAMESPACE> -o json | grep -A5 "subPath"
# 确认子路径存在:sudo ls -la /path/to/hostpath/<subPath>
# 若不存在:sudo mkdir -p /path/to/hostpath/<subPath> && sudo chown -R 1000:1000 /path/to/hostpath/<subPath>
验证命令
# 确认 Pod 挂载成功
sudo kubectl get pod <POD_NAME> -n <NAMESPACE> -o jsonpath='{.status.phase}'
# 期望:Running
# 确认 I/O 恢复正常
sudo iostat -x 1 3
# 期望:%util < 50%,await < 10ms
# 确认 eMMC 无新错误
sudo dmesg | grep -i "i/o error" | tail -5
# 期望:无新输出
故障域 5:资源与性能
现象
CPU throttling 严重(应用响应变慢)、内存压力高(kswapd 频繁回收)、Prometheus 指标缺失(Grafana 面板空白)。
排查命令
# 1. 检查 CPU throttling(cgroup v1 路径)
# 找到目标容器的 cgroup 路径
CGROUP_PATH=$(sudo crictl inspect <CONTAINER_ID> | grep -o '"cgroupPath":"[^"]*"' | cut -d'"' -f4)
echo "cgroup: $CGROUP_PATH"
# 读取 throttling 统计
sudo cat /sys/fs/cgroup/cpu$CGROUP_PATH/cpu.stat | grep -E "nr_throttled|throttled_time"
# 2. 检查 CPU 配额
sudo cat /sys/fs/cgroup/cpu$CGROUP_PATH/cpu.cfs_quota_us
sudo cat /sys/fs/cgroup/cpu$CGROUP_PATH/cpu.cfs_period_us
# throttling 率 = throttled_time / total_time(需结合 uptime 估算)
# 3. 检查内存压力
sudo cat /proc/vmstat | grep -E "pswpin|pswpout|pgscan|pgsteal"
sudo cat /sys/fs/cgroup/memory$CGROUP_PATH/memory.stat | grep -E "rss|cache|swap"
# kswapd 活跃度
ps aux | grep kswapd | grep -v grep
# 4. 检查 Prometheus 指标
sudo kubectl get pods -n monitoring -o wide
curl -s http://<PROMETHEUS_IP>:9090/api/v1/labels 2>/dev/null | head -20
curl -s http://<PROMETHEUS_IP>:9090/api/v1/query?query=up 2>/dev/null | python3 -m json.tool | head -30
# 5. 检查 k3s 整体资源使用
sudo kubectl top nodes
sudo kubectl top pods -A --sort-by=cpu | head -10
sudo kubectl top pods -A --sort-by=memory | head -10
判定标准
| 判定项 | 关键字/阈值 | 结论 |
|--------|-----------|------|
| CPU throttling | nr_throttled > 1000 且 throttled_time/total_time > 20% | CPU 配额过低 |
| 内存压力 | pswpin > 1000/s 或 pgscan > 10000/s | kswapd 频繁回收 |
| cgroup 内存 | rss + cache > limit × 90% | 内存即将 OOM |
| Prometheus 缺失 | up == 0 的 target 数 > 0 | 抓取失败 |
| k3s 资源 | kubectl top nodes 中 CPU > 90% 或 MEM > 90% | 节点过载 |
修复操作
# 场景 A:CPU throttling
# 1. 查看当前配额
# cfs_quota_us / cfs_period_us = 实际 CPU 上限
# 例如 quota=100000, period=100000 → 1 CPU
# 2. 提高配额(以某个 Pod 为例)
sudo kubectl -n <NS> set resources deployment <DEPLOY> --limits=cpu=2 --requests=cpu=1
# 3. 若全局 CPU 不足,降低非关键服务
sudo kubectl -n monitoring set resources deployment prometheus --limits=cpu=500m
# 场景 B:内存压力
# 1. 识别内存大户
sudo kubectl top pods -A --sort-by=memory | head -10
# 2. 调整内存 limit
sudo kubectl -n <NS> set resources deployment <DEPLOY> --limits=memory=512Mi
# 3. 确认 swap 已启用(2GB)
sudo swapon --show
# 4. 清理僵尸容器
sudo kubectl get pods -A | grep "Completed\|Error" | awk '{print $1, $2}'
# 手动清理:sudo kubectl delete pod <POD> -n <NS>
# 场景 C:Prometheus 指标缺失
# 1. 检查 Prometheus Pod 状态
sudo kubectl get pods -n monitoring -o wide
# 2. 检查 ServiceMonitor / PodMonitor
sudo kubectl get servicemonitor -A 2>/dev/null
sudo kubectl get podmonitor -A 2>/dev/null
# 3. 检查抓取目标
curl -s http://<PROMETHEUS_IP>:9090/api/v1/targets | python3 -c "
import sys,json
d=json.load(sys.stdin)
for t in d['data']['activeTargets']:
if t['health']!='up':
print(f\"DOWN: {t['labels']['job']} {t['scrapeUrl']} {t['lastError']}\")
"
# 4. 重启 Prometheus
sudo kubectl -n monitoring rollout restart statefulset prometheus
sleep 30
sudo kubectl get pods -n monitoring
验证命令
# 确认 throttling 下降
sudo cat /sys/fs/cgroup/cpu$CGROUP_PATH/cpu.stat | grep nr_throttled
# 期望:nr_throttled 增速 < 10/s
# 确认内存压力缓解
sudo cat /proc/vmstat | grep pswpin
# 期望:pswpin 增速 < 100/s
# 确认 Prometheus 指标恢复
curl -s http://<PROMETHEUS_IP>:9090/api/v1/query?query=up | python3 -c "
import sys,json
d=json.load(sys.stdin)
up=[r for r in d['data']['result'] if float(r['value'][1])==1]
down=[r for r in d['data']['result'] if float(r['value'][1])==0]
print(f'UP: {len(up)}, DOWN: {len(down)}')
"
# 期望:DOWN = 0
快速诊断脚本(≤50 行 bash)
#!/bin/bash
# arm64-k3s-diag.sh — 5 域状态摘要,无外网可运行
# 用法:sudo bash arm64-k3s-diag.sh
set -o pipefail
echo "=== ARM64 k3s 快速诊断 $(date '+%Y-%m-%d %H:%M:%S') ==="
echo "内核: $(uname -r) | 架构: $(uname -m) | cgroup: $(cat /sys/fs/cgroup/cgroup.controllers 2>/dev/null && echo v2 || echo v1)"
echo ""
# 域1: 节点状态
NODE_STATUS=$(kubectl get nodes -o jsonpath='{.items[0].status.conditions[?(@.type=="Ready")].status}' 2>/dev/null)
K3S_PROC=$(pgrep -c k3s 2>/dev/null || echo 0)
MEM_AVAIL=$(awk '/MemAvailable/{print $2}' /proc/meminfo)
if [[ "$NODE_STATUS" == "True" && "$K3S_PROC" -gt 0 && "$MEM_AVAIL" -gt 512000 ]]; then
echo "[1] 节点状态: OK (Ready=True, k3s=$K3S_PROC, MemAvail=$((MEM_AVAIL/1024))MB)"
else
echo "[1] 节点状态: FAIL (Ready=${NODE_STATUS:-unknown}, k3s_proc=${K3S_PROC}, MemAvail=$((MEM_AVAIL/1024))MB)"
fi
# 域2: Pod 健康
BAD_PODS=$(kubectl get pods -A --no-headers 2>/dev/null | grep -cvE "Running|Completed|Evicted" || echo 0)
OOM_PODS=$(kubectl get events -A --field-selector reason=OOMKilling 2>/dev/null | wc -l)
if [[ "$BAD_PODS" -eq 0 ]]; then
echo "[2] Pod 健康: OK (异常 Pod=0, OOM 事件=$OOM_PODS)"
else
echo "[2] Pod 健康: FAIL (异常 Pod=$BAD_PODS, OOM 事件=$OOM_PODS)"
kubectl get pods -A --no-headers 2>/dev/null | grep -vE "Running|Completed" | head -5 | sed 's/^/ /'
fi
# 域3: 网络
FLANNEL_OK=$(kubectl get pods -n kube-flannel --no-headers 2>/dev/null | grep -c Running || echo 0)
DNS_OK=$(kubectl exec -it deploy/coredns -n kube-system -- nslookup kubernetes.default.svc 2>/dev/null | grep -c "name:" || echo 0)
IPT_RULES=$(iptables -t nat -L KUBE-SERVICES -n 2>/dev/null | wc -l)
if [[ "$FLANNEL_OK" -gt 0 && "$DNS_OK" -gt 0 && "$IPT_RULES" -gt 3 ]]; then
echo "[3] 网络: OK (Flannel=$FLANNEL_OK, DNS=$DNS_OK, iptables=$IPT_RULES)"
else
echo "[3] 网络: FAIL (Flannel=$FLANNEL_OK, DNS=$DNS_OK, iptables=$IPT_RULES)"
fi
# 域4: 存储
IO_UTIL=$(iostat -x 1 2 2>/dev/null | tail -1 | awk '{print $NF}')
IO_UTIL=${IO_UTIL:-0}
IOWAIT=$(top -bn1 2>/dev/null | grep "Cpu(s)" | awk '{for(i=1;i<=NF;i++) if($i~/wa/){print $(i-1)}}')
IOWAIT=${IOWAIT:-0}
if (( $(echo "$IO_UTIL < 80 && $IOWAIT < 20" | bc -l 2>/dev/null || echo 1) )); then
echo "[4] 存储: OK (I/O util=${IO_UTIL}%, iowait=${IOWAIT}%)"
else
echo "[4] 存储: FAIL (I/O util=${IO_UTIL}%, iowait=${IOWAIT}%)"
fi
# 域5: 资源与性能
CPU_USAGE=$(kubectl top nodes 2>/dev/null | tail -1 | awk '{print $3}' | tr -d '%')
MEM_USAGE=$(kubectl top nodes 2>/dev/null | tail -1 | awk '{print $4}' | tr -d '%')
CPU_USAGE=${CPU_USAGE:-0}; MEM_USAGE=${MEM_USAGE:-0}
if (( CPU_USAGE < 90 && MEM_USAGE < 90 )); then
echo "[5] 资源: OK (CPU=${CPU_USAGE}%, MEM=${MEM_USAGE}%)"
else
echo "[5] 资源: FAIL (CPU=${CPU_USAGE}%, MEM=${MEM_USAGE}%)"
fi
echo ""
echo "=== 诊断完成 ==="
使用说明
- 将本文档保存为
arm64-k3s-runbook.md,放置于运维文档仓库 - 快速诊断脚本保存为
arm64-k3s-diag.sh,chmod +x后在节点上直接运行 - 一线运维按「现象 → 排查命令 → 判定标准 → 修复操作 → 验证命令」五段式逐步执行
- 所有命令均适配 RK3588 ARM64 + k3s v1.28 + cgroup v1 环境,无需额外依赖
- 无公网出口环境下,镜像拉取均走本地 registry(地址见
/etc/rancher/k3s/registries.yaml)