DevOps工程师面试造火箭,入职先查DNS?我整理了8个生产高频故障和排查命令

🔑 关键词:DevOps工程师,K8s故障排查,CI/CD,Argo CD,Prometheus

📖 摘要:一个半路出家的DevOps工程师,把招聘JD和生产故障做了对比,给出K8s Pending、OOMKilled、DNS超时、镜像拉取失败、CI runner磁盘满等8类问题的具体排查步骤、命令、版本参数和工具选型观点。

我第一次被叫 DevOps 工程师,是在 2019 年 3 月。 公司一共 14 个后端,2 个运维,我是其中一个。 面试时问的是 Jenkins 共享库、K8s 网络插件、Terraform state 锁; 入职第一周修的是测试环境 DNS 解析超时。 开发说 CI 挂了,其实是 CoreDNS 副本数从 2 被误删成 1,节点还刚好在滚动重启。

图片

所以我不太信招聘 JD 上那套:Docker、K8s、Jenkins、GitLab CI、Argo CD、Prometheus、Grafana、ELK、Terraform、Ansible,最好还会 Go。 不是这些没用,而是生产里 70% 的时间花在更碎的地方:证书过期、磁盘满、OOMKilled、镜像拉取 401、PVC 挂载失败、Ingress 502、CI runner 并发打满、K8s 节点 NotReady。 下面按我踩过的坑写,版本以我最近维护的一套为准:K8s 1.22.8、containerd 1.5.11、Calico 3.22、CoreDNS 1.8.4、Prometheus 2.30.3、Grafana 8.2.5、Argo CD 2.3.4、Jenkins 2.303.2 LTS、GitLab Runner 14.10。

1. Pod Pending:先别猜,看 events 的先后顺序

我遇到最常见的是 nodeSelector 写死 disktype=ssd,但新扩的 3 台节点只有 disktype=sata。 命令很简单,先看 pod 和 events:

kubectl get pod -n prod -o wide
kubectl describe pod <pod> -n prod | tail -40
kubectl get events -n prod --sort-by=.metadata.creationTimestamp | tail -30

describe 里重点看 Conditions 和 Events。 如果是 0/8 nodes are available,通常看 nodeSelector、taint、affinity。 如果是 Insufficient cpu,就看 requests。 我们有个服务 requests 写 2 CPU,limits 4 CPU,节点是 4C8G,实际每个节点只能放 1 个副本,滚动更新时必然 Pending。 后来把 requests 降到 500m,副本从 2 加到 4,反而稳了。 这里的具体数字比背概念有用:4C8G 节点,系统组件预留约 500m CPU,Calico 和 kube-proxy 再吃一点,别把 requests 打到 2 CPU。

图片

2. OOMKilled:limits 不是越大越好,JVM 要看 -Xmx

2021 年有个 Java 服务,容器 limits 512Mi,JVM 没设 -Xmx,默认拿宿主机内存的 1/4。 宿主机 32G,JVM 以为能用 8G,结果频繁 OOMKilled。 排查:

kubectl top pod -n prod --containers | sort -k3 -hr | head -20
kubectl describe pod <pod> -n prod | grep -A8 Last State
kubectl logs <pod> -n prod --previous --tail=100

后来把 JVM 参数改成 -Xmx384m -Xms384m,容器 limits 提到 768Mi,重启次数从一天 11 次降到 0。 别只看 kubectl top,它默认是 15s 到 30s 的采样,短时尖刺会漏。 Prometheus 里用 container_memory_working_set_bytes 比 container_memory_usage_bytes 更接近 OOM 判定。 我们告警线设的是 limits 的 80%,持续 5 分钟。

图片

3. DNS 5s 超时:ndots:5 和 search 域会放大问题

开发跟我说接口偶发 5s 超时,我一开始查网关,后来发现是 CoreDNS。 K8s 默认 resolv.conf 里 ndots:5,访问外部域名 api.xxx.com 会先拼一串 search 域。 如果 CoreDNS 只有 1 个副本,又赶上节点重启,就会 5s 超时。 排查命令:

kubectl -n kube-system get pod -l k8s-app=kube-dns -o wide
kubectl -n kube-system logs deploy/coredns --tail=80
kubectl run dns-test --rm -it --image=busybox:1.28 --restart=Never -- nslookup kubernetes.default
kubectl exec -it <pod> -n prod -- cat /etc/resolv.conf

