Skip to content

Docker 面试题精选 10 道 ​

生成时间:2026-06-06 21:38 | 难度范围:⭐ ~ ⭐⭐⭐


1. 请描述 Docker 的整体架构,以及 Client、Daemon、Registry 三者的协作关系 ​

难度: ⭐

标准答案:

Docker 采用 C/S 架构,核心由三部分组成:

  • Docker Client:用户与 Docker 交互的入口(docker 命令行、Docker Desktop GUI 等),负责发送请求到 Daemon。
  • Docker Daemon(dockerd):后台守护进程,监听 Docker API 请求,负责镜像构建、容器生命周期管理、网络和存储等核心操作。Client 与 Daemon 可以在同一主机,也可通过 TCP/Unix Socket 远程通信。
  • Docker Registry:镜像仓库,存储和分发 Docker 镜像。Docker Hub 是默认公共仓库,企业可搭建私有 Registry(Harbor、自建 registry 容器等)。

协作流程:Client 发送 docker pull nginx → Daemon 接收请求 → Daemon 从 Registry 拉取镜像层 → 存储到本地 /var/lib/docker → Client 收到成功响应。

延伸思考: 当 Daemon 与 Client 分离部署时,如何保证通信安全?(提示:TLS 双向认证、配置 DOCKER_HOST 与 DOCKER_TLS_VERIFY)


2. 编写 Dockerfile 时有哪些最佳实践?请至少列举 5 条 ​

难度: ⭐⭐

