)
第17章Docker 大厂面试题精选腾讯/阿里/字节/美团本文档按真实面试流程组织从浅到深、从基础到场景模拟面试官的提问方式和追问逻辑。每道题给出面试官想听到的回答和踩坑点而非教科书式的标准答案。第一轮基础摸底5-10 分钟面试官目的确认你不是背八股文而是真的用过 Docker。Q1你平时用 Docker 做什么说说你项目里 Docker 的使用场景❌ 背书式回答“Docker 是一个开源的应用容器引擎基于 Go 语言开发实现了容器级别的虚拟化…”✅ 面试官想听的我之前在 XX 项目里主要用 Docker 做了三件事统一开发环境——团队成员本地环境不一致有的 Mac 有的 Ubuntu用 docker-compose 一键拉起 MySQL Redis 应用新人入职半天就能跑起来CI/CD 流水线——代码提交后 Jenkins 自动 build 镜像 → 跑测试 → 推到 Harbor 仓库 → 部署到测试环境线上部署——生产环境用 K8s 管理容器每个微服务一个镜像支持滚动更新和自动扩缩容考察点真正用过的人一定会提到具体场景和痛点而不是复述定义。Q2容器和虚拟机到底有什么区别你项目里怎么选的❌ 背书式回答“虚拟机通过 Hypervisor 虚拟化硬件容器共享宿主机内核…”✅ 面试官想听的核心区别就一句话虚拟机是模拟一台完整的电脑容器是隔离一个进程。举个实际例子我们之前有一台 4 核 8G 的服务器跑虚拟机最多开 3-4 个每个 VM 要分配 2G 内存 1 个虚拟内核换成 Docker 后同样配置能跑 15-20 个容器因为容器不需要独立的 OS 内核。选型上需要跑不同操作系统比如同时跑 Windows 和 Linux 服务用虚拟机同一个 Linux 环境下跑微服务用 Docker省资源、启动快。但 Docker 的隔离性确实不如虚拟机如果安全性要求极高比如多租户隔离可能还是需要虚拟机或者 gVisor 这种安全容器。考察点能否结合实际资源数据说明差异理解各自的适用边界。Q3Docker 镜像为什么要分层有什么好处❌ 背书式回答“镜像采用分层存储每条 Dockerfile 指令生成一个只读层使用 Copy-on-Write 机制…”✅ 面试官想听的分层最大的好处是共享和缓存。举个例子我们团队有 20 个 Python 微服务它们的基础镜像都是python:3.11-slim。如果用分层存储这 20 个镜像共享同一个基础层本地磁盘只存一份。docker pull的时候基础层也只下载一次后续只拉各服务自己的代码层。构建的时候也一样我写 Dockerfile 时会把变化少的比如pip install依赖放前面变化多的比如COPY . .放后面。这样改一行代码重新 build 时前面的依赖层直接命中缓存构建时间从 5 分钟缩短到 30 秒。本质上就是增量存储 增量传输 增量构建。考察点能否结合具体数据说明分层的实际价值。第二轮命令与实操10-15 分钟面试官目的考察动手能力你是不是真写过 Dockerfile、排过线上问题。Q4写一个生产级的 Dockerfile要求镜像尽量小、安全、能健康检查面试官期待看到的写法# 阶段1构建 FROM python:3.11-slim AS builder WORKDIR /app # 先复制依赖文件利用缓存 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . # 阶段2运行 FROM python:3.11-slim RUN groupadd -r appuser useradd -r -g appuser appuser WORKDIR /app # 从 builder 复制已安装的依赖 COPY --frombuilder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages COPY --frombuilder /app /app # 非 root 用户运行 USER appuser EXPOSE 5000 # 健康检查 HEALTHCHECK --interval30s --timeout5s --retries3 \ CMD curl -f http://localhost:5000/health || exit 1 CMD [python3, app.py]面试官会追问Q4-1为什么用python:3.11-slim而不是python:3.11“slim 版本去掉了编译器、man 手册等非必要包镜像从约 900MB 缩到 150MB。线上不需要 gcc 这些东西只有编译某些 C 扩展时才需要所以构建阶段用完整版运行阶段用 slim。”Q4-2为什么先 COPY requirements.txt 再 COPY 代码“Docker 构建缓存是按层判断的。如果先 COPY 全部代码再 pip install改一行代码就会导致整个 pip install 重新执行。先复制 requirements.txt只要依赖文件没变pip install 那层就一直命中缓存。”Q4-3ENTRYPOINT 和 CMD 你一般怎么选简单服务直接用 CMD比如CMD [python3, app.py]。如果需要固定程序但参数可变用 ENTRYPOINT CMD 组合比如ENTRYPOINT [python3] CMD [app.py]docker run myapp→ 执行python3 app.pydocker run myapp test.py→ 执行python3 test.py需要写 entrypoint 脚本做初始化比如等数据库就绪、初始化配置时用 ENTRYPOINT 指向脚本。Q5docker compose up之后服务起不来你怎么排查✅ 面试官想听的排查思路我会按这个顺序来第一步看日志dockercompose logs服务名# 或者只看最近的dockercompose logs--tail50服务名第二步看容器状态dockercomposeps# 重点看 STATUS 列Up 还是 Exit (code)# Exit 0 正常退出可能是 CMD 问题# Exit 1 应用错误# Exit 137 OOM Killed# Exit 139 段错误第三步进容器排查dockercomposeexec服务名/bin/bash# 检查环境变量、配置文件、网络连通性curlhttp://mysql:3306# 测试依赖服务是否可达第四步检查资源dockerstats# 看 CPU、内存是否打满常见原因depends_on 顺序问题——应用起来了但 MySQL 还没 ready代码里没做重试端口冲突——宿主机某端口被占用环境变量没传——.env文件缺失或变量名写错网络问题——容器间 DNS 解析失败特别是用了默认 bridgeQ6容器退出码 137 和 139 分别是什么怎么处理✅ 实际回答137 128 9 SIGKILL通常是OOM Killed——内存超限被内核杀掉了。排查方法# 1. 确认退出码dockerinspect容器--format{{.State.ExitCode}}# 2. 查 dmesg 看内核日志dmesg|grep-ioom\|killed# 会看到类似Out of memory: Killed process 12345 (python3)# 3. 临时方案调高内存限制dockerrun-d--memory2g myapp# 根本方案用 profiling 工具找内存泄漏139 128 11 SIGSEGV段错误通常是应用本身的 bug空指针、数组越界需要看核心转储文件定位代码问题。还有常见退出码0正常退出1应用错误126权限问题127命令找不到CMD 路径写错了Q7线上容器日志撑爆了磁盘怎么办✅ 实际回答这个问题我处理过。当时某服务循环打日志几天就把宿主机磁盘写满了连 SSH 都登不上。临时处理# 1. 清空指定容器的日志不删除容器truncate-s0/var/lib/docker/containers/容器ID/容器ID-json.log# 或者直接杀掉日志文件的 fd# 找到容器的容器 IDCONTAINER_ID$(dockerinspect--format{{.Id}}容器名)cat/dev/null/var/lib/docker/containers/$CONTAINER_ID/${CONTAINER_ID}-json.log根治方案Docker daemon 全局配置日志轮转/etc/docker/daemon.json{log-driver:json-file,log-opts:{max-size:100m,max-file:3}}应用层——不要疯狂打日志设置合理日志级别接入日志收集ELK/Loki日志打到 stdout 后被收集走不用长期存本地第三轮网络与原理15-20 分钟面试官目的考察你对 Docker 底层的理解深度。Q8Docker 默认的 bridge 网络和自定义 bridge 网络有什么区别为什么生产一定要用自定义的✅ 实际回答最大的区别是DNS 解析。默认 bridge 网络里容器之间只能用 IP 互相访问不能用容器名。比如你启动了一个 MySQL 容器叫db另一个容器里配DB_HOSTdb是解析不了的必须写DB_HOST172.17.0.xIP 一变就挂了。自定义 bridge 网络自带 DNS 服务127.0.0.11容器名自动解析为 IP所以DB_HOSTdb直接就能用。还有一个问题是隔离性。默认 bridge 网络里所有容器都在同一个网络互相都能访问。自定义网络可以做网络分组比如把前端服务放frontend网络后端服务放backend网络数据库只在backend里外部访问不到。# 正确做法dockernetwork create frontenddockernetwork create backenddockerrun-d--namenginx--networkfrontend nginxdockerrun-d--nameapp--networkbackend myappdockerrun-d--namedb--networkbackend mysql# nginx 连到 backend 访问 app但 db 无法从外部直接访问Q9容器之间怎么通信的底层原理是什么✅ 实际回答以最常见的 bridge 模式为例容器A ←→ veth pair ←→ docker0 网桥 ←→ veth pair ←→ 容器B1. 每个容器有自己的 Network Namespace独立的网络栈、IP、路由表 2. Docker 为每对容器创建 veth pair虚拟网卡对一端在容器里一端在 docker0 网桥上 3. 容器间通信本质上是通过 docker0 网桥转发跟局域网交换机一个道理 4. 出站流量通过 iptables 的 SNAT/MASQUERADE 规则做地址转换 5. 端口映射-p 8080:80通过 iptables DNAT 实现验证方法# 在宿主机上看 veth pairiplinkshow|grepveth# 看 iptables 规则iptables-tnat-L-n|grepDNAT# 输出DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80Q10端口映射-p 8080:80底层发生了什么✅ 实际回答Docker 帮你在宿主机的 iptables 里加了一条 DNAT 规则当有人访问宿主机IP:8080时iptables 自动把目标地址改成172.17.0.2:80容器 IP然后转发到容器。# 验证iptables-tnat-L-n|grep8080# DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80所以如果宿主机的防火墙或安全组没开放 8080 端口即使 Docker 做了映射外部也访问不了。我之前踩过这个坑——Docker 配置没问题但云服务器安全组没放行端口。第四轮安全与生产15-20 分钟面试官目的考察生产环境实战经验和安全意识。Q11你们生产环境 Docker 容器有哪些安全加固措施✅ 实际回答挑几个说不要背清单我们主要做了这几件事1. 不用 root 跑容器RUN groupadd -r appuser useradd -r -g appuser appuser USER appuser因为容器里 root 和宿主机 root 是同一个 UID如果容器被攻破攻击者可能拿到宿主机 root 权限。2. 最小权限原则dockerrun --cap-drop ALL --cap-add NET_BIND_SERVICE nginx先 drop 所有 capabilities只加需要的。大部分容器只需要绑定低端口的能力。3. 限制资源防止被薅dockerrun--cpus2--memory1g--pids-limit100myapp不限制的话一个容器内存泄漏能拖垮整台机器。pids-limit 防 fork bomb。4. 密钥不进镜像密码、API Key 这些通过环境变量注入或者用 Docker Secrets绝对不写在 Dockerfile 或代码里。5. 镜像扫描CI 流水线里接了 TrivyHIGH/CRITICAL 漏洞直接阻断构建。Q12Docker Secrets 是什么和环境变量有什么区别✅ 实际回答环境变量有个问题docker inspect能直接看到而且镜像构建历史里可能泄露。Docker Secrets 是 Swarm 模式下的功能密钥存在内存里/run/secrets/不会持久化到镜像层也不会被docker inspect暴露。services:db:environment:MYSQL_PASSWORD_FILE:/run/secrets/db_passwordsecrets:-db_passwordsecrets:db_password:file:./secrets/db_password.txt如果不用 Swarm生产中一般用 HashiCorp Vault 或者云厂商的密钥管理服务比如阿里云 KMS。Q13你们的 Docker 镜像仓库是怎么管理的Harbor 用过吗✅ 实际回答我们用的是 Harbor开源的企业级镜像仓库部署在内网。主要解决了几个问题镜像分发速度——Docker Hub 在国内太慢了Harbor 部署在内网push/pull 都是内网带宽权限控制——不同项目组只能 push 自己 namespace 下的镜像漏洞扫描——Harbor 集成了 Trivy镜像 push 上去自动扫描镜像签名——开启了 Content Trust只允许拉取签名过的镜像垃圾回收——定期清理没被引用的镜像层释放磁盘空间# 配置 Docker 客户端信任 Harbor# /etc/docker/daemon.json{insecure-registries:[harbor.internal.com:443],registry-mirrors:[https://harbor.internal.com]}第五轮故障排查与场景题15-20 分钟面试官目的考察真实故障处理能力和工程思维。Q14线上容器突然访问不了了你怎么排查✅ 面试官想听的排查路径我按这个顺序来从外到内1. 确认容器是否在运行dockerps|grep容器名# 如果不在docker compose ps 看状态和退出码2. 看日志dockerlogs--tail100容器名# 看有没有报错、OOM、启动失败3. 进容器测网络dockerexec-it容器名ping目标地址dockerexec-it容器名curl-vhttp://localhost:端口dockerexec-it容器名cat/etc/resolv.conf# 确认 DNS 配置是否正确4. 检查端口映射和 iptablesdockerport容器名# 确认映射是否正确iptables-tnat-L-n|grep容器IP# 确认 DNAT 规则是否存在5. 检查防火墙/安全组如果是云服务器还要去控制台看安全组规则是否放行了对应端口。6. 检查宿主机资源df-h# 磁盘满了free-m# 内存不够dockerstats# CPU 打满了7. 依赖服务检查比如 app 连不上 mysql可能是 mysql 容器挂了或者网络不通。Q15你的应用需要连接 MySQLdocker-compose.yml 里怎么配置才能确保 MySQL 先起来✅ 实际回答很多人以为depends_on就够了其实depends_on只等容器启动不等服务就绪。MySQL 容器起来了不代表 3306 端口能连。方案一depends_on healthcheck推荐services:mysql:image:mysql:8.0healthcheck:test:[CMD,mysqladmin,ping,-h,localhost]interval:10stimeout:5sretries:5app:depends_on:mysql:condition:service_healthy# 等 healthcheck 通过方案二应用层做重试不管编排层怎么配应用代码里都应该有数据库连接重试逻辑因为线上 MySQL 可能随时重启。importtimeforiinrange(10):try:dbconnect(db_url)breakexcept:time.sleep(3)生产环境一定要两种都做因为 healthcheck 也可能误判。Q16你们怎么做的灰度发布用 Docker 的话怎么做✅ 实际回答我们之前没上 K8s 的时候用 Docker Compose Nginx 做过金丝雀发布思路services:app-stable:image:myapp:v1.0deploy:replicas:9# 90% 流量app-canary:image:myapp:v2.0deploy:replicas:1# 10% 流量nginx:image:nginx:alpineports:-80:80volumes:-./nginx.conf:/etc/nginx/nginx.conf:roNginx 配置 upstream 里两个后端权重按副本数分配。步骤先部署 v2.0 1 个副本观察 10 分钟看监控指标错误率、延迟、CPU没问题就逐步增加 v2.0 副本数减少 v1.0全量切完后停掉 v1.0有问题立刻回滚——把 v1.0 副本加回来v2.0 停掉现在上了 K8s用 Deployment 的maxSurge和maxUnavailable参数做滚动更新更方便。第六轮深入追问10-15 分钟面试官目的看你的技术深度和思考能力。Q17Docker 的 Cgroups 具体是怎么限制 CPU 和内存的✅ 实际回答别背定义结合现象说CPU 限制的本质是时间片分配。比如--cpus2对应 Cgroups 里的cpu.max 200000 100000每 100ms 周期内可以用 200ms 的 CPU 时间等于 2 核。如果一个容器配了--cpus0.5它每 100ms 只能用 50ms CPU剩下的时间让给别的容器。内存限制更直接--memory1g对应memory.max 1073741824。一旦使用量超过这个值内核直接 SIGKILL 进程这就是 137 退出码的来源。我踩过的坑设--memory1g但没设--memory-swapDocker 默认 swap 是 memory 的 2 倍所以容器实际能用 3G 内存。如果要完全禁用 swap需要设--memory-swap1g和 memory 一样。Q18overlay2 存储驱动的工作原理是什么✅ 实实际回答overlay2 把镜像的只读层和容器的可写层合并成一个统一视图lowerdir只读层可以多个 ↓ upperdir可写层容器的修改在这里 ↓ merged联合挂载点容器看到的完整文件系统 ↓ workdirOverlayFS 内部使用读取文件先查 upperdir没有再查 lowerdir从上往下找修改文件从 lowerdir 复制到 upperdirCopy-on-Write在 upperdir 改删除文件在 upperdir 创建whiteout文件标记已删除查看实际存储dockerinspect容器--format{{.GraphDriver.Data}}# 会看到 MergedDir、UpperDir、LowerDir、WorkDir 四个路径 ---### Q19容器里的进程 PID 是 1和宿主机的 PID 1 有什么关系**✅ 实际回答** 没有关系。每个容器有独立的 PID Namespace。 - 容器内 PID1你的应用主进程比如 nginx master process - 宿主机上看到的 PID 是一个完全不同的数字比如12345bash# 宿主机上看psaux|grepnginx# root 12345 nginx: master process nginx -g daemon off;# 容器内看dockerexec容器psaux# PID 1 nginx: master process nginx -g daemon off;这就是 Namespace 隔离的效果——容器以为自己是 PID 1系统的第一个进程但实际上只是宿主机上的一个普通进程。坑点这就是为什么 Dockerfile 里 CMD 要用 exec 格式CMD [nginx]而不是 shell 格式CMD nginx。shell 格式会在 nginx 前面套一层 sh导致 sh 是 PID 1nginx 是 PID 2nginx 收不到 SIGTERM 信号容器 stop 的时候只能等到超时被 SIGKILL。Q20你有没有遇到过 Docker 相关的线上事故怎么处理的这道题没有标准答案面试官考察的是真实经历和反思能力。参考回答框架STAR 法则Situation背景某天早上监控告警线上某服务大量 502。Task问题排查发现 3 个应用容器全部 OOM Killed 了。Action处理先临时重启容器恢复服务docker compose restart app查 dmesg 确认是 OOM看容器内存配置只有 512MB拉取 profiling 数据发现是某个接口有内存泄漏——每次请求创建大量临时对象没释放临时调高内存限制到 1G加了内存监控告警跟开发一起修复了内存泄漏代码Result结果内存泄漏代码修复后发布稳定运行制定了规范所有容器必须设置内存限制 内存告警CI 里加了 profiling 步骤内存增长超阈值阻断构建附加题系统设计高级/架构岗Q21从零搭建一套 Docker 容器化基础设施你会怎么做考察系统设计能力不需要面面俱到挑重点说。回答框架镜像管理Harbor 私有仓库 Trivy 漏洞扫描 镜像签名编排平台Kubernetes10 容器以上小规模用 Docker Swarm 也行CI/CDGitLab CI Harbor流水线lint → build → scan → push → deploy监控Prometheus 采集容器指标CPU/内存/网络/磁盘Grafana 做可视化看板AlertManager 接企业微信/钉钉告警cAdvisor 或 node-exporter 采集宿主机指标日志容器日志输出到 stdoutPromtail 收集 → Loki 存储 → Grafana 查询比 ELK 轻量资源占用少链路追踪Jaeger 或 SkyWalking安全非 root 运行 只读文件系统 最小 capabilities网络策略隔离K8s NetworkPolicy密钥管理用 Vault高可用K8s 多 master etcd 集群应用多副本 PodAntiAffinity 分散到不同节点PDBPod Disruption Budget保证升级时至少可用副本数Q22你们的微服务部署架构是什么样的考察架构全局视野。回答要点我们是典型的三层架构接入层SLB云负载均衡→ Nginx Ingress → 网关鉴权、限流、路由服务层每个微服务一个 Deployment3 副本起Deployment Service Ingress。服务间调用用 gRPC 服务发现K8s Service 自带 DNS 解析。数据层MySQL 主从用 Operator 管理、Redis Cluster、ES 三节点集群。关键配置所有 Deployment 配resources.limits防止一个服务把节点资源吃光所有 Deployment 配readinessProbe没准备好不接流量所有 Deployment 配livenessProbe挂了自动重启配 PDB 保证滚动更新时可用副本数面试技巧总结回答原则原则说明别背定义说我用过…比Docker 是…好 100 倍带数据镜像从 1.2G 优化到 150M比优化了镜像大小有说服力说踩坑我之前遇到过…比理论上应该…更真实承认边界这个我没用过但我理解原理是…比硬编好追问深挖面试官追问时主动解释 why不要只说 what不同级别侧重点级别重点初级1-3 年Docker 基础命令、Dockerfile 编写、简单 Compose 编排中级3-5 年网络/存储原理、安全加固、CI/CD 集成、故障排查高级5 年架构设计、性能调优、生产事故处理、基础设施规划建议面试前对着每道题口述一遍计时 2 分钟。能流畅说出就过关卡壳的地方就是薄弱环节。