Docker-13 高频面试题(基础与命令篇):40+ 题带答题思路
使用方式
面试时不要只背一句定义。一个好的回答通常包含:先给结论,再解释机制,最后补充边界和实践。例如回答”容器和虚拟机的区别”时,先说共享内核与隔离边界,再说明性能和安全取舍,最后给出什么时候选择 VM。
每道题标注了难度,方便按自身水平针对性准备:
- [初级]:基础概念和常见命令,应届和初级岗位必答。
- [中级]:需要理解原理或有实际排障经验,中级岗位重点。
- [高级]:生产设计、开放题和深度追问,高级/资深岗位考察。
1. 基础概念题
1.1 [初级] Docker 和虚拟机有什么区别?
**参考答案:**虚拟机通过 Hypervisor 虚拟硬件,每台 VM 运行完整 Guest OS 和独立内核;Docker 容器是宿主机上的隔离进程,主要依赖 namespace、cgroup、联合文件系统、capability 和 LSM。容器启动更快、密度更高、镜像更小,但共享宿主内核,隔离强度和内核漏洞影响面不同。需要不同内核或强隔离时选 VM,需要高密度交付应用时选容器;两者也常组合使用。
1.2 [初级] 镜像和容器有什么区别?
镜像是不可变的分层文件系统加运行元数据,类似“模板”;容器是镜像的运行实例,拥有可写层、进程、namespace、cgroup、网络和生命周期。删除容器通常会删除它的可写层,但不会删除被独立引用的镜像和 named volume。
1.3 [初级] 镜像为什么要分层?
每个 layer 内容寻址且只读,多个镜像可以共享相同层,减少传输和磁盘占用。构建时层还可以参与缓存;修改发生在上层,overlayfs 会做 copy-up。层太多或在大文件上频繁修改,会造成构建慢、磁盘膨胀和运行时 I/O 成本,因此要合理组织 Dockerfile,并把变化频繁的内容放后面。
1.4 [初级] Docker Hub、Registry、Repository、Tag、Digest 有什么区别?
Registry 是镜像分发服务,Repository 是其中的一组镜像名称,Tag 是可移动的版本别名,Digest 是内容摘要。repo/app:1.0 可能以后指向另一个 digest;repo/app@sha256:... 内容不可变,生产发布和审计应记录 digest。多架构镜像还可能先解析到 image index,再选择目标架构的 manifest。
1.5 [中级] Docker Engine 包含哪些组件?
CLI 负责发送 API 请求;dockerd 管理镜像、容器、网络和卷;containerd 负责镜像传输、snapshot 和容器生命周期;containerd-shim 解耦任务与 daemon;runc 按 OCI Runtime Spec 创建 namespace、挂载 rootfs、配置 cgroup 和启动进程。回答时要强调 Docker 是产品层,而不是一个单独的“容器系统调用”。
1.6 [中级] Docker 和 Kubernetes 是什么关系?
Docker Engine 主要管理单机容器生命周期,Kubernetes 管理多机集群中的调度、服务发现、扩缩容和自愈。Kubernetes 1.24 起移除了内置 dockershim,通常通过 containerd 或 CRI-O 运行容器,但仍可运行 Docker 构建的 OCI 镜像。Docker 负责构建和本地运行,Kubernetes 负责集群编排,这两个职责不冲突。
1.7 [中级] 什么是 OCI?
OCI 是开放容器倡议,定义镜像、运行时和分发规范。Docker、containerd、Podman、Kubernetes 使用的很多镜像和低层 runtime 因此可以互操作。Dockerfile 是构建输入,OCI image 是构建产物,config.json 是某次运行实例的低层执行配置,三者不要混为一谈。
1.8 [初级] docker run 和 docker start 的区别?
docker run 通常等价于“从镜像创建一个新容器并启动”,每次可以产生新容器;docker start 只启动已经存在但停止的容器,保留其名称、可写层和元数据。需要修改端口、挂载或环境变量时通常要删除并重新创建,不能依赖 start 修改创建时参数。
1.9 [初级] docker stop、kill、rm -f 有什么区别?
stop 先发 SIGTERM,等待超时再 SIGKILL,给应用优雅退出机会;kill 默认直接发 SIGKILL(也可指定信号);rm -f 会强制停止并删除容器,可能破坏排障现场和可写层。生产排障先 inspect、logs、保存事件,再决定是否强制删除。
1.10 [中级] 为什么容器退出码常见 137?
137 = 128 + 9,表示进程收到 SIGKILL。最常见原因是 cgroup 内存超限被 OOM kill,也可能是人为 docker kill 或宿主机压力下被杀。不能只看退出码,要检查 .State.OOMKilled、docker stats、cgroup memory.events、宿主 dmesg 和应用日志。
2. 命令和生命周期题
2.1 [中级] 如何排查”容器启动后马上退出”?
docker ps -a --no-trunc
docker inspect app --format '{{.State.Status}} {{.State.ExitCode}} {{.State.Error}}'
docker logs --tail 200 app
docker image inspect image
先确认 entrypoint/CMD 是否存在和可执行,再确认环境变量、配置文件、动态库、端口和依赖服务。不要先使用 rm -f,否则会丢失退出状态和现场。
2.2 [初级] docker exec 和 docker attach 有什么区别?
exec 在运行中的容器内启动一个新进程,适合执行 shell、检查配置和临时诊断;attach 把当前终端连接到容器主进程的标准输入输出,退出方式不当可能影响主进程。生产调试优先 exec,不要把 attach 当作登录会话。
2.3 [初级] docker inspect 用来解决什么问题?
它返回容器/镜像/网络/卷的结构化元数据,可查看状态、退出码、PID、挂载、端口、网络、环境变量、健康检查和 runtime 配置。复杂字段配合 Go template 或 jq 提取;它不会显示应用内部所有状态,也不能替代日志、指标和抓包。
2.4 [中级] 如何查看一个容器占用的资源?
临时观察使用 docker stats,查看进程使用 docker top,查看配置限制使用 docker inspect,深入资源控制器使用 /sys/fs/cgroup。CPU 百分比、内存 working set 和网络 I/O 要结合采样时间、宿主总容量及 cgroup 上限理解,不能把一次快照当结论。
2.5 [中级] docker logs 为什么看不到应用日志?
docker logs 默认读取容器的 stdout/stderr。如果应用把日志写到容器内文件,Docker 不会自动展示;要么改成 stdout/stderr 并由日志驱动采集,要么明确挂载日志目录并由采集器读取。还要检查容器是否使用了特殊 logging driver,以及应用是否在启动前就退出。
2.6 [中级] 如何清理 Docker 磁盘?
先执行 docker system df -v 区分镜像层、已停止容器、volume、网络、BuildKit cache 和日志,再按风险清理 container prune、悬空镜像和 builder cache。system prune -a --volumes 可能删除未使用镜像和卷,生产执行前必须列目标、确认备份和业务窗口。
2.7 [中级] docker save 和 docker export 有什么区别?
save/load 面向镜像,保留多层结构、tag 和镜像元数据,适合离线搬运镜像;export/import 面向容器 rootfs,通常得到扁平文件系统,不保留原镜像历史和 volume。二者都不是数据库一致性备份工具。
2.8 [中级] 如何连接远程 Docker daemon?
优先使用 SSH context:
docker context create prod --docker host=ssh://ops@server
docker context use prod
不要把未加密 TCP 2375 暴露到公网;如果确需 TCP,应使用 TLS、证书授权、网络 ACL 和审计。操作前用 docker context show 确认当前目标,避免把清理命令执行在生产上。
3. Dockerfile 面试题
3.1 [初级] CMD 和 ENTRYPOINT 的区别?
ENTRYPOINT 更像固定的主程序,CMD 提供默认命令或参数。二者同时使用时,exec form 下通常是 ENTRYPOINT + CMD;docker run image args... 会覆盖 CMD,--entrypoint 会替换 ENTRYPOINT。优先使用 JSON 数组 exec form,避免 shell 成为 PID 1 而截留 SIGTERM。
3.2 [初级] ADD 和 COPY 的区别?
COPY 只负责从构建上下文复制文件;ADD 还支持本地归档自动解包等额外语义。普通复制优先 COPY,这样意图更清楚、风险更低。远程文件下载应在可校验的构建步骤中完成,而不是依赖不透明的 URL 行为。
3.3 [初级] ARG 和 ENV 的区别?
ARG 只在构建阶段可用,可用 --build-arg 传入;ENV 会写进镜像配置,并在容器运行时默认存在。两者都不适合保存秘密:ARG 可能出现在构建历史和元数据中,ENV 会被 inspect 看到。
3.4 [中级] 什么是构建上下文?为什么要 .dockerignore?
构建上下文是传给 BuildKit 的目录,COPY 只能读取其中的文件。上下文包含 .git、依赖缓存或秘密会让构建慢、泄露数据并污染缓存;.dockerignore 用来排除它们。面试可以补充:Dockerfile 所在目录不一定等于上下文目录,命令最后的路径才决定上下文。
3.5 [中级] 什么是多阶段构建?
在同一个 Dockerfile 中用多个 FROM,前一阶段编译,最终阶段只 COPY --from 产物。它把编译器、源码和测试工具排除出运行镜像,减小攻击面和体积。要确认静态/动态链接、证书、时区、非 root 用户和调试能力,不是盲目选择 scratch。
3.6 [中级] 如何优化 Dockerfile 构建缓存?
把稳定输入先复制、变化频繁的源代码后复制,例如先 COPY go.mod go.sum 再下载依赖。减少无关文件进入上下文,合并合理的包安装和清理步骤,启用 BuildKit cache mount。缓存不能替代依赖锁定和定期无缓存重建,升级基础镜像或安全补丁时要主动失效缓存。
3.7 [高级] 如何在 Docker 构建时处理秘密?
不要用 ENV、ARG 或 RUN echo secret,因为秘密可能进入 layer、历史、构建日志或缓存。使用 BuildKit RUN --mount=type=secret,或让部署阶段注入秘密。即使使用 secret mount,也要限制构建器权限、避免打印秘密,并在 CI 中轮换凭据。
4. Compose 面试题
4.1 [初级] Compose 的用途和边界是什么?
Compose 用 YAML 声明单机上一组服务、网络、卷、环境和健康检查,适合开发、测试、CI 和简单单机部署。它不提供完整的多机调度、跨节点高可用、自愈和成熟滚动发布;这些属于 Kubernetes、Swarm 或云编排平台。
4.2 [初级] Compose 中服务之间如何通信?
同一 Compose 网络内通过服务名访问,例如 db:5432,Docker 内置 DNS 会把服务名解析到当前容器 IP。不要使用 localhost 连接另一个服务,因为 localhost 指当前 network namespace。容器重建后 IP 可能改变,服务名和重试机制应保持稳定。
4.3 [中级] depends_on 能保证数据库可用吗?
短写法只保证启动顺序,不保证服务已经接受连接。应配置 healthcheck 和 condition: service_healthy,应用仍要实现连接重试、退避和断线重连。健康检查只说明探针成功,不代表迁移完成或业务已经可写。
4.4 [初级] docker compose down 和 down -v 的区别?
down 删除 Compose 创建的容器和网络,默认保留 named volume;down -v 还会删除声明的卷,可能造成数据库数据丢失。面试时应说明清理前查看项目名、卷列表和备份,不要把 -v 当普通重启命令。
4.5 [中级] 如何管理多套 Compose 环境?
用基础 compose.yaml 加 compose.dev.yaml/compose.prod.yaml 覆盖,使用 --env-file 管理变量,并在启动前运行 docker compose config 查看最终渲染结果。生产秘密不进 Git;Compose 文件要避免宿主绝对路径和固定 container_name,以保留可移植性与扩展能力。
5. 继续追问:容易被追到的细节
5.1 [中级] docker create、start、run、restart 如何区分?
create 只根据镜像和参数生成已停止容器,不启动主进程;start 启动已存在容器,不能改变创建时的端口、卷和环境;run 通常是 create + start;restart 是对现有容器执行 stop/start,不重新读取 Dockerfile,也不改变挂载和环境。配置改变时应该重新创建容器,不能用 restart 假装发布了新配置。
5.2 [中级] HEALTHCHECK 失败会自动重启吗?
不会。它只把容器健康状态标为 unhealthy,restart policy 观察的是主进程退出。单机 Docker 可以让应用在不可恢复时退出,或者由外部 watchdog 处理;Kubernetes 等平台通常把 liveness 和 readiness 分开,分别决定重启和摘流。健康检查必须轻量、幂等,并有启动宽限期。
5.3 [中级] -v 和 --mount 选哪个?
两者都能创建 volume、bind 和 tmpfs,但 --mount 字段更明确,路径错误和类型错误更容易被发现;-v 更短,历史脚本很多。生产配置优先 --mount 或 Compose 长语法,显式写 type、source、target、read_only 和传播选项,减少“路径不存在时被 Docker 自动创建”的误会。
5.4 [中级] 容器端口为什么必须监听 0.0.0.0?
容器内 127.0.0.1 只在本容器 network namespace 有效,其他容器通过容器 IP 访问不到;服务通常监听 0.0.0.0,再由 Docker network、宿主防火墙和入口代理控制暴露范围。使用 host network 时语义不同,因为容器直接看到宿主 namespace。
5.5 [中级] 如何推送一个生产镜像?
docker buildx build --platform linux/amd64,linux/arm64 \
-t registry.example.com/team/api:1.4.0 \
--push .
docker buildx imagetools inspect registry.example.com/team/api:1.4.0
docker pull registry.example.com/team/api:1.4.0
docker image inspect registry.example.com/team/api:1.4.0 \
--format '{{json .RepoDigests}}'
先登录受控 registry,扫描并签名,再把 digest 写入部署配置。tag 只作为人类入口,回滚和审计要以 digest 为准;多架构发布还要确认每个目标架构都能启动。
5.6 [中级] 怎样判断镜像是否真的变小了?
docker image ls example/api
docker history --no-trunc example/api:1.0.0
docker system df -v
镜像压缩体积、解压后磁盘占用、构建缓存、运行时可写层和网络拉取时间不是同一个指标。多阶段构建能去掉编译工具,.dockerignore 能缩小上下文;把文件在下一层删除并不会删除前一层 blob。最终还要测冷启动、扫描结果和应用依赖是否完整。
5.7 [中级] docker commit 为什么通常不推荐?
它可以把容器当前文件系统层保存成镜像,但无法可靠表达构建命令、依赖版本、秘密来源、测试和审计信息;同一操作难以复现。排障时可以临时保留现场,但生产修复应回写 Dockerfile、锁文件和 CI,重新构建并发布。
5.8 [高级] docker update 能修改什么?
docker update 修改已有容器的部分运行配置,主要是 CPU、内存、PIDs、块 I/O 和 restart policy;资源控制通常直接写入 cgroup,容器 PID 1 不变。它不能更新镜像、环境变量、端口、挂载、entrypoint 或 healthcheck,这些变更需要按新配置重建容器。Compose 管理的容器手工 update 还会产生配置漂移,紧急止损后必须把最终值回写声明文件。
常用验证:
docker inspect api --format '{{json .HostConfig}}' | jq
docker update --cpus 1.5 --memory 768m --restart unless-stopped api
docker inspect api --format '{{.State.Pid}} {{.HostConfig.NanoCpus}} {{.HostConfig.Memory}}'
5.9 [高级] 修改 docker update 的内存上限有风险吗?
有。增大上限通常不会重启进程,但减小到低于当前使用量可能触发回收和 cgroup OOM;--memory-swap 表示内存+swap 总量的组合还必须合法。变更前记录当前值,变更后观察 memory.current、memory.events、OOMKilled、延迟和错误率,并准备按原值回滚。
6. 开放题答题模板
6.1 [高级] “如何把一个服务容器化?”
按以下顺序回答:
- 确认服务端口、配置、依赖、数据生命周期和优雅退出协议。
- 写
.dockerignore和多阶段 Dockerfile,固定基础镜像,非 root 运行。 - 加 healthcheck、日志 stdout、资源限制和安全选项。
- 用 Compose/CI 构建测试、扫描、生成 SBOM、推送 registry。
- 部署用 tag + digest,配置和秘密独立注入,准备监控、备份、回滚和故障演练。
6.2 [中级] “容器为什么比虚拟机快?”
不要回答“容器没有虚拟化”。更准确的说法是:容器复用宿主机内核,启动时不需要引导 Guest OS,因此启动和资源开销通常更低;但应用本身、网络、磁盘和安全检查仍会产生成本,Desktop 还要经过 Linux VM。性能结论必须用目标工作负载基准测试验证。
7. 本篇小结
基础面试题的高分答案不在于背更多命令,而在于能说明对象、生命周期、边界和风险:镜像不可变、容器可替换、数据独立持久化、网络通过服务名、权限最小化,出了问题用 inspect/日志/指标保留证据。
| 上一篇 | 下一篇 |
|---|---|
| 12-实战项目与生产发布 | 14-面试题:原理与生产 |