标准答案:

  1. 使用多阶段构建:编译阶段与运行阶段分离,最终镜像只包含运行时必要文件,大幅减小体积。
  2. 合理利用构建缓存:将变化频率低的指令(如 COPY requirements.txt + RUN pip install)放前面,变化频繁的(如 COPY . .)放后面。
  3. 选择精简基础镜像:优先使用 alpine、slim 变体而非完整版(如 python:3.12-slim 代替 python:3.12)。
  4. 减少镜像层数:合并多条 RUN 指令(RUN apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/*),并在同一层清理缓存。
  5. 使用 .dockerignore:排除 .git、node_modules、__pycache__ 等,避免无关文件进入构建上下文。
  6. 避免以 root 运行:使用 USER 指定非 root 用户运行应用。
  7. 固定基础镜像版本:使用 python:3.12.3-slim 而非 python:latest,确保构建可复现。

延伸思考: ADD 和 COPY 有什么区别?什么时候该用 ADD?(提示:ADD 支持远程 URL 和自动解压 tar,但语义不明确时优先用 COPY)


3. 什么是多阶段构建(Multi-stage Build)?它解决了什么问题?请举例说明 ​

难度: ⭐⭐

标准答案:

多阶段构建允许在一个 Dockerfile 中使用多个 FROM 语句,每个 FROM 开始一个新阶段,可从前一阶段选择性拷贝产物。

解决的问题:

  • 镜像体积膨胀:传统方式需在同一镜像中安装编译工具链(如 Go 编译器、Node 构建依赖),导致最终镜像包含大量无用文件。
  • 安全性风险:编译工具和源码留在生产镜像中,增加攻击面。

示例(Go 应用):

dockerfile
# 阶段1:构建
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o myapp

# 阶段2:运行
FROM alpine:3.19
RUN apk add --no-cache ca-certificates
COPY --from=builder /app/myapp /usr/local/bin/myapp
ENTRYPOINT ["myapp"]

最终镜像从 ~1GB(含 Go 工具链)缩减到 ~10MB(仅 alpine + 二进制)。

延伸思考: 多阶段构建中如何调试中间阶段的产物?(提示:docker build --target builder -t debug-image . 可构建到指定阶段)


4. Docker 的网络模式有哪些?bridge、host、overlay 分别适用于什么场景? ​

难度: ⭐⭐

标准答案:

模式原理适用场景
bridge默认模式。容器通过虚拟网桥(docker0)连接,每个容器分配独立 IP,通过 NAT 访问外部网络单机多容器通信、需要端口映射的场景
host容器直接使用宿主机网络栈,无网络隔离对网络性能要求极高的场景(如高并发网关),或需要直接访问宿主机网络接口时
overlay跨主机的虚拟网络,基于 VXLAN 隧道实现,需配合 Swarm 或独立 etcd/ConsulDocker Swarm 集群中跨主机容器通信、多主机微服务互联

其他常用模式:

  • none:无网络,适用于安全敏感的离线计算任务
  • macvlan:容器拥有独立 MAC 地址,直接接入物理网络,适用于需要被外部网络直接访问的场景

延伸思考: bridge 模式下容器间通信的性能瓶颈在哪?如何优化?(提示:docker0 的 NAT 转发、iptables 规则匹配开销,可考虑 macvlan 绕过网桥)


5. Docker 数据卷(Volume)与绑定挂载(Bind Mount)有什么区别?生产环境应如何选择? ​

难度: ⭐⭐

标准答案:

特性VolumeBind Mount
存储位置Docker 管理(/var/lib/docker/volumes/)宿主机任意路径
创建方式docker volume create 或 Dockerfile VOLUME-v /host/path:/container/path
生命周期独立于容器,需显式删除依赖宿主机目录
可移植性高,跨平台一致低,依赖宿主机目录结构
权限管理Docker 自动处理可能遇到 UID/GID 映射问题
备份docker run --rm -v vol:/data busybox tar czf /backup/data.tar.gz /data直接备份宿主机目录

生产建议:

  • 优先使用 Volume:数据库持久化、配置文件、日志等场景,由 Docker 统一管理更安全可靠
  • Bind Mount 适用于:开发环境代码热更新(挂载源码目录)、需要精确控制宿主机路径的场景
  • tmpfs Mount:敏感临时数据(如密码、session),不落盘,容器停止即消失

延伸思考: 容器集群(Swarm/K8s)中如何处理数据卷的跨节点共享?(提示:分布式存储如 NFS、Ceph、GlusterFS,或使用 CSI 插件)


6. 如何使用 Docker Compose 编排一个包含 Web + Redis + PostgreSQL 的多层应用?请写出核心配置并说明关键指令 ​

难度: ⭐⭐

标准答案:

yaml
version: "3.8"
services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://app:secret@db:5432/appdb
      - REDIS_URL=redis://cache:6379/0
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: appdb
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 5s
      retries: 5

  cache:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redisdata:/data

volumes:
  pgdata:
  redisdata:

关键点:

  • depends_on + healthcheck:确保数据库就绪后再启动 Web,避免连接失败
  • 命名 Volume 持久化数据库和缓存数据
  • 服务间通过服务名(db、cache)互相访问,Docker 内置 DNS 解析

延伸思考: depends_on 只保证启动顺序,如何确保应用在依赖服务真正可用后才开始连接?(提示:应用层重试机制 + healthcheck + condition: service_healthy)


7. Docker 容器安全有哪些关键实践?如何防止容器逃逸? ​

难度: ⭐⭐⭐

标准答案:

镜像安全:

  • 使用可信基础镜像(官方镜像、Docker Scout 扫描漏洞)
  • 定期更新镜像,修复已知 CVE
  • 不在镜像中硬编码密钥(使用 Docker Secrets 或外部密钥管理)

运行时安全:

  • 禁止以 root 运行:USER nobody 或指定非零 UID
  • 只读文件系统:docker run --read-only,配合 --tmpfs 挂载临时目录
  • 限制能力:--cap-drop ALL --cap-add NET_BIND_SERVICE,仅授予必要 Linux 能力
  • 禁用特权模式:避免 --privileged,这是容器逃逸的主要入口
  • 资源限制:--memory、--cpus、--pids-limit 防止 DoS
  • AppArmor/SELinux:启用强制访问控制策略
  • Seccomp:限制容器可用的系统调用(Docker 默认启用 Seccomp Profile)

防止容器逃逸核心措施:

  1. 不挂载 Docker Socket(/var/run/docker.sock)
  2. 不挂载宿主机敏感目录(/、/etc、/proc、/sys)
  3. 不使用 --privileged 和 --pid=host
  4. 使用 User Namespace 隔离(--userns-remap)
  5. 保持 Docker 版本更新,关注 runc 等运行时安全补丁

延伸思考: 什么是 User Namespace?它如何映射容器内 root 到宿主机非特权用户?(提示:/etc/subuid、/etc/subgid 配置映射范围)


8. 如何对 Docker 容器进行性能调优?请从 CPU、内存、I/O、网络四个维度说明 ​

难度: ⭐⭐⭐

标准答案:

CPU 调优:

  • --cpus=2.5:限制容器最多使用 2.5 个 CPU 核心
  • --cpuset-cpus=0-3:绑定容器到指定 CPU 核心,减少上下文切换
  • --cpu-shares=512:设置 CPU 时间分配权重(相对值,非绝对限制)

内存调优:

  • --memory=2g --memory-swap=2g:限制内存和 swap(swap=memory 表示禁用 swap)
  • --memory-reservation=1g:软限制,内存紧张时才生效
  • --oom-kill-disable:禁止 OOM Killer 杀容器(⚠️ 慎用,可能导致宿主机不可用)
  • 使用 tmpfs 替代磁盘 I/O 临时数据:--tmpfs /tmp:size=100m

I/O 调优:

  • --device-write-bps /dev/sda:10mb:限制块设备写入速率
  • 使用 Volume 而非 Bind Mount(Volume 使用 Docker 优化的存储驱动)
  • 选择合适的 Storage Driver(overlay2 > devicemapper)
  • 数据库类容器考虑直接挂载物理磁盘(--device)

网络调优:

  • host 模式消除 NAT 开销(适合高并发网关)
  • 调整 net.core.somaxconn 等内核参数
  • 使用 --dns 指定高性能 DNS,减少解析延迟

监控工具: docker stats、cAdvisor、Prometheus + Grafana

延伸思考: --cpu-shares 和 --cpus 的本质区别是什么?为什么 --cpu-shares 在宿主机空闲时不起作用?(提示:shares 是相对权重,只在资源竞争时生效;cpus 是绝对上限)


9. 如何有效减小 Docker 镜像体积?请给出具体策略和工具 ​

难度: ⭐⭐

标准答案:

策略层面:

  1. 多阶段构建:构建阶段与运行阶段分离,只拷贝最终产物(效果最显著)
  2. 选择精简基础镜像:alpine(~5MB)> slim(~70MB)> 默认(~900MB)
  3. 合并 RUN 指令:RUN apt-get update && apt-get install -y pkg && rm -rf /var/lib/apt/lists/*
  4. 清理构建缓存:pip 缓存 --no-cache-dir、npm 缓存 npm cache clean --force
  5. 使用 .dockerignore:排除 .git、node_modules、测试文件等
  6. 使用 distroless 镜像:Google distroless 仅包含应用运行时,无 shell 和包管理器

工具层面:

  • docker image history <image>:查看每层大小,定位臃肿层
  • dive(开源工具):交互式分析镜像层内容,发现浪费空间
  • docker-slim:自动分析容器运行时依赖,生成最小化镜像(可从 400MB 压缩到 20MB)
  • trivy:扫描镜像漏洞的同时也能发现无用包

对比示例:

node:20           → 1.1GB
node:20-slim      → 230MB
node:20-alpine    → 180MB
多阶段 + alpine   → ~50MB
distroless        → ~30MB

延伸思考: alpine 镜像使用 musl libc 而非 glibc,可能带来什么兼容性问题?(提示:预编译二进制可能不兼容、DNS 解析行为差异、某些 Python C 扩展编译失败)


10. 如何搭建企业级 Docker 私有仓库?请对比主流方案并说明 CI/CD 集成方式 ​

难度: ⭐⭐⭐

标准答案:

方案对比:

方案特点适用场景
官方 registry轻量,仅提供 push/pull,无 UI小团队、简单需求
Harbor企业级:RBAC、镜像扫描、镜像签名、复制策略、审计日志中大型团队、合规要求
Nexus Repository支持多种包格式(Docker + Maven + npm)多语言制品统一管理
云厂商 ACR/ECR/GCR免运维、全球加速、与云生态深度集成云原生部署

Harbor 搭建核心步骤:

bash
# 1. 下载 Harbor 安装包
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-online-installer-v2.10.0.tgz
tar xzf harbor-online-installer-*.tgz

# 2. 配置 harbor.yml
hostname: harbor.company.com
harbor_admin_password: <密码>
data_volume: /data/harbor

# 3. 安装(含 Trivy 镜像扫描)
./install.sh --with-trivy --with-chartmuseum

CI/CD 集成流程:

yaml
# GitLab CI 示例
build-and-push:
  stage: deploy
  image: docker:24
  services:
    - docker:24-dind
  script:
    - echo "$HARBOR_PASSWORD" | docker login harbor.company.com -u "$HARBOR_USER" --password-stdin
    - docker build -t harbor.company.com/project/app:$CI_COMMIT_SHORT_SHA .
    - docker push harbor.company.com/project/app:$CI_COMMIT_SHORT_SHA
    # 可选:推送 latest 标签
    - 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
  only:
    - main

关键实践:

  • 使用 HTTPS + 证书认证,禁止 HTTP 推送
  • 启用镜像漏洞自动扫描(Trivy/Clair),阻止高危漏洞镜像部署
  • 配置镜像保留策略,自动清理旧标签
  • Robot Account 代替个人凭据用于 CI/CD 推送
  • 多 Harbor 实例间配置复制策略实现异地容灾

延伸思考: 如何实现镜像的「不可变标签」策略,防止同一 tag 被覆盖导致生产环境不可复现?(提示:Harbor 支持开启 Immutability Rules,锁定特定 tag 不可被覆盖或删除)


本文档由阿虾 🦐 自动生成,祝面试顺利!