☰
Docker面试核心指南:从镜像容器原理到高频实践题
2026/10/13 2:54:05 网站建设 项目流程

1. 找准主线:Docker 面试题考的其实是“怎么理解这三个东西”

最近一个月,前前后后有十多位读者来找我聊 Docker 面试的事。有人把各种速成资料翻了一大堆,能背出docker run -d -p 8080:80,结果被问一句“容器启动的完整流程是什么”就开始卡壳;也有人已经在项目里用 Docker 跑服务跑了大半年,却说不清“为什么容器一删,日志和数据就全没了”。我把这类问题集中整理了一遍,按“基础知识、高频十大面试题、常用指令”三块重新拆开,于是有了这篇内容。

先说一个判断标准:面试官很少真的想听你把docker ps背出来。他们真正想确认的,是你能不能把“架构、隔离、分层、状态、生命周期”这几个词落到具体场景里。能解释清楚“镜像和容器的差别”,说明你理解了不可变交付;能说出“数据卷和容器层谁先丢”,说明你理解了状态和数据;能把“CMD 为什么会被覆盖”讲明白,说明你理解了容器内进程的执行模型。只要这三条线立得住,题目怎么换都不慌。

1.1 容器与虚拟机的区别,是所有问题的第一道门槛

面试里至少有一半的题,绕来绕去都会回到“容器和虚拟机到底差在哪”。如果这道题答出花来,后面很容易被追问网络、存储、资源限制;如果连这道题都含含糊糊,整场基本就定性了。

两者最核心的分界点,是隔离层级不同。虚拟机通过虚拟化硬件运行一个完整内核,Guest OS 独享一段资源;容器则直接复用宿主机内核,靠系统级隔离手段把进程、文件、网络、PID 这些视图隔开。这就是为什么容器启动能以“秒”为单位,而虚拟机从开机到系统就绪通常要几十秒。

特性容器虚拟机
隔离维度进程和资源视图隔离硬件级虚拟化
内核共享宿主机内核独占独立内核
启动速度秒级,本质是拉起进程慢,需要引导完整系统
资源占用轻量,但仍占用宿主机资源固定分配 CPU、内存、磁盘
镜像大小可能只有几十 MB通常几个 GB 起
安全边界内核边界共享,隔离更薄更强的系统边界

听完区别,还要防止踩一个常见坑:不要只说“容器更轻”。面试官马上会追问“为什么更轻”,如果你答不上来,等于没准备。准确说法是:容器不需要引导内核,不需要初始化整块虚拟硬件,它只不过是把用户态进程用 Namespace 和 Cgroups 包装了一下。

1.2 镜像、容器、仓库的关系:用一条时间线讲清楚

镜像只是一堆只读文件层的组合,仓库负责存镜像和分发镜像,容器则是在镜像之上加了一层可读写层后跑起来的进程实例。

打个生活化比方:镜像是一张冷冻披萨饼底,仓库是超市货架,容器是那张被拿出来解冻、加料、烤好并端上桌的成品披萨。饼底是整个流程中可复用的部分,货架上放了同一款饼底的不同批次,而每次按菜单做出来的成品,才是真正被吃掉的那一份。

库、像、器串联起来,意思就是:把干净的交付物放在仓库里,运行时根据需要拉取并实例化。理解了这个三角关系,你就会明白为什么 99% 的题目最后都要落到“镜像层”和“容器层”这两个概念上。镜像层不可修改,所有变更只发生在容器的可写层;一旦docker rm容器,那层可写文件就没了,赖在外面的数据只能靠挂载卷存活。

2. 基础概念不需要全背,但这几个底子必须打牢

2.1 先分清 client 和 daemon:命令行不是你输入的地方

很多人面试时容易把docker命令和后台服务混成一体。实际上你敲的docker run只是一个 client,真正干活的是后台常驻的 daemon。client 把命令行参数转成请求,通过本地 socket 发给 daemon,daemon 再去操作镜像、容器、网络、存储。

这个模型最直接的启发是:daemon 挂了,你输入的指令根本没机会执行。生产环境里排查“命令卡住”“容器状态拉不出来”,第一步通常就是看 daemon 是否正常。理解 client/daemon 的通信方式,还顺带解释了“为什么有些环境下要配置远程连接”、为什么安全上要慎用暴露的 socket。

2.2 Namespace 和 Cgroups:隔离与限制的真正实现者

容器底层主要靠 Linux 的两个机制:Namespace 负责“看起来像一台独立机器”,Cgroups 负责“用资源不能超限”。

Namespace 隔离的是视图。PID Namespace 让容器内的 1 号进程以为自己是系统第一个进程;Mount Namespace 让容器内看到的是自己的文件系统挂载关系;Network Namespace 让容器拥有独立的网络栈、自己的 IP 和端口空间。Cgroups 则是一套资源控制器,能限制 CPU、内存、IO、PID 数量等。面试中被问“容器怎么限制内存”,本质上就是在问 Cgroups 怎么配。

