Skip to content

本模块聚焦 Docker 容器化核心知识,从基础概念到镜像构建、网络、存储、安全等实战层面,全面考察候选人对容器技术的理解深度和实践经验。

Q1: Docker是什么?和虚拟机有什么区别? 「🟢 校招/初级」

考察点:考察容器基础概念,筛掉对容器化和虚拟化本质区别理解不清的人。

参考答案

  • Docker 是一个开源的容器化平台,用于将应用及其依赖打包到一个轻量级、可移植的容器中,实现"一次构建,到处运行"。
  • 容器 vs 虚拟机的核心区别:
    • 架构层面:虚拟机(VM)通过 Hypervisor 模拟完整的操作系统,每个 VM 有独立的内核;容器共享宿主机内核,在用户空间进行隔离。
    • 启动速度:容器秒级启动,VM 需要分钟级。
    • 资源占用:容器体积小(MB 级),资源利用率高;VM 体积大(GB 级),开销大。
    • 隔离性:VM 是操作系统级别的强隔离;容器是进程级别的轻量隔离(Namespace + Cgroup)。
    • 性能:容器接近原生性能,VM 有虚拟化层损耗。
架构对比:
VM 模式:  App → Bins/Libs → Guest OS → Hypervisor → Host OS → Hardware
容器模式:App → Bins/Libs → Docker Engine → Host OS → Hardware

追问延伸

  • Docker 利用了 Linux 的哪些内核特性实现隔离?(Namespace、Cgroup、UnionFS)
  • 容器的隔离性是不是绝对安全的?有哪些容器逃逸的风险?
  • 什么场景下更适合用 VM 而不是容器?

Q2: Docker的核心概念?镜像、容器、仓库 「🟢 校招/初级」

考察点:考察 Docker 三大核心概念的理解,筛掉对基础概念混淆的人。

参考答案

  • 镜像(Image)

    • 是一个只读的模板,包含运行应用所需的代码、运行时、库、环境变量和配置文件。
    • 采用分层存储(UnionFS),每一层都是只读的,通过层的叠加构建完整镜像。
    • 类似于面向对象中的"类"。
  • 容器(Container)

    • 是镜像的运行实例,是镜像创建的运行态实体。
    • 在镜像的只读层之上添加了一层可写层(Container Layer),所有文件修改都发生在可写层。
    • 可以被创建、启动、停止、删除,容器删除后可写层数据也随之丢失。
    • 类似于面向对象中的"对象/实例"。
  • 仓库(Repository/Registry)

    • 用于存放镜像的集中地,类似于代码的 Git 仓库。
    • Docker Hub 是官方公共仓库,也可以搭建私有仓库(如 Harbor)。
    • 一个仓库可以包含多个标签(Tag)的镜像,如 nginx:latestnginx:alpine
  • 三者关系:从仓库拉取镜像 → 基于镜像创建容器 → 容器运行应用 → 容器提交后可生成新镜像 → 推送回仓库。

追问延伸

  • 镜像的分层机制有什么好处?(复用、节省空间、增量分发)
  • 容器的可写层数据如何持久化?(数据卷 Volume)
  • 什么是 Docker Registry?和 Docker Repository 有什么区别?

Q3: Dockerfile的最佳实践有哪些? 「🟡 中级」

考察点:考察镜像构建能力和工程化意识,筛掉只会写简单 Dockerfile、不关注构建效率和镜像质量的人。

参考答案

  • 多阶段构建(Multi-stage Build)
    • 使用 FROM ... AS builder 构建阶段编译代码,再用 FROM 运行阶段只拷贝产物。
    • 最终镜像不包含编译工具和源码,大幅减小体积。
    dockerfile
    FROM golang:1.21 AS builder
    WORKDIR /app
    COPY . .
    RUN go build -o myapp .
    
    FROM alpine:3.18
    COPY --from=builder /app/myapp /usr/local/bin/
    CMD ["myapp"]
  • 合理利用构建缓存
    • 将变化少的指令(如依赖安装)放在前面,变化多的指令(如代码拷贝)放在后面。
    • 先拷贝 package.json / go.mod 再安装依赖,最后拷贝源码,避免每次代码变更都重新下载依赖。
  • 减少镜像层数
    • 合并多个 RUN 指令为一个,用 && 连接,减少中间层。
    • 清理缓存和临时文件在同一个 RUN 指令中完成。
  • 使用 .dockerignore
    • 排除 .gitnode_modules、日志等不需要的文件,加快构建速度、减小上下文体积。
  • 使用非 root 用户
    • 创建普通用户并切换,遵循最小权限原则,增强安全性。
    dockerfile
    RUN adduser -D appuser
    USER appuser
  • 选择合适的基础镜像
    • 优先使用 alpinedistroless 等精简镜像。
    • 固定镜像版本标签,避免使用 latest 导致的不可预期。
  • 设置合理的 WORKDIR、EXPOSE、CMD/ENTRYPOINT
    • 明确工作目录、暴露端口、启动命令,提升可读性和规范性。

