这三个工具是云原生和微服务时代的"铁三角",分别解决了**"怎么打包"、"怎么调度"、"怎么观测"**这三个核心问题。面试官通过这个问题,能快速判断你是否具备生产级系统的部署思维。
结合你之前的大模型(LLM / Agent)背景,我来给你拆解清楚,并附上面试中的"AI 视角"加分回答。
1. Docker(容器化)------"标准化集装箱"
- 它是干什么的 :把代码、运行环境(Python 依赖、模型权重)、配置文件打包成一个轻量级的、可移植的"容器"。它解决了"在我机器上能跑,在你机器上跑不了"的千古难题。
- 本质:利用 Linux 的 Namespace(隔离)和 Cgroups(资源限制)技术,实现进程级的隔离。
- AI 场景中的应用 :
- 把你的 FastAPI 智能体服务打包成镜像。
- 把带有依赖的 Chroma / Milvus 向量数据库打包。
- 当你需要加载 10GB 的嵌入模型时,Docker 可以限定该容器内存上限,避免因内存溢出(OOM)拖垮宿主机。
2. Kubernetes / K8s(容器编排)------"集装箱调度指挥官"
- 它是干什么的 :当你的机器从 1 台变成 100 台,Docker 就管不过来了。K8s 负责自动部署、弹性伸缩、故障自愈 和服务发现。
- 核心能力(高频考点) :
- Pod:K8s 的最小调度单位,一个 Pod 里可以运行一个或多个 Docker 容器。
- HPA(水平自动伸缩):根据 CPU 使用率或自定义指标(如队列长度)自动增加或减少 Pod 数量。
- 自愈:如果 Agent 服务挂了,K8s 会自动重启它。
- AI 场景中的应用(面试重点) :
- GPU 调度 :通过
nvidia.com/gpu资源申明,K8s 能将推理任务调度到带 GPU 的节点上。 - 金丝雀发布:升级智能体时,先让新版本承接 5% 的流量,验证无问题后再全量切换,避免新版的 Prompt 调整导致大面积报错。
- GPU 调度 :通过
3. Prometheus(普罗米修斯)------"监控与报警眼睛"
- 它是干什么的 :它是一个指标采集 和时序数据库(TSDB)。它会定期(比如每 15 秒)去你的服务里拉取(Pull)指标,并存储下来。
- 核心概念(高频考点) :
- Metrics(指标) :比如
http_requests_total(请求总数)、llm_token_usage(Token 消耗量)。 - Pull 模型 :服务方需要暴露一个
/metrics接口,Prometheus 主动来抓取,而不是服务方上报(Push)。 - AlertManager:当指标异常时(如 Agent 的 500 错误率超过 10%),发送告警到钉钉、邮件或电话。
- Metrics(指标) :比如
- AI 场景中的应用(面试亮点) :
- 监控 GPU 显存 :如果你的 Agent 用了开源模型进行本地推理,Prometheus 结合
dcgm-exporter可以监控 GPU 温度、显存占用率。 - Token 消耗计费 :可以在 Agent 代码里暴露
token_consumed_total,用 Prometheus 统计每天花费了多少 API 费用。
- 监控 GPU 显存 :如果你的 Agent 用了开源模型进行本地推理,Prometheus 结合
🏗️ 它们是怎么协同工作的?(必答逻辑链)
面试时,你最好能画出这个"生命周期":
- 开发期:你写好了 Python 智能体代码。
- 构建期 :用 Docker 把代码 + 环境打包成一个镜像(
docker build -t my-agent:v1)。 - 部署期 :把这个镜像地址告诉 Kubernetes,K8s 拉取镜像并启动容器(Pod)。
- 运行期 :当用户请求量暴增,K8s 自动扩展出 10 个 Pod 副本。
- 观测期 :这些 Pod 上运行的
/metrics接口被 Prometheus 发现,实时抓取性能数据。 - 报警期 :当 10 个 Pod 中有 3 个崩溃了,Prometheus 检测到可用率下降,发送报警。
🎯 面试常见追问与"AI 版"加分回答
Q1:Docker 和虚拟机(VM)有什么区别?
- 答:Docker 共享宿主机内核(启动毫秒级,资源占用 MB 级);VM 模拟完整操作系统(启动分钟级,占用 GB 级)。
- AI 加分项:"在大模型训练场景中,我们坚决不用虚拟机,因为虚拟化层带来的 I/O 损耗对读取大规模权重文件影响非常大,Docker 几乎是零损耗。"
Q2:K8s 的 HPA 在 AI 场景下有什么局限?
- 答 :HPA 基于 CPU/内存扩容,但 LLM 服务往往受显存 和并发请求数 限制。我们可以部署 KEDA(基于事件驱动的弹性伸缩),根据队列深度(比如 RabbitMQ 的积压数)来提前扩容,而不是等 CPU 满了再扩,那时候已经超时了。
Q3:你用过 Prometheus 的哪些指标来优化智能体?
- 答 :我们通过
histogram类型指标,监控langgraph_node_duration_seconds。发现"向量检索节点"耗时占整个链路的 60%,从而促使我们将 Chroma 迁移到了性能更强的 Milvus,并启用了 GPU 加速的 IVF-PQ 索引。
💡 一句话总结(面试收尾金句)
Docker 是标准化"打包",K8s 是自动化"管理",Prometheus 是全天候"监控"。 这三者构成了现代 AI 应用从开发到上线再到运维的完整闭环。
Docker 面试题的核心逻辑是:"为什么需要 Docker(解决了什么问题)→ 怎么构建(Dockerfile 优化)→ 怎么运行(网络/存储/资源)→ 怎么保生产安全" 。结合你正在做 AI Agent + FastAPI + 云原生的背景,我为你整理了 8 道必考高频题,并附带了面试官期待的"加分细节" ,尤其是关于镜像瘦身 和 PID 1 信号处理这两点,非常容易让面试官眼前一亮。
1. Docker 镜像和容器的区别?(基础必问)
答题逻辑:类比 OOP 编程。
- 镜像(Image) :是一个只读的模板 ,包含了运行应用程序所需的所有代码、依赖库、环境变量和配置文件。相当于 "类(Class)"。
- 容器(Container) :是镜像的运行实例 。相当于 "对象(Object)",有生命周期(创建、启动、停止、删除)。
2. Dockerfile 中 RUN、CMD、ENTRYPOINT 的区别?(几乎 100% 问)
这是区分"背题党"和"实战派"的关键,特别注意 CMD 和 ENTRYPOINT 的组合使用。
| 指令 | 执行时机 | 核心特点 | 能否被 docker run 覆盖 |
|---|---|---|---|
RUN |
构建镜像时 (docker build) |
用于安装软件包(apt-get)、生成文件。 |
❌ 不能 |
CMD |
容器启动时 (docker run) |
提供默认 的执行命令(如 python app.py)。 |
✅ 能(docker run ... /bin/bash 会覆盖) |
ENTRYPOINT |
容器启动时 (docker run) |
将容器配置为可执行程序 。docker run 后面追加的参数会作为 ENTRYPOINT 的参数附加。 |
❌ 需加 --entrypoint 才能覆盖 |
面试加分金句(实战最佳实践):
"在生产环境中,我通常采用
ENTRYPOINT + CMD组合写法:
dockerfileENTRYPOINT ["python", "app.py"] CMD ["--port", "8000"]这样既能固定启动程序(避免运维误改入口),又能允许灵活传入启动参数(如
docker run ... --port 9000)。另外注意CMD必须是 JSON 数组格式(["exec"]) ,如果写成CMD python app.py(shell 格式),会导致应用收不到SIGTERM信号,docker stop会卡住 10 秒强制杀死。"
3. 什么是 Docker 镜像层(Layer)?如何利用缓存加速构建?
答题逻辑 :Dockerfile 每一条指令都会生成一个只读层(Layer) 。docker build 时会检查本地缓存,如果指令未变且上下文未变,则直接复用缓存。
黄金规则(必须提到):
"为了最大化利用缓存,我会把变化频率低的指令放前面,变化频率高的放后面。顺序应该是:
FROM(基础镜像)WORKDIRCOPY requirements.txt(先拷依赖清单)RUN pip install -r requirements.txt(这层会被缓存,只要依赖不改)COPY . .(最后拷源码,这是变化最频繁的)"
4. COPY 和 ADD 的区别?(容易记混)
| 指令 | 功能 | 推荐度 |
|---|---|---|
COPY |
仅将本地文件复制到镜像中。功能单一、行为透明。 | ✅ 强烈推荐(安全、可预测) |
ADD |
除了复制,还支持 自动解压 tar 压缩包 ,以及从 URL 下载文件。 | ❌ 不推荐(网络下载行为不可控,且无法断点续传) |
面试金句 :"如果只是复制文件,永远用 COPY。只有明确需要解压本地压缩包时,才考虑用 ADD。" |
5. 容器数据持久化:Volume(卷)和 Bind Mount(绑定挂载)的区别?
- Volume :由 Docker 管理,存储在宿主机
/var/lib/docker/volumes/。最推荐,适合生产环境存储数据库数据。 - Bind Mount :映射宿主机任意目录 (如
/home/user/code)。适合开发环境(代码热更新),但安全性较低。
面试加分(结合你的 AI 项目):
"在我们的 LangGraph 智能体项目中,我使用
Bind Mount把本地的./chroma_excel_db(向量库持久化目录)映射进容器,方便我在宿主机直接用 Python 脚本检查向量库状态。而对于 MySQL 或 Redis,我用Volume确保容器重启后数据不丢失。"
6. 容器网络模式:Bridge、Host、Overlay 的区别?
| 模式 | 原理 | 适用场景 |
|---|---|---|
| Bridge(桥接) | 默认模式。创建虚拟网桥,容器间通过 NAT 通信。 | 单机多容器(最常用)。 |
| Host(主机) | 容器共享宿主机网络栈,没有 IP 转换开销。 | 对网络性能要求极高的场景。 |
| Overlay(覆盖网络) | 跨多台物理机,让不同机器的容器处于同一子网。 | Kubernetes / Docker Swarm 集群通信。 |
7. 如何对 Docker 容器进行资源限制?(防止容器把宿主机搞崩)
"我会在
docker run时显式限制:
bashdocker run -d \ --memory="4g" \ # 硬限制 4GB,超了会被 OOM Killer 杀掉 --memory-swap="4g" \ # 禁用 swap(防止内存不够时用磁盘拖垮性能) --cpus="2.5" \ # 限制使用 2.5 个 CPU 核心 --restart=always \ # 异常退出时自动重启 my-agent:v1特别是在 GPU 场景,我会用
--gpus all配合NVIDIA_VISIBLE_DEVICES环境变量来限定特定显卡,防止多个容器争抢显存导致 OOM。"
8. 什么是 Docker 多阶段构建(Multi-stage Build)?(超级加分项)
- 痛点 :Go、Java 或 Python 编译/安装依赖时需要大量构建工具(如
gcc),导致最终镜像体积达到 1GB+。 - 解决方案 :在 Dockerfile 中声明多个
FROM阶段。前一阶段负责"编译/构建",后一阶段只负责"运行",仅复制最终产物。
dockerfile
# 阶段1:构建(大镜像)
FROM python:3.11 AS builder
COPY requirements.txt .
RUN pip install --user -r requirements.txt
# 阶段2:运行(小镜像)
FROM python:3.11-slim
COPY --from=builder /root/.local /root/.local
COPY ./app /app
CMD ["python", "/app/main.py"]
面试金句 :"我们将镜像从 1.2GB 缩减到了 120MB ,不仅节省了磁盘空间,更重要的是极大缩短了 CI/CD 推拉镜像的时间。"
9. Docker 容器中的 PID 1 问题与 tini 的作用(高能硬核考点!)
问题:
- 容器启动时,默认的第一个进程(PID 1)是你的 Python 进程。
- 在 Linux 中,PID 1 有特殊的职责:它必须负责回收孤儿进程(
wait()),并响应SIGTERM(docker stop发的信号)。 - 如果你的 Python 进程不处理
SIGTERM,docker stop会等待 10 秒 后强制SIGKILL杀进程,导致应用来不及优雅下线(比如正在写数据库、释放连接池)。
解决方案 :在 ENTRYPOINT 前加上 tini(或 dumb-init):
dockerfile
RUN apt-get update && apt-get install -y tini
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["python", "app.py"]
面试金句 :"在高并发生产环境中,优雅停机至关重要。我们强制在基础镜像中集成了 tini,确保容器能在 2 秒内完成流量摘除、连接池关闭和状态保存。"
💡 结合你背景的实战包装(面试开口跪)
如果面试官问:"你在 AI 项目里遇到过什么 Docker 难题?"
答:"我们遇到过大模型依赖包(
torch+transformers)体积过大,构建超时的问题。我们用了三招 解决:1)使用nvidia/cuda:12.1-runtime-ubuntu22.04作为基础镜像,而不是python:3.11,因为后者自带 Python 但不带 CUDA 运行时,装了 PyTorch 反而会重复下载 CUDA 库,导致镜像从 800MB 膨胀到 6GB。2)利用 Docker BuildKit 的--mount=type=cache缓存pip包,二次构建从 15 分钟缩短到 3 分钟。3)针对 LangGraph 这种频繁改动的代码,我们开启了docker build --target=build只重建变更层,CI 流水线速度提升了 70%。"