CI/CD 面试问答(34 题)
本文整理了CI/CD 面试问答(34 题)相关的 34 个高频面试问题,从基础到进阶再到生产实战层层递进,覆盖CI/CD、面试等核心考点,每题附参考回答与追问,适合面试前系统复习。
适用岗位:运维工程师 / 技术支持工程师 / AI 运维工程师 / DevOps 工程师
一、岗位高频速查
| 岗位 | 必考问题(3-5 个) | 一句话要点 |
|---|---|---|
| 运维工程师 | 1. GitLab Runner 怎么注册、用哪种执行器? 2. Harbor 镜像推送失败怎么排查?垃圾回收怎么做? 3. Argo CD 同步失败/OutOfSync 怎么处理? 4. 发布失败怎么回滚? 5. Cert-Manager 证书没签发/过期怎么办? |
偏”跑得起来 + 出问题能救”:注册命令、排查命令、回滚命令张口就来 |
| 技术支持工程师 | 1. CI/CD 是什么?能解决什么问题? 2. 代码提交到线上部署的完整流程讲一遍? 3. 部署效率提升 60% 是怎么衡量的? |
低频偏概念,能把”提交代码 → 构建 → 镜像 → 同步部署”的链路讲清楚即可,不问细节实现 |
| AI 运维工程师 | 1. 大模型/推理服务的镜像怎么构建推送(GPU 基础镜像、体积大)? 2. 镜像仓库大镜像拉取慢/超时怎么办? 3. 模型版本怎么管理、怎么回滚到旧版本? 4. Argo CD 部署推理服务 + GPU 节点调度怎么配合? 5. 推理服务更新怎么做到少中断(滚动/灰度)? |
重点在”大镜像、模型版本、服务不中断”,结合 K8S 调度回答更出彩 |
二、基础篇(12 题)
Q1. 什么是 CI/CD?它的核心价值是什么?
- 【考察点】面试官想验证你是不是只背了概念,能不能讲清楚 CI 和 CD 各解决什么问题、对团队意味着什么。
- 【参考回答】先说结论:CI 是持续集成,代码一提交就自动触发构建、测试、静态检查,把”集成地狱”消灭在每次提交里;CD 是持续交付/持续部署,把构建产物自动发布到环境甚至生产。核心价值就三个词:自动化、快速反馈、质量门禁。自动化省的是人工操作和等待时间;快速反馈是让问题在提交后几分钟内暴露,而不是上线当天爆炸;质量门禁是把 lint、单测、镜像扫描做成流水线里的关卡,不合格直接拦下。我在公司做 CMDB 容器化时搭的就是这条链路:git push 触发 GitLab CI 构建镜像推到 Harbor,Argo CD 检测到清单变更自动同步到集群。
- 【追问 1】CI 和 CD 的边界在哪?——CI 到”产出可交付的制品(镜像)”为止,CD 从”拿到制品部署到环境”开始。我们流水线里 build/push 阶段属于 CI,Argo CD 同步属于 CD。
- 【追问 2】没有 CI/CD 之前团队是怎么发布的?——手动 ssh 上服务器、手动改配置、手动拉镜像 restart,发布一次半小时起步,还经常有人漏步骤,这就是为什么我把”从代码提交到镜像构建”自动化后,发布耗时降了 60%。
- 【岗位标注】通用 / 运维 / 技术支持 / AI 运维 / DevOps
Q2. 你们 CI 和 CD 分别是哪部分技术实现的?各自负责什么?
- 【参考回答】我这边 CI 用的是 GitLab CI:GitLab 托管代码,GitLab Runner 负责执行流水线,流水线里做编译、单元测试、Docker 多阶段构建、trivy 镜像扫描,最后把镜像 push 到 Harbor 私有仓库;CD 用的是 Argo CD 做 GitOps:应用清单(Deployment、Service、Ingress)都存在 Git 仓库里,Argo CD 持续对比 Git 和集群实际状态,有差异就自动同步。所以分工很明确:CI 管”代码变成镜像”,CD 管”镜像按声明的方式跑到集群里”。中间靠镜像 tag 衔接——CI 把 tag 写进 Git 里的清单文件,Argo CD 感知到变化就发版。
- 【追问】镜像 tag 是怎么从 CI 传到 CD 的?——我们 Jenkins 流水线(后来迁移到 GitLab CI)构建完镜像后,用
yq命令把新 tag 写回仓库里argocd_yaml/base/nginx-deployment.yaml的 image 字段,然后git push,Argo CD 轮询到仓库变更自动同步。 - 【岗位标注】通用 / 运维 / DevOps
Q3. GitLab CI 是怎么工作的?.gitlab-ci.yml 里的 stages、jobs 是什么?
- 【考察点】基础中的基础,验证是否真的写过流水线。
- 【参考回答】GitLab CI 的核心是仓库根目录的
.gitlab-ci.yml:push 代码后 GitLab 根据它生成 pipeline,pipeline 按 stages(阶段)串行执行,每个 stage 里可以有多个 job(任务),同 stage 的 job 可以并行。我写的最简例子:
1 | stages: |
job 必须有 script,tags 用来指定由哪类 Runner 执行,image 指定跑这个 job 的容器镜像,only/except 或新版 rules 控制触发条件。
- 【追问 1】如果 build 失败了,push 会执行吗?——不会,同一 stage 的 job 都成功才进入下一 stage,失败默认整个 pipeline 红掉,这也是质量门禁的基础。
- 【追问 2】怎么让某个 job 只在 main 分支触发?——
rules: - if: '$CI_COMMIT_BRANCH == "main"',旧写法是only: - main。 - 【岗位标注】通用 / 运维 / DevOps / AI 运维
Q4. GitLab Runner 是什么?有哪些类型和执行器?怎么注册一个?
- 【考察点】Runner 是流水线的执行引擎,运维岗必问。
- 【参考回答】Runner 是真正跑 job 的程序,可以注册成三种作用域:shared(全局共享)、group(组内项目共享)、project(单项目)。执行器我主要用两种:shell 和 docker。shell 直接在宿主机上跑,快但污染环境;docker 每个 job 起一个容器、用完即弃,隔离干净,构建镜像时用
dockerexecutor +docker:dind服务(docker-in-docker)。注册命令是:
1 | sudo gitlab-runner register \ |
token 在 GitLab 项目 Settings → CI/CD → Runners 里拿,--docker-privileged 是 dind 跑 Docker 构建必需的。
- 【追问 1】dind 是什么坑?——dind 里构建的镜像在容器内,job 结束就没了,所以要把镜像 push 到 Harbor;privileged 有安全风险,生产上可以换成 kaniko(不需要 privileged 也能构建)。
- 【追问 2】Runner 资源不够怎么办?——多注册几台、给 job 打不同 tag 分流,或者用 Kubernetes executor 让 Runner 自动弹 pod。
- 【岗位标注】运维 / DevOps
Q5. GitLab CI 的 cache 和 artifacts 有什么区别?什么时候用哪个?
- 【考察点】高频考点,区分不清说明流水线实践经验不足。
- 【参考回答】一句话:cache 是给”依赖”加速的,artifacts 是给”产物”传参的。cache 存的是依赖包(npm 的 node_modules、Maven 的 .m2、pip 缓存),下次构建直接复用,省的是下载依赖的时间,它不保证一定被用上;artifacts 是 job 的产出文件,传给后面的 job 用,比如编译出的 jar、构建出的镜像清单、测试报告,只在 job 成功时默认上传,可以在 GitLab 界面下载。例子:
1 | build: |
- 【追问】cache 常见问题?——key 设置不当导致缓存失效或串用(不同分支要分开 key),cache 满了不清理、构建机磁盘爆掉。
- 【岗位标注】DevOps / 运维
Q6. GitLab CI 里的变量和 secrets 怎么管理?密码能直接写在 yml 里吗?
- 【考察点】安全意识 + 变量作用域、优先级等细节。
- 【参考回答】绝对不能明文写在 .gitlab-ci.yml 里——仓库是共享的,历史里还能翻出来。正确做法是在 GitLab 项目的 Settings → CI/CD → Variables 里配置,CI 里用
$VAR引用。有两个关键开关:Masked(脱敏,日志里自动打码)和 Protected(只给受保护分支用)。比如 Harbor 的账号密码我一般配成HARBOR_USER/HARBOR_PASSWORD,Robot 账号最安全。优先级从低到高:项目变量 < 组变量(覆盖项目)< 流水线级变量 < job 内variables:关键字。还有内置的CI_REGISTRY_USER、CI_REGISTRY_PASSWORD(deploy token)可以直接登 GitLab 自带 registry。 - 【追问 1】Masked 变量有什么限制?——变量值太短或含特殊格式(如 JSON)可能无法脱敏;脱敏只在 GitLab 日志展示层做,命令里不要 echo 打印。
- 【追问 2】更高级的密钥管理?——和 Vault 集成(
vault:关键字)或 CI 里调用 Vault API 取密钥,不落盘、不落日志。 - 【岗位标注】通用 / 运维 / DevOps
Q7. Harbor 是什么?完整的镜像推送/拉取流程怎么走?
- 【考察点】Harbor 是简历明确写的技能,推送拉取是基本功。
- 【参考回答】Harbor 是开源的私有镜像仓库,支持项目隔离、权限控制、镜像复制、漏洞扫描、配额和垃圾回收。我这边是
harbor.internal,项目按团队分(如 library、ai、ops),普通用户只能 pull,CI 用 Robot 账号 push。推送流程:先配好登录(推荐用 robot account):
1 | docker login harbor.example.com -u 'robot$ci+build' -p '<token>' |
拉取分两种情况:本机能 docker login 后 docker pull;K8s 节点需要先建 docker-registry 类型的 Secret 挂到 Pod 的 imagePullSecrets,或者用 K8s 1.24+ 的 kubernetes.io/dockerconfigjson Secret,配合 ServiceAccount 自动注入。内网机器如果没配证书,要在每台机器的 /etc/docker/daemon.json 加 "insecure-registries": ["harbor.example.com"] 并重启 docker。
- 【追问】生产环境镜像拉不下来常见原因?——认证过期(Secret 里密码是老的)、insecure-registries 没配、节点 DNS 解析不到 Harbor 域名、Harbor 磁盘满了、网络策略挡了 443 端口。
- 【岗位标注】运维 / AI 运维 / DevOps
Q8. Harbor 有哪些常用的仓库策略?垃圾回收(GC)是什么?
- 【考察点】不只是会用,还要懂仓库治理;运维岗会深入问。
- 【参考回答】常用策略四件套:保留策略(Retention)、配额(Quota)、复制(Replication)、垃圾回收(GC)。保留策略按规则自动删旧 tag,比如”每个仓库保留最近 10 个 tag”或”按正则保留 release-.*”、按保留天数删——不然每次发版都留 tag,仓库很快爆掉。配额是按项目限制存储上限。复制是把镜像同步到灾备仓库或离线环境。GC 回收的是”没有被任何 tag 引用的 blob”:先删 tag,blob 失去引用,再跑 GC 才能真正释放磁盘空间。Harbor 2.x 支持在线 GC(旧版要停服务),在 System Settings 里可以配置定时任务。
- 【追问 1】GC 跑的时候能 push 吗?——Harbor 2.4+ 的在线 GC 不影响正常 push/pull;但要注意 GC 只删”无引用 blob”,如果所有 tag 都指向同一层,那层不会被删,所以先确认 tag 删干净了。
- 【追问 2】怎么验证 GC 真的释放了空间?——在 Harbor 管理界面看存储统计,或者
du -sh /data/registry/docker/registry/v2对比前后大小。 - 【岗位标注】运维 / DevOps
Q9. Docker 多阶段构建是什么?为什么要用它?镜像优化还有哪些手段?
- 【考察点】镜像构建是 CI 的核心环节,多阶段构建几乎必问。
- 【参考回答】多阶段构建就是一个 Dockerfile 里多个 FROM,前一阶段负责编译,后一阶段只拷贝产物,最终镜像只保留运行时需要的东西。以 Go 服务为例:
1 | FROM golang:1.21-alpine AS builder |
好处是最终镜像里没有编译器、源码、依赖缓存,体积能小 80% 以上,攻击面也小。其他优化手段:基础镜像选 alpine 或 distroless(甚至 scratch)、.dockerignore 排除 .git 和 node_modules、层顺序把”不常变的依赖拷贝”放前面利用缓存、用 --mount=type=cache 缓存 apt/go mod 下载。
- 【追问】镜像大小为什么重要?——拉取快(尤其离线环境)、启动快、漏洞少、磁盘占用低;我们离线部署场景里镜像从几个 G 压到几百 M,部署效率提升明显。
- 【岗位标注】通用 / DevOps / AI 运维
Q10. Argo CD 是什么?GitOps 是什么?为什么说”声明式”?
- 【考察点】简历核心技能,必须讲清原理而不是只会点按钮。
- 【参考回答】GitOps 的核心思想:Git 仓库是应用状态的唯一事实来源(Single Source of Truth),一切变更先改 Git,然后有个控制器把 Git 里的状态”拉”到集群并保持两者一致。Argo CD 就是这个控制器:它持续对比 Git 仓库里的清单(Deployment、Service、Ingress 等)和集群当前状态,不一致就标记 OutOfSync,配了自动同步就执行同步。声明式就是”我只描述想要什么(desired state),不关心怎么达到”——比如我写”副本数 3”,Argo CD 负责把集群调成 3,而不是我手动
kubectl scale。我在容器化改造里就是把 nginx 等服务的清单放到argocd_yaml/base/目录(配合 kustomize),建了 Application 指向那个路径,之后的发布全是”改 Git → 自动同步”。 - 【追问 1】Argo CD 怎么发现 Git 有变化?——默认每 3 分钟轮询一次 repo,也可以配 GitLab webhook 触发即时刷新。
- 【追问 2】OutOfSync 和 Healthy 分别什么意思?——OutOfSync 是”Git 声明和集群实际不一致”(待同步);Healthy 是”应用运行健康”(Pod 就绪等)。两者独立:可能 Git 同步了但应用运行不健康(Degraded)。
- 【岗位标注】DevOps / 运维 / AI 运维
Q11. 部署策略有哪些?滚动、蓝绿、金丝雀、灰度各是什么?怎么选?
- 【考察点】发布体系的核心知识,DevOps 必问,回答要能落到 K8s 配置。
- 【参考回答】四种主流策略。滚动更新(Rolling)是 K8s 默认:新 Pod 逐个替换旧 Pod,通过
maxUnavailable和maxSurge控制节奏,比如maxSurge: 1, maxUnavailable: 0保证始终有完整容量,平滑但出问题回滚要等滚动完成。蓝绿(Blue/Green):两套 Deployment 同时存在,Service 的 selector 指向哪套就发布到哪套,切 selector 瞬间切换、回滚也是瞬间切回,代价是双倍资源。金丝雀(Canary):新版本先放 5%-10% 流量,观察指标没问题再逐步放大到 100%,用 nginx-ingress 的nginx.ingress.kubernetes.io/canary: "true"+canary-weight: "10"注解实现。灰度(Gray)和金丝雀常混用,但灰度更偏”按用户分组/比例放量”,可以按 header、cookie、地域分,支持 A/B 测试。选型看场景:核心无状态服务用蓝绿保证秒级回滚;大版本不确定用金丝雀;资源紧张就滚动。 - 【追问】你线上主要用哪种?——多数服务滚动+不可变 tag;关键变更用金丝雀先放量观察;配合 Argo CD 的 sync 策略做自动发布。
- 【岗位标注】DevOps / 运维 / AI 运维
Q12. GitLab CI 和 Jenkins 怎么选?你实际用过哪个?
- 【参考回答】两者我都接触过,公司老流水线有 Jenkinsfile,新的 CI/CD 工具链用的 GitLab CI。选型看场景:Jenkins 生态老、插件多(2 千多个)、自由风格项目上手快、适合异构环境复杂编排,缺点是维护重、Master 单点、Pipeline as Code 是后补的;GitLab CI 最大的优势是”和代码仓库一体”——MR 里直接看到流水线结果、天然做合并门禁、yaml 即配置、Runner 弹性伸缩、内置 registry,对”Git 驱动”的团队来说心智负担小很多。我新搭的链路上 GitLab CI + Harbor + Argo CD 三个组件职责干净:代码托管/流水线、制品仓库、GitOps 发布。
- 【追问】Jenkins 和 Argo CD 能配合吗?——能,老项目就是 Jenkins 构建推 Harbor,再更新 Git 清单,Argo CD 同步(我们早期 Jenkinsfile 就是这套模式,用 yq 改 yaml 后 push),所以 Jenkins 不是被淘汰,是职责收窄到”构建制品”。
- 【岗位标注】通用 / DevOps / 运维
三、进阶篇(12 题)
Q1. 怎么组织 .gitlab-ci.yml 才可维护?include 和 rules 怎么用?
- 【考察点】考察流水线工程化能力——小项目一个文件搞定,生产环境文件会爆炸。
- 【参考回答】核心是”模板化 + 复用 + 按环境收敛”。做法:把公共的 job 定义抽到仓库根的
ci/templates.yml,用include引入:
1 | # ci/templates.yml |
extends 继承模板,job 里可以覆盖部分字段;rules 比旧版 only/except 强大得多,支持条件组合、when: manual(人工触发)、allow_failure(允许失败不阻塞)。还可以 include: project 跨项目引用公共模板(比如公司统一的 trivy 扫描 job)。生产建议:分支合并前必须流水线绿(MR 门禁),main 分支的 job 要加 when: manual 的人工审批再发生产。
- 【追问】rules 里
when: manual有什么用?——发生产前人工点一下确认,既是审批又是审计留痕,配合allow_failure: false强制通过。 - 【岗位标注】DevOps
Q2. 镜像构建慢怎么优化?BuildKit、构建缓存、registry 加速分别怎么用?
- 【考察点】生产真实痛点,考察是否踩过坑。
- 【参考回答】构建慢主要三个原因:拉基础镜像慢、依赖下载慢、层缓存不生效。解法:一是开 BuildKit(Dockerfile 顶部
# syntax=docker/dockerfile:1,构建时DOCKER_BUILDKIT=1),支持RUN --mount=type=cache,target=/var/cache/apt这类挂载缓存,COPY --link不依赖前面层缓存;二是 GitLab CI 里配cache缓存依赖目录(go mod、npm),或把构建缓存 push 到 registry 用--cache-from复用;三是内网环境用 Harbor 的 Proxy Cache 项目或搭建 registry mirror——我们离线部署时就是镜像缓存到本地,断网环境也能快速拉取。还要注意 Dockerfile 层顺序:COPY 依赖文件(go.mod)放前面,源码放最后,这样源码变了依赖层还能命中缓存。 - 【追问】dind 构建的缓存为什么不生效?——dind 每次 job 起全新容器,本地层缓存全丢,所以要么 push 镜像时连带 cache manifest,要么改用 kaniko 挂 PVC 缓存。
- 【岗位标注】DevOps / 运维 / AI 运维
Q3. 镜像漏洞扫描怎么落地?trivy 和 Clair 怎么选?
- 【参考回答】我这边两种方式都用过:CI 阶段用 Trivy 扫描阻断,Harbor 侧接扫描器做持续巡检。Trivy 在流水线里加一个 stage:
1 | scan: |
--exit-code 1 让高危漏洞使 job 失败、流水线红掉,实现”带漏洞不放行”;--ignore-unfixed 是只报有修复版本的漏洞,避免被无解的系统漏洞卡死。Harbor 里在 Interrogation Services 添加 Trivy/Clair 适配器,推送镜像后自动扫描,页面上按 severity 排序,还能配 CVE allowlist(白名单)豁免。选型:Trivy 轻量、离线可用(下载 db)、扫描快,适合 CI 内嵌;Clair 是传统方案、依赖 API 解析,现在新项目一般用 Trivy。
- 【追问】高危漏洞很多、项目又要上线怎么办?——先看是否”可利用 + 是否公网暴露 + 是否有缓解措施”,能豁免的走评审流程记录到 allowlist,不能豁免的必须修;禁止为赶进度把
--exit-code 1全局去掉。 - 【岗位标注】DevOps / 运维 / AI 运维
Q4. Harbor 垃圾回收的原理是什么?有什么坑?
- 【考察点】简历写了 Harbor,GC 是运维最常踩坑的点之一,容易暴露”只点过按钮”。
- 【参考回答】原理:镜像存储是内容寻址的,一个 tag 指向 manifest,manifest 引用一堆 blob(层)。删 tag 只删引用,blob 还在,GC 就是扫描 registry 找出”没有任何 tag 引用的 blob”并删除,释放磁盘。所以正确顺序是:先跑保留策略或手动删 tag → 再触发 GC。坑有三个:第一,旧版 Harbor GC 要停写(只读模式)才能跑,2.x 以后有在线 GC;第二,GC 期间如果还有并发 push 可能误判删除,官方建议低峰期跑;第三,GC 不是万能的——如果 manifest 还在(tag 没删),对应 blob 永远不会被清,磁盘满要先查”是不是 tag 堆太多”而不是只怪 GC。
- 【追问】GC 后镜像还能正常拉吗?——能,GC 只删无引用 blob,被引用的层不动;如果出现拉取 404,基本是并发删除场景误判,需要从复制规则或备份恢复。
- 【岗位标注】运维
Q5. 离线/内网环境怎么部署 Harbor 和整套 CI/CD?镜像怎么同步进去?
- 【考察点】简历明确写了”全套离线部署方案”,这是差异化亮点,面试官会深挖。
- 【参考回答】离线部署的核心是”内容本地化 + 无外网可运维”。我们当时的做法分四层:一是依赖本地化,所有 rpm/deb、容器镜像、Helm chart、安装包都提前下载好放进离线包;二是镜像缓存,用 Harbor 的复制规则(Replication)把外网或源仓库的镜像拉到离线 Harbor——配 push 模式规则,源端是
docker.io白名单代理或者用skopeo copy批量同步,支持按 tag 正则过滤(比如只同步release-.*);三是离线安装,Harbor 本身用./install.sh --offline(离线安装包预置了所有依赖镜像),K8s 侧镜像通过docker save/load或让节点从内网 Harbor 拉;四是断网验证,全部装完断掉外网跑一遍全流程,确保没有任何隐式外网依赖。另外离线环境强烈建议配 DNS 或/etc/hosts+ insecure-registries,不然每台机器拉镜像都要改 daemon.json。 - 【追问】离线环境镜像拉取慢怎么办?——内网带宽不够就做节点本地镜像缓存(containerd 的 image store 或每节点预拉),或按批次错峰拉取。
- 【岗位标注】运维 / AI 运维
Q6. Argo CD 的 Application 怎么定义?多环境、多集群怎么管理?
- 【考察点】简历写”Argo CD GitOps”,多环境管理是生产必然场景,考察真实落地深度。
- 【参考回答】Application 是一个 CRD,声明”哪个仓库、哪个路径、同步到哪个集群的哪个命名空间”。我管理多环境用两个手段:一是按路径分环境,
config/dev/、config/prod/两个目录,dev 的 Application 开自动同步,prod 的 Application 用automated+prune但发版走人工确认;二是环境差异用 Kustomize 的 overlay 或 Helm values 解决——同一套 base 清单,dev/prod 覆盖不同镜像、副本数、资源限制。多集群用 ApplicationSet(git generator 或 list generator)批量生成 Application。一个关键的 sync 细节是syncOptions里CreateNamespace=true(自动建命名空间)、Prune=true(删除 Git 里删掉的资源)、SelfHeal=true(发现集群被手改自动纠正回来)。同步顺序用 sync-waves 注解:先 CRD、再 ConfigMap、最后 Deployment。 - 【追问 1】selfHeal 有什么风险?——集群上有人
kubectl patch应急改的东西会被 Argo CD 5 分钟内改回去,所以生产要明确纪律:应急操作必须同时改 Git,否则会被”纠正”;实在要手动干预可以先暂停自动同步。 - 【追问 2】Application 删了资源会没吗?——
kubectl delete application默认不级联删除资源(cascade 要显式开),但重建 Application 指向同路径会重新接管,所以一般先恢复 Application 再看资源。 - 【岗位标注】DevOps / 运维
Q7. GitOps 的回滚到底怎么做?git revert、argocd rollback、reset 有什么区别?
- 【考察点】回滚是 CD 的灵魂问题,面试官几乎必问,且最容易答得含糊。
- 【参考回答】GitOps 回滚的本质是”把 Git 里的声明改回旧版本”,Argo CD 感知后把集群也拉回去。三条路径:第一,
git revert上一个提交,推上去自动同步——推荐,因为保留历史、可审计、符合 GitOps 原则;第二,argocd app rollback <app> <历史版本号>——它把集群状态回退到之前某个已同步版本,但不改 Git 仓库,会造成”集群和 Git 不一致”,只适合紧急止血;第三,git reset --force强推——会重写历史,多人在用时不推荐。我生产上的标准流程是:紧急情况先argocd app rollback止血(或直接把 Deployment 的 image tag 改回旧 tag 推 Git),事后补git revert让 Git 和集群重新一致。 - 【追问】回滚能成功的前提是什么?——镜像 tag 必须是不可变的(用 commit SHA 或构建号做 tag),如果 tag 是
latest,旧清单指向的镜像可能已经被新镜像覆盖,回滚等于白回。 - 【岗位标注】DevOps / 运维
Q8. GitOps 和传统 CD(Jenkins 直接部署)的本质区别是什么?
- 【考察点】考察原理理解深度,只会”会操作”答不好这题。
- 【参考回答】本质区别四点:一是驱动方向,传统 CD 是 push 模式——CI 服务器主动 ssh 到目标机或调 kubeconfig 执行部署;GitOps 是 pull 模式——集群里的控制器主动从 Git 拉取声明。二是状态管理,传统 CD 部署完就完了,集群实际状态没人持续校验,谁手改了没人知道;GitOps 里 Argo CD 持续对比 Git 与集群,漂移(drift)会被标记 OutOfSync,配 selfHeal 自动纠正。三是回滚,传统 CD 回滚靠重跑旧脚本/旧制品,容易”脚本对不上当前环境”;GitOps 回滚就是改 Git。四是权限与审计,传统 CD 通常要一个”能操作所有集群的凭证”,泄露风险大;GitOps 里改集群的入口收敛为”改 Git + 仓库权限 + MR 评审”,谁改了什么、为什么,git log 一目了然,符合等保审计要求。
- 【追问】pull 模式有什么缺点?——多了一层组件(Argo CD 本身要维护、要高可用);Git 与集群网络必须通;对”非声明式”的临时操作(调试、数据修复)不友好。
- 【岗位标注】DevOps / 运维
Q9. Cert-Manager + Let’s Encrypt 自动证书是怎么实现的?HTTP-01 和 DNS-01 区别?
- 【考察点】简历明确写了 Cert-Manager,必须能讲出完整机制而不是”装了个工具”。
- 【参考回答】原理:Cert-Manager 是 K8s 里的证书控制器,我配了一个 ClusterIssuer 对接 Let’s Encrypt ACME 服务,然后给 Ingress 加注解,它自动申请、签发、注入、续期证书。核心配置:
1 | apiVersion: cert-manager.io/v1 |
Ingress 加注解 cert-manager.io/cluster-issuer: letsencrypt-prod,证书自动写到指定 Secret,nginx 自动加载。HTTP-01 是”Let’s Encrypt 访问你的域名 /.well-known/acme-challenge/ 验证域名归属”,要求 80 端口公网可达;DNS-01 是”往 DNS 加一条 TXT 记录验证”,不依赖 80 端口,适合内网/端口受限场景,阿里云用 cert-manager-webhook-aliyun 这类 webhook 自动加记录。续期是自动的:证书有效期 90 天,Cert-Manager 在剩余约 1/3 时自动 renew,全程无感。
- 【追问】证书没签发怎么排查?——
kubectl get certificate看状态,kubectl describe certificate、查 CertificateRequest 和 Order/Challenge 的 events:HTTP-01 不通多是 ingress class 不匹配或 80 端口没通;DNS-01 失败多是 webhook 的 accessKey 权限不够。 - 【岗位标注】运维 / DevOps / AI 运维
Q10. 金丝雀/灰度发布在 K8s 里怎么真正落地?Argo Rollouts 用过吗?
- 【考察点】从”知道策略名词”到”能落地”,这是运维和 DevOps 的分水岭问题。
- 【参考回答】落地有两条路。轻量方案:nignx-ingress 的金丝雀注解,新版本 Deployment 先起少量副本,ingress 按权重切流量:
1 | apiVersion: networking.k8s.io/v1 |
观察 10% 流量没问题,把 weight 改成 30、50、100 逐步放量;出问题改回 0。这个方案简单,但”观察 + 决策 + 改注解”还是人工的。进阶方案:Argo Rollouts,它把 Deployment 换成 Rollout 资源,用 steps 定义放量节奏,还能配 Analysis(对接 Prometheus 指标自动判断成败):指标异常自动 abort 回滚到 stable 版本,全程不需要人盯着。我实际用的更多是前者(配合 Argo CD 管理清单),理解思路比背工具重要。
- 【追问】金丝雀和蓝绿能结合吗?——能,Argo Rollouts 支持 canary 里带蓝绿语义(先起全套新版本、切流量、保留旧版本若干时间),关键是大流量服务要保证新旧版本同时在线时的容量。
- 【岗位标注】DevOps / AI 运维
Q11. 多环境流水线(dev/staging/prod)怎么设计?环境晋升(promotion)怎么做?
- 【考察点】生产级流水线设计,考察是否只管过单环境。
- 【参考回答】我的设计原则:”一次构建、多处部署”——同一 commit 只构建一次镜像,tag 用
$CI_COMMIT_SHA,dev/staging/prod 只是把同一个镜像按各自环境配置部署。流水线分三段:dev 全自动(提交即构建即部署);staging 自动部署但接自动化冒烟测试,测试挂了流水线红;prod 用when: manual人工点击 + 环境变量控制:
1 | deploy-prod: |
promotion(晋升)的核心是”制品不可变 + 环境配置分离”:镜像只有一个,各环境差异(域名、副本数、资源配置)全部收在各自的 values/overlay 里,谁晋升只是把同一镜像指到下一环境,这样 staging 测过的东西 prod 一定一样,杜绝”prod 又拉了个新镜像”的经典事故。Argo CD 侧就是三个 Application 指向三个目录,手动晋升 = 触发 prod 目录的同步。
- 【追问】人工审批除了手动 job 还有什么做法?——GitLab 的 Environment Approval(环境审批规则)、或者 MR 评审本身作为门槛。
- 【岗位标注】DevOps / 运维
Q12. GitOps 里密钥(secrets)怎么管理?仓库里能放 Secret 吗?
- 【考察点】安全敏感点:Git 是版本库,把 Secret 明文放进去等于把密钥写进历史,面试官必挖。
- 【参考回答】原则:明文 Secret 绝对不能进 Git 仓库,哪怕私有仓库也不行——历史删不掉、权限难收。成熟方案三种:Sealed Secrets(Bitnami):把 Secret 用公钥加密成 SealedSecret 存进 Git,集群内控制器私钥解密生成真 Secret,仓库里只有密文,简单好用;External Secrets Operator:Git 里只放一个”引用”(SecretStore + ExternalSecret),真正密钥存在 Vault/AWS Secrets Manager/阿里云 KMS 里,控制器运行时拉取,密钥轮换不用改 Git;SOPS:配合 age/PGP 加密 YAML 里的敏感字段。我这边密钥少,用的 External Secrets + Vault 思路,Harbor/镜像仓库这类凭证走 GitLab CI/CD Variables 的 protected + masked,不进 yml。如果发现历史里已经放过明文,用
git filter-repo或 BFG 清理并强制轮换密钥。 - 【追问 1】Sealed Secrets 和 External Secrets 怎么选?——密钥改动频繁、要轮换选 External Secrets;就想”把加密后的 Secret 版本化管理”选 Sealed Secrets。
- 【追问 2】Pod 里挂载 Secret 有什么注意?——Secret 更新后默认不会自动重载到已运行的 Pod,要么滚动重启,要么用 reloader 组件监听自动滚动。
- 【岗位标注】DevOps / 运维
四、生产实战·刁钻篇(10 题)
Q1. 简历写”部署效率提升 60%”,这个 60% 是怎么算出来的?
- 【追问 1】20 分钟里能不能再优化?——能,构建的 15 分钟主要是冷缓存编译,上构建缓存和并行 stage 后能再压缩 30%。
- 【追问 2】有没有反面指标?——有,早期 Argo CD 自动同步刚开时出过一次”同步删掉了不该删的资源”的教训,后来加了 prune 白名单和评审,这是后话了。
- 【岗位标注】通用 / DevOps / 运维 / 技术支持 / AI 运维
Q2. 生产上镜像 push 一直失败,报 413 Request Entity Too Large,怎么排查?
- 【考察点】真实故障场景,考察排查思路是否成体系(链路式排查),而不是背命令。
- 【参考回答】413 是”请求体太大”,说明请求到达了某个反代/网关但被大小限制拦了。链路排查:先是哪一层报的——如果
docker push直接报 413,通常是 Harbor 前面 nginx 的client_max_body_size限制,默认配置对大镜像(几个 G 的 AI 推理镜像常见)不够,改/etc/nginx/nginx.conf里client_max_body_size 0;(不限)或调大到 8g 后 reload;如果经过了自己的网关/负载均衡,还要检查那一层的 body 限制(如云 SLB、Ingress 的proxy-body-size注解)。同时配合其他可能:401 是认证问题(robot 账号过期、权限只给了 pull)、500/502 是 Harbor 后端故障(看/var/log/harbor/日志)、超时是网络。还有一个高频坑是磁盘满——Harbor 数据盘满时 push 会报 500 或空间不足,先df -h看数据盘,配合前面的保留策略 + GC 清理。 - 【追问】排查时先看什么日志?——先看报错输出本身(docker push 的 stderr 是分层的,能定位到第几层失败),再看 Harbor core/nginx 容器日志,最后看数据盘和 Harbor 健康检查页。
- 【岗位标注】运维 / AI 运维
Q3. 生产发布失败了,你的完整回滚流程是什么?从发现到恢复多久?
- 【考察点】刁钻点:面试官要的是”操作序列 + 决策点”,不是”我会回滚”。
- 【参考回答】我的标准动作分三步。第一步止血判定:同步或部署失败、应用不可用时,先确认是”新版本自身问题”还是”环境问题”——看 Argo CD 的 Sync/Health 状态和 Pod 日志,1 分钟内判断。第二步回滚:优先
git revert上一个发布提交并推送(Argo CD 自动同步回旧声明,干净、留痕);如果判断是紧急服务不可用,直接argocd app rollback <app> <上上个同步版本>秒级拉回,同时知会团队”集群与 Git 暂时不一致,稍后补 revert”。第三步验证与复盘:argocd app get确认 Healthy、拨测接口确认恢复,然后排查根因(镜像问题?配置问题?依赖不兼容?),补测试用例,必要时把失败版本做成不可变 tag 保留供分析。恢复时间:蓝绿/回滚操作本身 1-2 分钟,加上判定时间一般 5 分钟内恢复。 - 【追问】如果回滚的旧版本镜像已经没了怎么办?——说明镜像保留策略把旧 tag 清了,这是教训:生产镜像保留策略要保留足够历史(比如最近 30 个 tag 或 90 天),否则”回滚没有弹药”。我们的保留策略就是为此设计的。
- 【岗位标注】运维 / DevOps
Q4. 镜像 tag 用的是 latest,为什么 Argo CD 永远显示 Synced、新代码根本没上线?
- 【考察点】经典生产事故:把 GitOps”只认清单”的特性当 bug 考你。
- 【参考回答】因为 Argo CD 对比的是”Git 清单”和”集群状态”,而清单里 image 写的是
nginx:latest——latest 变了,但清单文本一个字没变,Git 没有新提交,Argo CD 认为声明没变化,自然不触发同步,也不会标记 OutOfSync。这是 immutable tag 问题的根源:latest 是”可变的引用”,不是版本。解决方案是强制不可变 tag:CI 里用$CI_COMMIT_SHA(前 7 位)或构建号做 tag,并且 CI 要把新 tag 写回 Git 清单并提交(我们就是 Jenkinsfile 里用 yq 把 image 字段改成harbor.internal/library/my-nginx:0.${BUILD_NUMBER}再 push 仓库,触发 Argo CD)。配套还可以上 Argo CD Image Updater 自动检测新镜像更新清单,但前提也是 tag 有语义(不可变 + 可排序)。 - 【追问】还想用 latest 的话怎么兜底?——可以用
argocd-image-updater的 tag 策略(semver/最新)定期比对 registry,但它解决不了”镜像已覆盖、历史不可追溯”的根本问题,生产还是建议不可变 tag。 - 【岗位标注】DevOps / 运维
Q5. 流水线越来越慢,从哪些维度排查和优化?给个排查顺序。
- 【考察点】面试官模拟你接手一条老流水线,考察系统性思维。
- 【参考回答】按”先定位再优化”排:第一步看 pipeline 耗时分解(GitLab 界面每个 job 的耗时),找出最慢的 stage——是构建、测试还是 push?第二步看是否”每个 job 都在拉大基础镜像”:把
image: golang:1.21换成预装了缓存的镜像,或用 Harbor 代理缓存 docker.io,内网拉取能省几十秒到几分钟。第三步看构建缓存:无缓存构建是大头,检查 BuildKit 缓存、依赖目录 cache、--cache-from,一般能砍 40% 以上。第四步看并行度:同 stage 的 job 是否串行了(没并行的话把能拆的 job 拆开、配置足够的 Runner 并发);是否所有 job 挤在一个 Runner 上。第五步看 artifacts/日志:大 artifacts 上传下载慢,expire_in和路径裁剪;日志太多也拖慢。最后看 Runner 本身:磁盘 IO、内存、docker 镜像存储清理(docker system prune)。优化顺序永远是”先测耗时分布 → 打最大的点”,不要盲目上缓存。 - 【追问】Runner 队列堵了怎么判断?——GitLab 的 CI/CD → Jobs 里 pending 的 job 数量,pending 多说明 Runner 并发不足或 tag 匹配不上(注册的 tag 和 job 的 tags 对不上,job 会一直 pending)。
- 【岗位标注】DevOps / 运维 / AI 运维
Q6. trivy 扫出高危漏洞,但业务着急上线,你作为运维怎么处理?
- 【考察点】安全 vs 业务的真实博弈,考察原则性 + 可操作性(不是无脑放行也不是无脑卡死)。
- 【参考回答】我的处理是”分层决策 + 留痕豁免”,而不是一刀切。第一步评估严重性:
trivy image --severity HIGH,CRITICAL --ignore-unfixed看具体 CVE——是否可远程利用?是否暴露在公网入口?目标端口是否被防火墙挡了?很多高危漏洞在网络层面就被隔离了,风险可控。第二步找修复路径:基础镜像升级能不能解(比如换 alpine 小版本)?能解就花 10 分钟重构建,这通常是最优解。第三步确需紧急上线:走豁免流程——在 Harbor 项目的 CVE allowlist 里加白名单并填备注(关联 ticket),或 CI 里用.trivyignore文件按 CVE ID 豁免,同时必须记录:上线窗口、责任人、修复计划日期、事后补发修复版本。绝不允许的做法:为上线临时把扫描 stage 删掉或把--exit-code去掉——那是把安全门禁整个拆了。 - 【追问】Harbor 的 allowlist 和 CI 的 ignore 有什么区别?——allowlist 管”仓库侧扫描结果展示与拦截”,ignore 管”CI 门禁是否放行”,生产上建议两者都用且都留痕,单一处豁免容易被绕过。
- 【岗位标注】运维 / DevOps / AI 运维
Q7. GitOps 模式下,谁能改生产?怎么防止有人直接 kubectl 改集群或者改坏 Git?
- 【考察点】治理问题:GitOps 不是”装个 Argo CD 就完事”,权限设计才是落地难点。
- 【参考回答】三层治理。第一层 Git 侧:生产清单在 protected branch 上,所有变更走 Merge Request,必须 code review + 流水线通过才能合并——改生产 = 过评审,这是第一道闸。第二层 Argo CD 侧:RBAC 用 policy.csv 控制谁能 sync/rollback 哪个项目,比如
p, role:admin, applications, *, *, allow,普通开发者只给 view 权限;Application 之间的 Project 隔离,生产项目只有运维角色能操作。第三层集群侧:Argo CD 的 ServiceAccount 只给需要的 namespace 最小权限(不要给 cluster-admin),甚至projects里限制destinations(只能部署到指定集群/命名空间);kubectl apply -f直连集群的权限收拢到运维专用账号。防止”改坏 Git”靠的是:revert 而非 reset(不重写历史)、push 前本地git diff检查、CI 里加清单校验(kubectl apply --dry-run=client或 kubeconform 校验 yaml 合法性)。 - 【追问】有人直接在集群里改了资源(漂移)怎么办?——自愈(selfHeal)开着就会自动纠正回去,同时可以配 webhook 告警提醒”检测到漂移已纠正”,从流程上杜绝”绕过 Git”。
- 【岗位标注】DevOps / 运维
Q8. Argo CD 或 Harbor 本身挂了,发布体系瘫痪了,你怎么恢复?平时做什么准备?
- 【考察点】”运维自己也是要运维的”,考察高可用意识和灾备实操。
- 【参考回答】分两个层面。平时准备:Argo CD 和 Harbor 都以多副本高可用部署(Argo CD 2+ 副本 + repo-server 扩容,Harbor 前面负载均衡 + 数据盘定期快照 + 复制规则把镜像同步到灾备仓库),关键配置
argocd-cm、argocd-rbac-cm、argocd-secret、Harbor 的配置和数据目录做定期备份,并演练过恢复流程。故障恢复:Argo CD 挂了不影响已部署应用(它只是控制器,Pod 照跑),影响的是”新发布”——此时可以先手动kubectl apply应急,Argo CD 恢复后如果清单一致会自动接管;Argo CD 应用本身崩溃就kubectl -n argocd rollout restart deployment/argocd-server或看 argocd-repo-server 日志。Harbor 挂了影响构建推镜像,应急办法是让 CI 暂时推到备用仓库(提前配好镜像同步/备用地址),Harbor 恢复后补同步;数据盘坏了就从快照恢复,镜像丢了靠复制规则从灾备拉回。 - 【追问】为什么 Argo CD 挂了应用还能跑?——Argo CD 只是”声明与集群状态的调解器”,它不在应用的数据路径上;只要集群 API 正常,已创建的 Deployment 由 kubelet/controller-manager 继续维护。
- 【岗位标注】运维
Q9. 证书一直没签发,或者 Let’s Encrypt 报 rate limit 429,怎么排查和处理?
- 【考察点】Cert-Manager 真实排障,考察事件链(Certificate → CertificateRequest → Order → Challenge)是否熟悉。
- 【参考回答】排查按事件链走:
kubectl get certificate看状态,不是 Ready 就看kubectl describe certificate里的事件,会指到 CertificateRequest;再kubectl get certificaterequest、kubectl get order、kubectl get challenge逐层看,每一层的 reason/events 都能定位问题。常见三类:HTTP-01 失败——ingress class 和 Issuer solver 里写的 class 不一致(或挑战路径被网关拦)、80 端口没通、域名解析到别处;DNS-01 失败——webhook 的 accessKey 权限不足、TXT 记录没生效(等 DNS 传播);rate limit——Let’s Encrypt 每个注册域名每周 50 张证书、重复证书每周 5 张,429 说明触发限流,处理:换测试用 staging issuer(https://acme-staging-v02.api.letsencrypt.org),别用生产环境反复试错;生产 429 只能等窗口期,期间临时用自签证书顶一下并通知用户。另外记得检查是不是”每个 Ingress 都独立申请了证书”导致数量爆炸——同域名用同一 Secret 复用证书。 - 【追问】怎么监控证书快过期?——cert-manager 会自动续期(剩余 1/3 生命周期时),但要做兜底告警:Prometheus 的
certmanager_certificate_expiration_timestamp_seconds指标,剩余 7 天告警;也有 blackbox 探测 HTTPS 证书过期时间。 - 【岗位标注】运维 / AI 运维
Q10. 金丝雀放量到 50% 时指标异常,你怎么快速处理?为什么不是直接 kubectl delete 新版本?
- 【考察点】应急决策 + 对发布体系机制的理解,考察”治标”和”治本”。
- 【参考回答】快速处理三步:第一步止损——金丝雀流量权重立刻改回 0(ingress 注解
canary-weight: "0"或删 canary 注解),流量全部回到稳定版本;如果是 Argo Rollouts,执行kubectl argo rollouts abort <rollout>,它会自动切回 stable 版本。第二步保留现场——新版本 Deployment/Rollout 先不删,保留 Pod 抓日志、看监控、dump 现场,方便定位根因;直接kubectl delete会把证据一起删了,这是为什么不建议直接删。第三步复盘——定位是代码问题还是配置问题,修好后走完整发布流程重新金丝雀。同时要把这次异常沉淀成 Analysis 规则:Argo Rollouts 里可以配 Prometheus 查询(错误率、P99 延迟)作为自动判断条件,下次指标一超直接自动 abort,不需要人盯着。 - 【追问】为什么金丝雀要用独立 Deployment 而不是改原 Deployment 的镜像?——独立 Deployment 才能让新旧版本并行、互不干扰,回滚时旧版本副本还在;改原 Deployment 镜像等于直接全量替换,就失去金丝雀的意义了。
- 【岗位标注】DevOps / AI 运维 / 运维