追问延伸

  • 多阶段构建有哪些高级用法?(多 FROM 并行构建、COPY --from 跨阶段拷贝)
  • 如何调试 Dockerfile 构建失败的问题?(查看中间层、--progress=plain、进入失败层排查)
  • CMD 和 ENTRYPOINT 的区别是什么?

Q4: Docker的网络模式有哪些? 「🟡 中级」

考察点:考察容器网络知识,筛掉对网络模式一知半解、只会用默认 bridge 的人。

参考答案

  • bridge 模式(默认)
    • Docker 创建一个 docker0 虚拟网桥,容器通过 veth pair 连接到网桥上。
    • 容器之间可以通过 IP 互相通信,外部通过端口映射访问容器。
    • 适用于同一宿主机上的容器间通信,是最常用的模式。
  • host 模式
    • 容器共享宿主机的网络命名空间,直接使用宿主机的 IP 和端口。
    • 性能最好(没有 NAT 开销),但端口冲突风险高,隔离性差。
    • 适用于对网络性能要求高的场景,如网络插件、监控 Agent。
  • none 模式
    • 容器没有网络栈,只有 loopback 接口,完全隔离网络。
    • 适用于高安全需求、不需要网络的计算任务。
  • container 模式
    • 新创建的容器共享另一个已存在容器的网络命名空间。
    • 两个容器之间可以通过 localhost 通信。
    • Kubernetes 的 Pod 就是基于此模式实现的(Pause 容器共享网络)。
  • overlay 模式
    • 用于跨多台宿主机的容器通信,构建在底层网络之上的覆盖网络。
    • 使用 VXLAN 技术实现,常见于 Docker Swarm 或 Kubernetes 集群网络。
    • 适用于分布式应用、集群环境。
网络模式选择参考:
单机单容器通信 → bridge
极致网络性能 → host
跨主机集群   → overlay
Pod 内共享   → container
完全隔离     → none

追问延伸

  • bridge 模式下容器是怎么访问外网的?(iptables NAT + 宿主机转发)
  • 容器之间除了 IP 还能怎么通信?(自定义网络 + DNS 服务发现)
  • Docker 的自定义网络和默认 bridge 有什么区别?(DNS 自动解析、更好的隔离性)

Q5: Docker的数据卷(Volume)有什么用?有几种类型? 「🟡 中级」

考察点:考察数据持久化方案,筛掉不理解容器数据管理、不知道如何持久化的人。

参考答案

  • 数据卷的作用
    • 数据持久化:容器删除后数据不丢失,解决容器可写层数据随容器销毁的问题。
    • 数据共享:多个容器之间可以共享数据。
    • 性能更好:直接操作宿主机文件系统,绕过 UnionFS。
    • 备份和迁移方便。
  • 三种数据卷类型
    1. Bind Mount(绑定挂载)
      • 将宿主机上的任意文件或目录挂载到容器中。
      • 灵活,直接访问宿主机文件系统,但依赖宿主机目录结构,可移植性差。
      • 适用于开发环境、配置文件挂载。
      bash
      docker run -v /host/path:/container/path ...
    2. Volume(命名卷)
      • 由 Docker 管理,存储在 Docker 的存储目录中(/var/lib/docker/volumes)。
      • 生命周期独立于容器,可以通过名称引用,便于共享和管理。
      • 支持卷驱动(Volume Driver),可对接远程存储。
      • 是生产环境推荐的持久化方式。
      bash
      docker run -v myvolume:/container/path ...
    3. tmpfs Mount(内存文件系统)
      • 挂载到宿主机内存中,不写入磁盘,速度极快。
      • 容器停止后数据丢失,适用于敏感数据临时存储、高性能缓存。
      bash
      docker run --tmpfs /run ...
  • 数据共享方案:同一 Volume 挂载到多个容器;使用 --volumes-from 继承其他容器的卷。

追问延伸

  • Volume 和 Bind Mount 应该怎么选?各有什么优缺点?
  • 如何备份和恢复 Docker Volume?(启动临时容器挂载卷 + tar 备份)
  • 什么场景下适合用 tmpfs?有什么限制?

Q6: 如何优化Docker镜像大小? 「🟡 中级」