一个容易忽略的点是:隔离的是“视图”,不是“安全边界”。容器和宿主机还是共享同一个内核,如果把权限配置得太开放,风险就会明显上升。这也是为什么正经项目里要做用户降权、只读根文件、丢弃多余 Capability。

2.3 镜像分层:Dockerfile 里的每一行,都可能生成一层

镜像由若干只读层堆叠而成。Dockerfile 里不同指令会创建不同层,层与层之间按顺序叠加,最终从容器角度看,目录是合并在一起的。

层最实际的价值是缓存复用。重新构建镜像时,如果某层没有变化,Docker 可以直接复用之前的层缓存。依赖装了半天的镜像,再次构建往往只有最后几秒,就是这个原因。

正因如此,调整依赖和代码的顺序会影响构建效率。把不常变的依赖安装先放,把频繁改动的业务代码后放,是控制构建速度的常用手段。这一条几乎一定会出现在面试题“如何优化 Dockerfile”里,提前理解分层的规则,比死记命令更可靠。

2.4 镜像层只读,容器层可写,数据问题都从这里来

容器启动时,Docker 在镜像层之上挂一个可写层。对运行中的容器来说,你写文件、改配置、生成日志,默认都落在这个可写层。

问题来了:可写层和容器同生共死。容器被删除,可写层也就没了。这解释了“日志文件为什么丢”“运行期间生成的数据为什么丢”。要持久化,就必须挂载外部存储。VOLUME、-v / 路径、--mount这些语法,本质都是在给容器“续上一条命”,把数据存到容器生命周期之外的地方。

理解这个概念后,很多实战教训都能对上号:不要在同一份镜像里反复改造成本镜像,要把变化的数据放卷里;不要在容器里存重要状态,因为容器随时会被销毁重建。

3. 高频十大面试题,按“问法→答案→得分点”拆开

这个板块是全文的正文重点,我把面试中出现频率最高的十类题逐一拆解,每题都给出可以直接口头回答的思路,后面再加一句“该答到什么程度”作为自查。

3.1 第一题:镜像和容器到底什么关系

问法一般是:“镜像是用来干嘛的?容器又是什么?它们有什么区别?”你要抓住的关键词是“静态”和“动态”。镜像是一堆只读层的静态产物,不做任何运行;容器是镜像实例化之后带可写层、带进程、带网络环境的动态实体。

答案模板可以这么说:镜像定义了“这个应用长什么样”,容器则是“这个应用跑起来的样子”。同一个镜像可以启动多个容器,每个容器之间相互独立;容器删除后镜像还在,可以继续生成新容器。能把“静态文件集”和“运行实例”这两个词说出来,这一题基本就过了。

3.2 第二题:执行 docker run 后,后台发生了什么

这题出现频率相当高。你要答出四段链路:

  • 检查本地有没有镜像,没有就按名称去仓库拉取;
  • 创建容器所需的文件系统,在镜像层上叠加可写层;
  • 分配网络资源,默认接入 bridge 网络并分配 IP;
  • 启动容器内的主进程,把入口命令交给它执行。

如果面试官再追问“-it是什么”,可以补一句:-t分配伪终端,-i保持标准输入打开,连起来的效果是像直接坐进容器里的 shell 一样。

3.3 第三题:为什么建议一个容器只跑一个进程

很多人觉得“一个容器就是一个小虚拟机,可以塞很多进程”,这是最常见的误解。容器真正的主进程只有第一个,也就是 PID 1。如果 PID 1 退出,容器生命周期就结束了,里面其它进程也会跟着被回收。

单进程容器不是硬性规定,而是一种职责拆分策略。一个容器只处理一件业务,日志、监控、升级、扩缩容都更清晰;如果硬塞多个进程,还要额外引入初始化进程来管僵尸进程,复杂度就上去了。你可以说:“我会让每个容器只承载一个主进程,典型的 web 服务就用一个 web 容器加一个数据库容器配合起来跑。”

3.4 第四题:CMD 和 ENTRYPOINT 的区别是什么

这是高频中的高频。核心规则记住三条:

  • CMD提供默认启动命令,可以被docker run后面的参数覆盖;
  • ENTRYPOINT是入口点,执行时不会被普通参数覆盖;
  • 两者同时写时,CMD变成ENTRYPOINT的默认参数。

面试话术可以这样讲:如果希望镜像默认执行某个命令,但允许外面替换,就写CMD;如果希望镜像把“必须执行的程序”焊死,只允许追加参数,就写ENTRYPOINT。举例说明:ENTRYPOINT ["nginx"]配合CMD ["-g", "daemon off;"],外面再传参数时,只是改到了 nginx 的启动参数,不会把 nginx 换成别的命令。

3.5 第五题:容器删了,数据去哪了

这题在新手面试里很常见。主线是分清“容器可写层”和“数据卷”。

容器运行中产生的数据,默认写在可写层。docker rm -f以后,可写层连容器一起被移除,数据就没了。如果你使用VOLUME或-v挂载,数据会写到宿主机目录或命名卷里,容器删除时卷还在,重新启一个容器挂上同一个卷就是旧数据。

