记录一次跟Cluade面试的经历
问题1:你们线上有一个服务需要发布新版本,你会怎么做到零停机更新?K8s 提供了哪些机制保证这一点?
如果我有新版本服务需要发布,我会先部署一部分新版本的服务器,确认没问题了,再逐步扩大规模,直至全部替换掉老版本,k8s提供了rollingUpdate策略可以实现这个功能。
- maxSurge / maxUnavailable:控制更新节奏,比如
maxSurge: 1表示最多多起 1 个新 Pod,maxUnavailable: 0表示不允许任何 Pod 在不可用状态下被替换 - readinessProbe 的关键作用:新 Pod 必须通过 readiness 检查才会加入 Service 流量,保证流量不会打到还没准备好的实例
- 验证手段:
kubectl rollout status deployment/fleet-api实时观察,kubectl rollout undo一键回滚
加上这几点,答案就从”知道概念”升级到”用过、踩过坑”的水平。
第 2 题:你们的 fleet-api 服务白天高峰期 QPS 是平时的 5 倍,晚上几乎没流量。现在每天早上都要手动扩容、晚上手动缩容,运维很累。请问你会怎么解决这个问题?说说你的方案和关键配置。
创建HPA,监测POD的CPU使用率,自动实现扩缩容
反馈: 答对了核心方案,HPA 确实是解决这个问题的标准答案。简洁有力。
可以再补充两点让答案更完整:
- 稳定窗口(stabilizationWindowSeconds):防止流量抖动导致频繁扩缩容。比如缩容稳定窗口设 300 秒,意味着 CPU 持续低于阈值 5 分钟后才真正缩容,避免”刚缩完又要扩”的震荡
- 资源 request 必须设置:HPA 是基于 Pod 的 CPU request 来算百分比的,如果 deployment 里没设
resources.requests.cpu,HPA 会显示<unknown>,根本无法工作——这是实际踩坑最多的地方
你在实验里就遇到过 <unknown> 的状态,能在面试里主动提这个细节,加分项。
第 3 题:现在线上出了个故障:用户反映某些请求返回 500,但不是所有请求都失败。你登上去一看,发现 deployment 有 3 个 Pod,其中 1 个 Pod 的日志里在不断报错。请问你会怎么处理?说说排查思路和操作步骤。
先把这个报错的POD流量切到其他POD上,再去查看这个报错的POD为什么出问题
反馈: 思路对,先止血再排查,这是 SRE 处理故障的正确优先级。
不过面试官接下来一定会追问:”你怎么把流量切走?” 这里要能说出具体操作:
- kubectl cordon / drain 是针对 Node 的,不适用于单个 Pod
- 正确做法是给这个问题 Pod 打上一个特殊 label,同时把 Service 的 selector 改掉,让它不再选中这个 Pod——但这个操作比较危险且手动
- 更常用的方式:直接
kubectl delete pod <问题pod名>,让 Deployment 重建一个健康的 Pod 替代它;问题 Pod 的日志在删之前先kubectl logs保存下来 - 或者直接
kubectl cordon问题 Pod 所在的 Node(如果是节点级问题),让新 Pod 调度到其他节点
排查步骤也可以更结构化:
kubectl logs <pod> --previous看崩溃前日志kubectl describe pod <pod>看 Events,有没有 OOMKilled、探针失败kubectl exec -it <pod> -- sh进去看运行时状态(如果 Pod 还活着)
止血 + 保留现场 + 系统排查,三步说清楚,答案就很完整了。
第 4 题:你用 Terraform 管理 Kubernetes 资源。某天一个同事直接用 kubectl apply 手动改了线上的 deployment(比如把 replicas 从 3 改成了 5),但没有更新 Terraform 代码。这时候你再跑 terraform apply,会发生什么?你们团队应该怎么避免这类问题?
会导致replicas从5变成3,我们团队应该以Terraform代码为最终依据,要把修改都体现到Terraform代码中
反馈: 完全正确,这就是 IaC 的核心原则——代码是 Single Source of Truth。terraform apply 会把实际状态强制拉回到代码描述的状态,kubectl 的手动改动会被覆盖掉。
可以额外补充两点:
- terraform plan 先看差异:在 apply 之前跑
terraform plan,你会看到~ replicas: 5 -> 3这样的变更提示,能让团队意识到有人动过线上 - 治理手段:除了流程上要求走 Terraform,技术上可以用 RBAC 限制 kubectl 的写权限,只允许 CI/CD pipeline 的 Service Account 做变更,普通开发者只有 get/list/watch 权限,从根本上堵住手动操作
第 5 题:你们的 GitHub Actions CI/CD pipeline 跑完之后,镜像推到了 ghcr.io,但 Kubernetes 集群里的 Pod 并没有拉取新镜像,还在跑老版本。请问可能是什么原因?你会怎么排查?
可能CI/CD过程被中断了,可能的原因有测试或者校验没过,可以查看CI/CD 的Actions查看具体是那一步出错了
反馈: 这个方向是排查思路之一,但题目里说的是”镜像推到了 ghcr.io”——也就是 CI/CD 已经成功跑完了,镜像确实推上去了,但 Pod 没有更新。这是更常见也更隐蔽的问题。
最可能的原因是 image tag 用了 latest:
- 如果 deployment 里写的是
image: ghcr.io/xxx/fleet-api:latest,而 Pod 的imagePullPolicy是IfNotPresent(默认值),那 k8s 看到本地已经有latest镜像,就不会去拉新的——即使 ghcr.io 上的latest已经是新内容 - 解决方案:CI/CD 每次构建用唯一 tag(比如 git commit SHA:
ghcr.io/xxx/fleet-api:abc1234),然后用kubectl set image更新 deployment,触发真正的滚动更新
其他可能原因:
imagePullPolicy: Never(你实验里就用过这个,因为镜像是手动 load 进 minikube 的)- deployment 的 image 字段根本没被更新,CI/CD 只推了镜像但没执行
kubectl set image
面试里能说出 latest tag + IfNotPresent 的陷阱,是真正踩过坑的体现,印象分很高。
第 6 题(系统设计方向):假设 fleet-api 现在要支持 10 万辆车同时在线,每辆车每 10 秒上报一次位置数据。请估算一下这个系统的 QPS,并说说你会怎么设计这个服务的架构来支撑这个规模?
平均QPS为1万,使用HPA采集POD的CPU使用率,根据使用率进行自动的扩缩容来应对流量的高峰和低谷
反馈: QPS 计算完全正确,10 万 ÷ 10 秒 = 1 万 QPS,这个数字说出来很有说服力。
HPA 是对的,但这是一道系统设计题,面试官期待的是更完整的架构图。光说 HPA 只回答了”怎么弹”,还没回答”怎么扛”:
可以补充的层次:
- 接入层:Ingress + LoadBalancer,把 1 万 QPS 分发到多个 Pod,单 Pod 扛 500-1000 QPS 是合理估算,大概需要 10-20 个 Pod
- 写多读少:位置上报是高频写入,直接打数据库会撑死。应该在 fleet-api 和数据库之间加一层消息队列(Kafka / Redis Stream),Pod 收到数据先写队列,消费者异步落库
- 存储选型:位置数据是时序数据,适合 InfluxDB 或 TimescaleDB,而不是普通关系型数据库
- 缓存:如果有读取最新位置的需求,用 Redis 缓存每辆车的最新状态,避免频繁查库
系统设计题的答题框架:估算规模 → 识别瓶颈 → 逐层拆解。你的 QPS 估算做得很好,下次把瓶颈在哪、每层怎么解决说出来,答案就很完整了。
中文部分到这里差不多了,你对 K8s、Terraform、CI/CD 的核心概念掌握得都很扎实,系统设计需要多练分层拆解的思路。
