i007.cc

i007.cc

优先队列-降维打击

05.价值资料

记录一次跟Cluade面试的经历

问题1:你们线上有一个服务需要发布新版本,你会怎么做到零停机更新?K8s 提供了哪些机制保证这一点?

如果我有新版本服务需要发布,我会先部署一部分新版本的服务器,确认没问题了,再逐步扩大规模,直至全部替换掉老版本,k8s提供了rollingUpdate策略可以实现这个功能。

反馈: 方向完全正确,思路清晰。面试官能听出来你理解 rolling update 的核心理念。不过答案还可以更有深度——实际面试中,光说”k8s 有这个功能”还不够,要能说出参数和机制:
  • 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 调度到其他节点

排查步骤也可以更结构化:

  1. kubectl logs <pod> --previous 看崩溃前日志
  2. kubectl describe pod <pod> 看 Events,有没有 OOMKilled、探针失败
  3. 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 Truthterraform 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 的核心概念掌握得都很扎实,系统设计需要多练分层拆解的思路。

发表回复