考察点:考察镜像优化能力,筛掉不关注镜像体积、构建出来的镜像臃肿不堪的人。

参考答案

  • 多阶段构建(Multi-stage Build)
    • 构建阶段使用完整开发镜像编译,运行阶段只拷贝二进制或产物。
    • 去除编译工具、源码、中间产物,是最有效的优化手段。
  • 选择精简的基础镜像
    • alpine:基于 Alpine Linux,体积小(5MB 左右),包管理器完善,最常用。
    • distroless:Google 出品,只包含应用和运行时依赖,无 shell 和包管理器,最安全最小。
    • scratch:空镜像,适合静态编译的 Go 等语言。
    • 避免使用 ubuntucentos 等完整系统镜像作为基础。
  • 合并 RUN 指令
    • 多个 RUN 会产生多个镜像层,合并为一个 RUN 并清理缓存可减少层数和体积。
    dockerfile
    # 不好的写法(3层,且缓存未清理)
    RUN apt-get update
    RUN apt-get install -y curl
    RUN apt-get clean
    
    # 好的写法(1层,清理缓存)
    RUN apt-get update && apt-get install -y curl && \
        rm -rf /var/lib/apt/lists/*
  • 清理缓存和不必要的文件
    • 包管理器缓存(apt cleanyum cleannpm cache clean)。
    • 删除文档、man 手册、临时文件、调试符号。
  • 使用 .dockerignore
    • 排除 node_modules.git、测试文件等,避免不必要的文件进入构建上下文。
  • COPY 精准拷贝
    • 只拷贝需要的文件,避免 COPY . . 把所有文件拷进去。
  • 使用镜像压缩/瘦身工具
    • docker-slim:自动分析并精简镜像。
    • 多架构镜像构建时只拉取需要的架构。
优化效果参考:
未优化 Node.js 镜像 → ~1GB
alpine 基础镜像    → ~300MB
多阶段构建 + alpine → ~100MB
distroless         → ~50MB

追问延伸

  • alpine 镜像有什么坑吗?(musl libc 兼容性问题、时区问题)
  • 镜像层数是不是越少越好?层数有没有限制?(不是越少越好,要平衡缓存利用和体积;存储驱动有层数上限)
  • 什么是 distroless 镜像?适合什么场景?

Q7: Docker容器安全有哪些注意事项? 「🔴 高级」

考察点:考察容器安全意识和实践经验,筛掉只关注功能、对安全毫无概念的人。

参考答案

  • 用户权限
    • 容器内避免使用 root 用户运行应用,Dockerfile 中创建普通用户并 USER 切换。
    • 设置合理的文件权限,避免敏感文件全局可读。
  • 资源限制(Cgroup)
    • 限制 CPU(--cpus--cpu-shares)、内存(--memory--memory-swap)。
    • 防止单个容器占用过多资源影响宿主机和其他容器。
    bash
    docker run --cpus=2 --memory=512m --memory-swap=512m myimage
  • 只读文件系统
    • 使用 --read-only 将容器根文件系统设为只读,防止恶意篡改。
    • 需要写入的目录使用 tmpfs 或 Volume。
    bash
    docker run --read-only --tmpfs /tmp myimage
  • 禁用特权模式
    • 避免使用 --privileged,该模式赋予容器几乎所有宿主机权限,风险极大。
    • 确有需要时使用 --cap-add 精确添加所需能力。
  • 镜像安全
    • 使用官方或可信来源的基础镜像,避免来路不明的镜像。
    • 镜像扫描工具:Trivy、Clair、Docker Scout,检测 CVE 漏洞。
    • 镜像签名验证(Docker Content Trust / Cosign),确保镜像未被篡改。
  • 内核安全特性
    • seccomp:限制容器可调用的系统调用,减少攻击面。Docker 默认启用 seccomp 配置。
    • AppArmor / SELinux:强制访问控制(MAC),限制容器的文件访问和操作。
    • Linux Capabilities:精细化控制 root 权限,按需添加能力而非全给。
  • 网络安全
    • 避免使用 host 网络模式,减少网络暴露面。
    • 使用自定义网络隔离不同业务的容器。
  • Docker 守护进程安全
    • 保护 Docker socket(/var/run/docker.sock),防止未授权访问。
    • 启用 TLS 认证的远程 API 访问。

追问延伸

  • 什么是容器逃逸?常见的容器逃逸方式有哪些?
  • 如何在容器中运行需要 root 权限的应用但又保证安全?(cap-add 精确授权)
  • Kubernetes 环境下的容器安全有哪些额外的措施?(Pod Security Standards、OPA/Gatekeeper)