得分点是:能主动说出“什么时候该用命名卷,什么时候该用 bind mount”。命名卷适合数据库文件这类程序自己管理的持久化数据,bind mount 适合你需要直接从宿主机编辑的配置文件或代码目录。两个词都提出来,答案的层次就不一样了。

3.6 第六题:容器网络模式怎么选

面试可能问:“host、bridge、none 有什么区别?什么时候用哪个?”你不需要追求全背,但要能分清三个关键词。

bridge 模式是默认方案:容器接入一个虚拟网络,每个容器有独立 IP,容器之间可以通信,对外通过端口映射暴露服务。host 模式直接使用宿主机网络栈,容器没有独立 IP,监听端口就是宿主机端口,性能好但隔离弱。none 模式不给容器配网络,适合需要完全隔离或走自定义网络的场景。

再补充一个加分点:使用自定义 bridge 网络时,容器可以按“容器名”互相访问,不用依赖 IP。很多人在生产环境用自定义网络,就是因为容器重建后 IP 会变,用名字访问才稳定。

3.7 第七题:怎么把镜像体积压下来

这题很实战。面试时不要只唱“用 Alpine”,要说完整的瘦身策略。

我的思路分成四条:选体积小的基础镜像;安装依赖时清理包管理器的临时文件,避免把下载缓存留在镜像里;用多阶段构建,前面阶段负责编译,最终交付阶段只拷贝运行产物;合理利用分层缓存,把依赖安装和代码复制分开,降低重复构建浪费。

多阶段构建是关键得分点,你可以说:我通常在第一个阶段装完整开发工具链,编译完以后在第二个阶段用一个精简运行时镜像,只把编译产出拷过去,这样最终镜像只有产物的体量。

3.8 第八题:我要把容器搬到另一台机器,怎么做

这是一道典型的命令题,但它问的其实是“传递交付物和传递状态的区别”。

如果只是把镜像搬走,用docker save导出成压缩文件,再到对方机器docker load导入。如果只想要文件系统内容、不关心镜像历史信息,可以用docker export配合docker import,但这种方式丢掉了镜像的构建历史和元数据,并不推荐用来迁移镜像。

最稳妥的答案其实不是迁移容器,而是迁移“可重建性”:用 Dockerfile 加依赖清单,到新机器上重新构建。容器本身是可替代的,你真正要搬的是镜像、数据卷内容、以及配置文件。

3.9 第九题:容器日志无限增长会把磁盘撑满吗

不会自动清理,所以确实会。默认的日志驱动是 json-file,通常只按文件轮转规则来决定保留,如果没有配置上限,长期运行的容器就会不断写日志,最终把磁盘占满。

答案里要带两个配置:max-size和max-file。前者限制单个日志文件大小,后者限制文件数量。还可以补一句:最好在 daemon 层面统一配置日志轮转策略,而不是等容器启动后再手动处理。

另外可以提一嘴日志驱动:常用有json-file、journald、syslog。如果你们已经有统一日志平台,再用文件式日志去采就多了一层负担。

3.10 第十题:容器真的安全吗

这道题用来测试你有没有“敬畏心”。正确答案不是“安全”,也不是“不安全”,而是“安全边界比虚拟机薄”。

容器共享宿主机内核之后,本意是为隔离。安全上要做层层加固:进程用非 root 用户运行、文件系统挂为只读、删掉不需要的内核能力、必要时配合完整虚拟化做边界。能把这些说清楚,说明你真正在真实环境里考虑过风险,而不是只会开容器。

4. 常用指令按场景重排:能记住的才是好命令

命令不需要背,需要按场景反复用。我把最常见的用法整理成几组,每一条都带有它解决的问题。

4.1 镜像管理:拉取、构建、查看、删除

docker pull your-image:tag # 拉取镜像 docker images # 查看本地镜像列表 docker build -t myapp:v1 . # 根据 Dockerfile 构建并打标签 docker rmi your-image:tag # 删除镜像 docker history myapp:v1 # 查看镜像的分层构建过程

重点关注docker history,它能让你直观看到每一层是谁生成的、有多大。排查镜像体积和层缓存问题时非常有用。

4.2 容器生命周期:创建、运行、查状态、看日志

docker run -d --name web -p 8080:80 myapp:v1 docker ps # 只看运行中的容器 docker ps -a # 查看所有容器,含已停止 docker stop web docker start web docker restart web docker logs -f --tail 200 web # 持续跟踪日志,只看最后200行 docker exec -it web /bin/sh # 进入运行中容器的 shell docker rm -f web # 强制删除容器

run和create的区别也值得补充:create只创建容器,不立即启动;run实际是“创建+启动”一步到位。日常用run比较多,但理解拆分逻辑对故障排查有帮助。

4.3 网络操作:创建网络、挂到容器

docker network ls docker network create -d bridge my-net docker run -d --network my-net --name app1 myapp:v1 docker network connect my-net app2 docker network disconnect my-net app2

自定义 bridge 网络的最大好处,是容器间可以直接用名字通信。同一个网络里的容器,app1在连接app2:8080时,不需要查 IP,名字本身就是解析目标。

4.4 数据卷与清理:挂载、查看、回收空间

docker volume create>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询