Docker 面试题精选
生成时间:2026-06-06 21:12 | 共 10 题
1. 请详细描述 Docker 的整体架构,以及 Client、Daemon、Registry 三者之间的交互流程。
难度: ⭐⭐
标准答案:
Docker 采用 C/S(Client/Server)架构,核心组件包括:
- Docker Client:用户与 Docker 交互的入口(
docker命令行),负责接收用户指令并通过 REST API 发送给 Docker Daemon。Client 和 Daemon 可以不在同一台机器上,通过DOCKER_HOST环境变量指定远程 Daemon 地址。 - Docker Daemon(dockerd):Docker 的核心后台进程,负责接收 Client 请求,管理镜像、容器、网络和数据卷等 Docker 对象。Daemon 监听 Unix socket(
/var/run/docker.sock)或 TCP 端口。 - Docker Registry:存储和分发 Docker 镜像的仓库服务。Docker Hub 是默认的公共 Registry,企业可搭建私有 Registry。
交互流程示例(docker pull nginx):
- Client 解析命令,向 Daemon 发送
POST /images/create?fromImage=nginx请求 - Daemon 查找本地是否已有该镜像,若无则向 Registry 发起 HTTPS 请求拉取
- Registry 返回镜像 manifest,Daemon 逐层下载 layer 并存储到本地存储驱动
- 下载完成后 Daemon 向 Client 返回结果
延伸思考: Docker Daemon 暴露 TCP 端口时有哪些安全风险?如何通过 TLS 双向认证保护 Daemon 通信?
2. Dockerfile 中 COPY 和 ADD 指令有什么区别?在镜像构建中应该优先使用哪个?
难度: ⭐
标准答案:
| 特性 | COPY | ADD |
|---|---|---|
| 基本复制 | ✅ | ✅ |
| 从 URL 复制 | ❌ | ✅ |
| 自动解压 tar 归档 | ❌ | ✅ |
多阶段构建中 --from | ✅ | ✅ |
最佳实践:优先使用 COPY。 原因:
COPY语义明确,只做文件复制,行为可预测ADD的自动解压功能可能导致意外行为(如将压缩包作为文件复制而非解压到目标目录)ADD从 URL 下载文件不可靠且不会自动缓存,应使用RUN curl替代以获得更好的缓存控制- Docker 官方 Dockerfile 最佳实践文档明确推荐优先使用
COPY
延伸思考: 如何利用 COPY --link 优化构建缓存?在什么场景下 ADD 的自动解压反而有用?
3. 什么是多阶段构建(Multi-stage Build)?它解决了什么问题?请给出一个实际示例。
难度: ⭐⭐
标准答案:
多阶段构建允许在一个 Dockerfile 中使用多个 FROM 指令,每个 FROM 开始一个新阶段,可以选择性地从前一阶段复制构建产物,最终镜像只包含最后一个阶段的内容。
解决的问题:
- 构建环境依赖(编译器、SDK)不需要进入运行时镜像
- 显著减小最终镜像体积(通常从 GB 级降到 MB 级)
- 减少攻击面,提升安全性
- 替代了之前"一个 Dockerfile 构建 + 一个 Dockerfile 运行"的双 Dockerfile 模式
示例 — Go 应用:
# 阶段1:构建
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .
# 阶段2:运行
FROM alpine:3.19
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/myapp /usr/local/bin/myapp
ENTRYPOINT ["myapp"]最终镜像仅包含 Alpine + 二进制文件,约 10-20MB,而非完整的 Go 构建环境(>1GB)。
延伸思考: 多阶段构建中如何使用 --target 指定构建到某一阶段?在 CI/CD 中如何利用这一特性同时产出测试镜像和发布镜像?
4. 请对比 Docker 的三种主要网络模式(bridge、host、overlay),并说明各自的适用场景。
难度: ⭐⭐
标准答案:
| 网络模式 | 原理 | 性能 | 隔离性 | 适用场景 |
|---|---|---|---|---|
| bridge | 默认模式。容器通过虚拟网桥(docker0)连接,每个容器分配独立 IP,通过 NAT 访问外部 | 中等(NAT 开销) | 高 | 单机容器通信,开发测试环境 |
| host | 容器直接使用宿主机网络栈,不创建独立网络命名空间 | 最高(无虚拟化开销) | 低 | 需要极致网络性能的场景,如网络监控、高性能服务 |
| overlay | 跨主机容器网络,基于 VXLAN 隧道实现,需配合 Swarm 或独立 etcd/Consul | 较低(封装开销) | 高 | 多主机集群通信,Swarm/Kubernetes 跨节点 Pod 通信 |
关键细节:
- bridge 模式下容器间通过
--link(已废弃)或自定义 bridge 网络通信 - host 模式下端口冲突是常见问题,多个容器不能绑定同一端口
- overlay 网络需要键值存储(Swarm 模式内置)来管理网络发现和加密
- Docker 还提供
none(无网络)和macvlan(容器拥有独立 MAC 地址)模式
延伸思考: 在 Kubernetes 中为什么不直接使用 Docker 的 overlay 网络?macvlan 网络模式有什么特殊用途和限制?
5. Docker 数据卷(Volume)和绑定挂载(Bind Mount)有什么区别?在生产环境中应如何选择?
难度: ⭐⭐
标准答案:
| 特性 | Volume(数据卷) | Bind Mount(绑定挂载) |
|---|---|---|
| 存储位置 | Docker 管理的区域(/var/lib/docker/volumes/) | 宿主机任意路径 |
| 创建方式 | docker volume create 或 -v name:/path | -v /host/path:/container/path |
| 生命周期 | 独立于容器,需显式删除 | 依赖宿主机目录 |
| 可移植性 | 高,不依赖宿主机目录结构 | 低,依赖宿主机特定路径 |
| 性能 | Linux 接近原生;Mac/Win 有 I/O 开销 | 同左 |
| 备份迁移 | docker run --rm -v vol:/src -v $(pwd):/dst alpine cp -a /src/. /dst/ | 直接备份宿主机目录 |
| 权限控制 | Docker 自动管理 | 可能遇到权限不匹配问题 |
生产环境建议:
- 数据库持久化数据 → 使用 Volume(管理方便、可命名、可备份)
- 开发环境代码热更新 → 使用 Bind Mount(实时同步宿主机文件变化)
- 配置文件注入 → 使用 Bind Mount 或
docker config(Swarm) - 敏感信息 → 使用
docker secret(Swarm)或环境变量
延伸思考: Docker Volume 在 Mac 和 Windows 上的 I/O 性能问题如何解决?tmpfs 挂载适合什么场景?
6. 请编写一个 docker-compose.yml 实现一个 LNMP(Linux + Nginx + MySQL + PHP)架构,并说明关键配置项的作用。
难度: ⭐⭐
标准答案:
version: "3.8"
services:
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d:ro # Nginx 配置
- ./www:/usr/share/nginx/html:ro # 网站根目录
- nginx-logs:/var/log/nginx # 日志持久化
depends_on:
- php
networks:
- frontend
- backend
restart: unless-stopped
php:
image: php:8.3-fpm-alpine
volumes:
- ./www:/usr/share/nginx/html:ro # 与 Nginx 共享代码
networks:
- backend
restart: unless-stopped
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} # 从 .env 读取
MYSQL_DATABASE: app_db
MYSQL_USER: app_user
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- mysql-data:/var/lib/mysql # 数据持久化
- ./mysql/init:/docker-entrypoint-initdb.d # 初始化脚本
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
volumes:
mysql-data:
nginx-logs:
networks:
frontend:
backend:
internal: true # 内部网络,不暴露到宿主机关键配置说明:
depends_on:控制启动顺序,但不等待服务就绪(需配合healthcheck)internal: true:backend 网络外部不可访问,提升安全性:ro只读挂载防止容器内进程修改配置文件docker-entrypoint-initdb.d:MySQL 首次启动时自动执行初始化 SQL.env文件管理敏感配置,避免硬编码密码
延伸思考: 如何使用 docker compose watch 实现开发环境热更新?depends_on 的 condition: service_healthy 与 service_started 有何区别?
7. 容器安全的最佳实践有哪些?如何实现容器运行时的安全加固?
难度: ⭐⭐⭐
标准答案:
容器安全应从镜像安全、运行时安全、编排安全三个层面考虑:
镜像安全:
- 使用最小基础镜像(
distroless、alpine、scratch) - 不以 root 用户运行:
RUN adduser -D appuser && USER appuser - 使用
docker scan/ Trivy / Snyk 扫描镜像漏洞 - 固定镜像版本标签(
nginx:1.25.3而非nginx:latest) - 使用
COPY --chown确保文件权限正确
运行时安全:
- 只读文件系统:
docker run --read-only --tmpfs /tmp - 限制资源:
--memory=512m --cpus=1.0 - 禁用特权:避免
--privileged,使用--cap-drop=ALL --cap-add=NET_BIND_SERVICE - 安全选项:
--security-opt=no-new-privileges:true - 只读挂载
/proc和/sys,或使用maskedPaths - 使用 Seccomp / AppArmor / SELinux 策略限制系统调用
编排安全:
- 使用 Docker Secrets 管理敏感信息,不使用环境变量
- 网络隔离:内部网络不暴露端口
- 启用 Docker Content Trust(
DOCKER_CONTENT_TRUST=1) - 定轮换镜像签名密钥
延伸思考: --privileged 容器与宿主机有什么区别?为什么在 Kubernetes 中 Pod Security Standards 推荐使用 restricted 策略?
8. 如何对 Docker 容器进行性能调优?请从 CPU、内存、磁盘 I/O、网络四个维度说明。
难度: ⭐⭐⭐
标准答案:
CPU 调优:
--cpus=2.0:限制容器最多使用 2 个 CPU 核心--cpuset-cpus=0,2:绑定容器到指定 CPU 核心,减少上下文切换--cpu-shares=512:设置 CPU 时间片权重(相对值,非绝对限制)- CFS 调度器参数:
--cpu-period和--cpu-quota精确控制 CPU 带宽
内存调优:
--memory=2g --memory-swap=2g:限制内存使用(swap=memory 表示禁用 swap)--memory-reservation=1g:软限制,内存紧张时才生效--oom-kill-disable=true(仅与--memory一起使用):禁止 OOM Killer 终止容器--kernel-memory:限制内核内存(已废弃,Linux 5.x+ 不推荐)
磁盘 I/O 调优:
--device-write-bps /dev/sda:10mb:限制块设备写带宽--device-write-iops /dev/sda:100:限制 IOPS- 使用 Volume 而非 Bind Mount 减少 I/O 开销(Mac/Windows)
- 存储驱动选择:
overlay2(推荐)vsdevicemapper(已弃用) - 日志限制:
--log-opt max-size=10m --log-opt max-file=3
网络调优:
- 高性能场景使用
--network host避免 NAT 开销 - 调整内核网络参数:
net.core.somaxconn、net.ipv4.tcp_tw_reuse - 使用
--dns指定 DNS 减少解析延迟 - Mac/Windows:
docker-desktop的 VM 网络是瓶颈,生产环境用 Linux
延伸思考: 如何使用 docker stats 和 cgroups 监控容器资源使用?在 Kubernetes 中 Resource Requests 和 Limits 与 Docker 资源限制是什么关系?
9. 如何将一个 1.2GB 的应用镜像瘦身到 200MB 以内?请列出至少 5 种具体方法。
难度: ⭐⭐⭐
标准答案:
方法一:多阶段构建(最有效) 将编译环境和运行环境分离,只复制最终二进制到精简基础镜像。Go/C++ 等编译型语言可瘦身 80%+。
方法二:使用更小的基础镜像
node:20(1.1GB) →node:20-alpine(180MB) →node:20-slim(250MB)- Python:
python:3.12→python:3.12-slim→python:3.12-alpine - 终极方案:
distroless或scratch(无 shell、无包管理器)
方法三:合并 RUN 指令减少层数
# 优化前(3 层)
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*
# 优化后(1 层)
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*方法四:利用 BuildKit 缓存挂载
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt缓存不进入镜像层,减少层体积。
方法五:.dockerignore 排除无关文件
.git
node_modules
__pycache__
*.pyc
.env
tests/
docs/方法六:压缩镜像层docker save | docker load 或 docker export | docker import 合并为单层(牺牲构建缓存能力)。
方法七:使用 docker slim 工具 自动分析容器运行时依赖,裁剪未使用的文件,可瘦身 30-70%。
延伸思考: distroless 镜像无法进入 shell,如何进行调试?镜像瘦身和可调试性之间如何权衡?
10. 如何搭建企业级 Docker 私有仓库?请描述基于 Harbor 的完整方案,包括高可用和 CI/CD 集成。
难度: ⭐⭐⭐
标准答案:
Harbor 架构方案:
Harbor 是 CNCF 毕业项目,提供企业级 Registry 功能:RBAC、镜像扫描、镜像签名、镜像复制、审计日志等。
部署方案(高可用):
# docker-compose-harbor.yml 核心组件
services:
harbor-core: # API 和 Web UI
harbor-registry: # 镜像存储(基于 Distribution)
harbor-db: # PostgreSQL(外部 HA 集群)
harbor-redis: # Redis 会话管理(外部 Sentinel 集群)
harbor-portal: # 前端
trivy: # 镜像漏洞扫描
notary: # 镜像签名(Docker Content Trust)高可用设计:
- 存储层:使用 S3/OSS 对象存储作为 Registry 后端,天然支持多节点访问
- 数据库:PostgreSQL 使用主从复制或云 RDS
- Redis:使用 Redis Sentinel 或集群模式
- Harbor Core:多副本部署 + Nginx 负载均衡
- 镜像复制:跨数据中心配置 Harbor Replication Policy
CI/CD 集成(GitLab CI 示例):
# .gitlab-ci.yml
build-and-push:
stage: build
image: docker:24
services:
- docker:24-dind
before_script:
- echo "$HARBOR_PASSWORD" | docker login harbor.company.com -u "$HARBOR_USER" --password-stdin
script:
- docker build -t harbor.company.com/project/app:${CI_COMMIT_SHORT_SHA} .
- docker push harbor.company.com/project/app:${CI_COMMIT_SHORT_SHA}
- docker tag harbor.company.com/project/app:${CI_COMMIT_SHORT_SHA} harbor.company.com/project/app:latest
- docker push harbor.company.com/project/app:latest
after_script:
- docker logout harbor.company.com安全加固:
- 启用 HTTPS(Let's Encrypt 或企业 CA)
- 配置 RBAC:项目级读写权限控制
- 强制镜像扫描策略:只允许通过扫描的镜像部署
- 启用 Docker Content Trust + Notary 镜像签名
- 配置 Webhook 对接安全审计平台
延伸思考: Harbor 的镜像代理缓存(Proxy Cache)功能如何加速公共镜像拉取?在空气隔离环境中如何实现镜像的离线分发?
💡 学习建议: 每道题的"延伸思考"都是面试中的追问方向,建议深入准备。Docker 面试通常从基础概念逐步深入到生产实践,掌握从"是什么"到"为什么"到"怎么优化"的完整链条是关键。