1.5 容器相关面试题

这三个工具是云原生和微服务时代的"铁三角",分别解决了**"怎么打包"、"怎么调度"、"怎么观测"**这三个核心问题。面试官通过这个问题,能快速判断你是否具备生产级系统的部署思维。

结合你之前的大模型(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 调整导致大面积报错。

3. Prometheus(普罗米修斯)------"监控与报警眼睛"

  • 它是干什么的 :它是一个指标采集时序数据库(TSDB)。它会定期(比如每 15 秒)去你的服务里拉取(Pull)指标,并存储下来。
  • 核心概念(高频考点)
    • Metrics(指标) :比如 http_requests_total(请求总数)、llm_token_usage(Token 消耗量)。
    • Pull 模型 :服务方需要暴露一个 /metrics 接口,Prometheus 主动来抓取,而不是服务方上报(Push)。
    • AlertManager:当指标异常时(如 Agent 的 500 错误率超过 10%),发送告警到钉钉、邮件或电话。
  • AI 场景中的应用(面试亮点)
    • 监控 GPU 显存 :如果你的 Agent 用了开源模型进行本地推理,Prometheus 结合 dcgm-exporter 可以监控 GPU 温度、显存占用率。
    • Token 消耗计费 :可以在 Agent 代码里暴露 token_consumed_total,用 Prometheus 统计每天花费了多少 API 费用。

🏗️ 它们是怎么协同工作的?(必答逻辑链)

面试时,你最好能画出这个"生命周期":

  1. 开发期:你写好了 Python 智能体代码。
  2. 构建期 :用 Docker 把代码 + 环境打包成一个镜像(docker build -t my-agent:v1)。
  3. 部署期 :把这个镜像地址告诉 Kubernetes,K8s 拉取镜像并启动容器(Pod)。
  4. 运行期 :当用户请求量暴增,K8s 自动扩展出 10 个 Pod 副本。
  5. 观测期 :这些 Pod 上运行的 /metrics 接口被 Prometheus 发现,实时抓取性能数据。
  6. 报警期 :当 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 中 RUNCMDENTRYPOINT 的区别?(几乎 100% 问)

这是区分"背题党"和"实战派"的关键,特别注意 CMDENTRYPOINT 的组合使用。

指令 执行时机 核心特点 能否被 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 组合写法:

dockerfile 复制代码
ENTRYPOINT ["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 时会检查本地缓存,如果指令未变且上下文未变,则直接复用缓存。

黄金规则(必须提到)

"为了最大化利用缓存,我会把变化频率低的指令放前面,变化频率高的放后面。顺序应该是:

  1. FROM(基础镜像)
  2. WORKDIR
  3. COPY requirements.txt(先拷依赖清单)
  4. RUN pip install -r requirements.txt(这层会被缓存,只要依赖不改)
  5. COPY . .(最后拷源码,这是变化最频繁的)"

4. COPYADD 的区别?(容易记混)

指令 功能 推荐度
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 时显式限制:

bash 复制代码
docker 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()),并响应 SIGTERMdocker stop 发的信号)。
  • 如果你的 Python 进程不处理 SIGTERMdocker 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%。"