如果看到 nameserver 10.96.0.10,options ndots:5,可以给应用加 dnsConfig,把 ndots 改成 2,或者用 FQDN 加末尾的点。 CoreDNS 副本从 1 调到 3,反亲和打散到不同节点,5s 超时从每天 20 多次降到 0。 注意 busybox:1.28 的 nslookup 有已知问题,测 DNS 最好用 dig 或 nslookup 加 +short。

4. ImagePullBackOff:secret 的 namespace 和 imagePullSecrets 经常对不上

图片

我们私有 Harbor 用 robot$prod 账号,secret 建在 default,但 deployment 在 prod namespace,结果一直 ImagePullBackOff。 排查:

kubectl describe pod <pod> -n prod | grep -A5 Events
kubectl get secret -n prod | grep regcred
kubectl get deployment <deploy> -n prod -o jsonpath='{.spec.template.spec.imagePullSecrets}'

修复不是复制 secret 就完事,还要在 serviceaccount 上挂 imagePullSecrets,这样新 namespace 的 pod 不用每个 deployment 都写。 Harbor 那边还要看项目是否公开、robot 账号是否有 pull 权限、镜像 tag 是否被清理。 我们设过 retention 保留最近 30 个 tag,结果某个老版本回滚时镜像没了,只能重新构建。 回滚前一定确认镜像 tag 还在仓库。

5. CI runner 磁盘满:40G 盘,30 天不清缓存,一定炸

GitLab Runner 用 docker executor,concurrent=4,每台 4C8G,系统盘 40G。 跑了 3 个月,/var/lib/docker 到 92%,构建开始报 no space left on device。 处理:

图片

df -h /var/lib/docker
docker system df
docker system prune -a --volumes --filter until=168h
gitlab-runner list

但 prune 是止血,不是治疗。 后来做了三件事:runner 单独挂 200G 数据盘;config.toml 里设置 pull_policy = if-not-present 改成 always 只在 release 分支,其他分支用 if-not-present;每周日凌晨 3 点跑清理,保留最近 7 天。 构建缓存改用 S3 兼容存储,MinIO 单节点 1T,缓存命中后 Maven 构建从 6 分 20 秒降到 2 分 50 秒。

6. Argo CD 自动同步:selfHeal 把压测副本数改回去了

这个坑我印象最深。 生产 Argo CD 2.3.4 开了 automated.selfHeal=true。 压测前手动把 deployment replicas 从 3 调到 10,过了 2 分钟被 Argo CD 改回 3,压测流量直接把 3 个 Pod 打满,P99 从 180ms 冲到 4.7s。 后来生产改成 manual sync,自动同步只在 staging 开。 如果非要自动,就加 sync window,别在压测和故障处理时跟平台较劲。

图片

7. 工具选型:Jenkins、GitLab CI、Argo CD、Flux 不是越多越好

小团队 10 到 30 人,我建议 CI 和 CD 分开看。 CI 用 GitLab CI 还是 Jenkins? 如果代码已经在 GitLab,GitLab Runner 更省心,14.10 之后 runner 自动注册和缓存都好用;Jenkins 插件多,但 2.303.2 LTS 升级一次坏一次插件是常事。 CD 用 Argo CD 还是 Flux? Argo CD 的 UI 对排障友好,适合让开发自己看 diff;Flux 更 GitOps 原生,但出问题多半要 kubectl 看 controller 日志。 别同时上两套,除非你有专人维护。

8. 我的独立观点:DevOps 工程师的核心指标是 MTTR,不是工具数量

DORA 四个指标里,部署频率、变更前置时间、变更失败率、MTTR。 小团队最容易忽略 MTTR。 你一天部署 20 次,但一次故障查 3 小时,开发就不敢发版。 我的做法很土:每个服务必须有 runbook,里面写清楚回滚命令、看板链接、最近 3 次故障。 回滚命令要具体到 kubectl rollout undo deployment/ -n prod 和确认命令 kubectl rollout status deployment/ -n prod --timeout=120s。

最后,如果你正在面试 DevOps,别只背 K8s 组件。 准备 3 个你亲手处理过的故障:时间、影响、命令、根因、修复、预防。 比如 DNS 超时、OOMKilled、CI 磁盘满。 面试官不一定懂每个命令,但他能听出来你是真干过还是背的。

🏷️ 标签: