Docker面试基础原理:从命名空间到镜像分层的核心问答
最近帮几位准备容器方向面试的朋友做模拟发现一个挺普遍的现象简历上都写着“熟悉 Docker”但问到镜像分层原理、容器和虚拟机的本质区别这类基础问题十有八九会卡壳。不是他们不努力是市面上的教程大多在教“怎么敲命令”很少讲“为什么这样设计”。而面试官恰恰最爱从这些“为什么”里判断你是真用过还是只会复制粘贴。这篇就把我在实际运维和面试别人时最常问的基础原理题整理一遍分成上下两篇的话这篇先聚焦核心原理和必问基础。1. 面试官问 Docker 原理到底想听什么1.1 从“Docker 是什么”看回答层次这道题基本是开场必问。初级回答是“Docker 是一个容器化平台可以把应用打包成镜像来运行”这个回答没有错但也没有信息量。面试官想听的其实是你能不能用一句话说清楚容器和虚拟机在隔离维度上的本质差异。我一般建议这样拆解Docker 是一种操作系统层面的虚拟化技术它利用 Linux 内核的命名空间Namespace做资源隔离利用控制组Cgroups做资源限制再配合联合文件系统UnionFS实现镜像分层存储。所以容器共享宿主机内核没有独立的操作系统内核这正是它比虚拟机轻量的根本原因。这里有个经常被追问的细节既然共享内核容器里执行uname -r看到的是宿主机内核版本这是正常的。所以凡是需要在容器里装一个“完整操作系统”或者依赖特定内核模块的场景容器就不是合适的选择别硬上。1.2 命名空间容器隔离的第一块基石关于命名空间面试官不要求你背全 8 类但至少要能说出最常见的几类并且知道它们各自隔离了什么。命名空间类型隔离内容对应面试常问场景Mount (mnt)文件系统挂载点容器里看到的文件系统和宿主机不同PID进程编号容器内 PID 1 是容器主进程看不到宿主机其他进程Network (net)网络栈网卡、路由、iptables每个容器有自己的 IP 和端口空间UTS主机名和域名容器 hostname 独立IPC进程间通信资源消息队列等隔离User用户和用户组 ID容器内 root 与宿主机 root 的映射关系这里我给一个记忆技巧把容器想象成一间带独立门窗的酒店房间。PID 命名空间让你看不到走廊里其他房间的人Mount 命名空间让你以为自己的衣柜就是全世界Network 命名空间给你独立的电话线和门牌号。面试时能打出这个比方再补一句“容器本质是宿主机上的普通进程只不过被这些命名空间‘包装’成了独立小世界”基本就过关了。需要注意的一个高频追问是既然 PID 命名空间隔离了进程为什么容器里ps aux有时还能看到其他进程这通常是因为容器镜像里安装了 procps 工具而/proc的挂载方式决定了进程信息的可见范围。实际排查中我用docker exec进容器看进程时基本都是用ps -ef如果看不到就考虑是不是 pid 命名空间或权限的问题而不是直接下结论说容器隔离失效。1.3 cgroups资源限额的幕后管家命名空间负责“隔离”cgroups 负责“限制”。面试题里最常见的问法是“怎么限制容器最多使用 1 核 CPU 和 512MB 内存”答案是用--cpus和--memory参数。比如docker run -d --name nginx-test --cpus1 --memory512m nginx:latest但面试官往往接着问这个限制是怎么生效的这里要答出 cgroups v2 的概念。在 Linux 系统中cgroups 通过虚拟文件系统暴露配置接口Docker 为每个容器创建一组控制文件写入对应的配额值后内核调度器和内存管理模块就会强制执行。我踩过的一个坑是--memory512m只限制内存如果容器内应用疯狂申请内存可能触发 OOM Kill。当时线上服务频繁重启排查到最后发现是容器内存配额给小了应用还没跑到峰值就被内核杀掉日志里出现 OOMKilled 关键字。后来我调整容量评估方式把 JVM 堆内存、元空间、线程栈全部算进去才消停。所以面试里提到内存限制时主动说出“内存配额需要评估应用真实峰值不能只看平均负载”会显得很有实战经验。2. 镜像与容器从“怎么构建”到“为什么这样构建”2.1 镜像是分层蛋糕容器是活的小蛋糕面试官常用一道题开刀“Docker 镜像和容器有什么区别”我习惯用蛋糕类比镜像是多层蛋糕的配方和冷冻成品每一层都是只读的容器是拿出来加热后正在吃的蛋糕。容器层是运行时可写的所有写入都发生在这一层。当你docker commit一个容器时容器层会被打包成新的镜像层但这样做出来的镜像无法完整保留容器运行时的状态比如网络连接、进程状态所以生产环境基本不会这么用而是用 Dockerfile 重新构建。这个“只读层 可写层”的模型衍生出一个高频题为什么同一个镜像启动多个容器磁盘占用不是成倍增长答案就是 Copy-on-Write写时复制机制。多个容器共享底层的只读镜像层只有写入新数据时才会在容器层复制出一个副本进行修改。这也是 Docker 能在一台机器上快速启动几十个容器的原因之一。2.2 Dockerfile 优化与镜像层缓存原理另一个经典问法是“你在生产环境怎么减少镜像体积”很多人第一反应是“用 alpine 版本”这没错但还不够。面试官想听到的是对层的理解Dockerfile 里每一条指令都会生成一个新的镜像层所以要把变化频率低的指令放前面、变化频率高的放后面尽可能复用构建缓存。举个实际例子我维护过一个 Node.js 项目原来的 Dockerfile 是这样的FROM node:18-alpine WORKDIR /app COPY . . RUN npm install CMD [npm, start]这个写法每次修改任何代码COPY . .后面那层缓存都得作废连带npm install也要重新跑构建特别慢。优化后的写法FROM node:18-alpine WORKDIR /app COPY package.json package-lock.json ./ RUN npm install --registryhttps://registry.npmmirror.com COPY . . CMD [npm, start]先复制依赖清单文件再装依赖最后才复制源代码。这样只要package.json不变npm install那层缓存就能命中构建速度能快好几倍。面试里补充这个细节同时点出“镜像层数不是越多越好层数过多会带来存储和传输开销所以 RUN 指令里可以用 合并多条命令”就能从“会写 Dockerfile”升级到“理解 Dockerfile”。2.3 容器退出后的状态与常见误区还有个基础题常被忽视“容器退出了镜像还在吗容器本身还在吗”答案是镜像一直在容器会变成 exited 状态并且仍然存在于磁盘上直到你显式删除。所以排查问题时不要只看docker ps要看docker ps -a。当时我帮一个同事排查 CI 构建失败的问题他反复说“容器明明跑起来了但结果显示失败”等我看了docker ps -a才发现容器启动几秒后就异常退出退出码是 127。后来定位到是镜像里缺少可执行文件的动态链接库。这类问题背后有一个常见的认知盲区容器的主进程是什么镜像是CMD [npm, start]启动的主进程就是 npm 的前台进程。很多人写启动脚本时不小心把脚本写成后台运行比如service nginx start这条命令执行完就返回了容器找不到前台进程立刻退出。面试可以主动说“容器必须有一个前台运行的进程才能保持存活后台进程无法维持容器生命期。”这一句能直接消除很多误解。3. 高频命令类问题别只背参数要答出设计逻辑3.1 run、start、restart 与 exec 的区分命令题是基础轮的重头戏。最常见的是docker run和docker start有什么区别看起来简单但答得好的不多。docker run 创建并启动一个新容器每次执行都会基于镜像创建全新的容器。docker start则是启动一个已经存在并且处于 exited 状态的容器不会重新创建。我见过有人把这两个搞混在脚本里用docker run去重试一个已经存在的容器结果报错Conflict. The container name is already in use直接把 CI 流程搞挂。另一个高频题是exec和attach的区别。attach是连接容器主进程的输入输出当主进程退出时attach 也会断开。exec是在容器内新开一个进程。所以日常调试我用 exec比如docker exec -it my-container /bin/sh这在容器没有被 SSH 服务的情况下是进入容器的标准姿势。这里补充一个面试加分点-it参数的实际意义。-i是保持标准输入打开-t是分配一个伪终端。如果只加-d后台运行不加-it你进容器执行交互式命令的时候会发现没有终端效果连上下翻历史都不行。我第一次调试的时候也栽在这儿。3.2 日志查看与排查命令的组合用法日志题几乎必考最简单的问法是“容器日志怎么查看”答案当然是docker logs -f --tail 200 container-name但面试官真正想听的是日志的底层由来。Docker 默认把容器内 PID 1 进程的标准输出和标准错误收集为日志由 json-file 日志驱动写到宿主机。也就是说容器内应用如果直接写日志文件比如写入/var/log/app.logdocker logs是看不到的。这是很多人排查日志时的第一个盲区。我之前排查过一个 Java 应用日志一直说存在磁盘占用异常但docker logs里只有少量输出。后来进容器里查才发现应用把所有日志写到了容器内的/logs目录而我没有给容器挂数据卷容器一删日志全没了。这个教训后来变成了我面试时主动分享的反面案例容器是“一次性”的应用日志必须交给 stdout 或挂载到宿主机目录否则删容器等于删日志。3.3 容器命名、标签与清理的规范命令题里还有一种考法docker rm、docker rmi、docker prune的区别。这是三个容易搞混的命令。docker rm删除容器docker rmi删除镜像docker system prune清理所有未被使用的资源。生产环境的典型操作是docker stop container-name docker rm container-name docker rmi image-name但实际生产里我会更推荐用docker compose down它会连网络和容器一起清理比手动一个个删安全得多。命名和标签的规范也是面试中的隐性考点。镜像 tag 不要用 latest因为 latest 不保证指向哪次构建回滚时很容易出问题。我维护的部署脚本里每个镜像都以版本号打 tag比如registry.example.com/app:20260115-1330再配合 git commit 缩短哈希作为辅助标识。容器命名则要能一眼看出服务和环境比如order-api-prod、redis-dev否则容器一多光靠 ID 操作非常容易误删。4. 网络模式容器通信绕不开的四个选项4.1 bridge 网络下的端口映射本质Docker 默认的网络模式是 bridge容器通过虚拟网桥连接宿主机对外用端口映射暴露服务典型命令是docker run -d -p 8080:80 nginx:latest这里的-p做了两层动作宿主机 8080 端口的流量转发到容器 80 端口同时 Docker 在宿主机上自动配置了一条 NAT 规则。面试官如果追问你可以说这底层是 iptables 的 DNAT 规则在起作用Docker 通过用户态代理进程docker-proxy和内核 NAT 规则协同实现端口转发。这里有个常见面试题为什么容器内服务监听 80 端口宿主机上访问 8080 能通而直接访问容器 IP 的 80 端口可能不通这是因为容器 IP 属于 Docker 内部虚拟网络从宿主机访问容器 IP 理论上可行但从外部机器访问必须通过宿主机端口映射。跨主机访问容器 IP 更是行不通除非你配置了 overlay 网络。回答时点出“默认 bridge 网络只能在单机内部通信”就能带出下一轮关于跨主机网络的讨论。4.2 host 模式的代价与适用场景host 模式是另一张常考牌。它让容器直接使用宿主机网络栈没有独立的网络命名空间所以-p参数会被忽略容器内监听的端口会直接绑定到宿主机。这样网络性能损耗极小但代价是端口冲突由你负责管理。有一次我在一台已跑着 MySQL 的服务器上启动一个 host 模式的服务容器监听 3306 直接起不来这是因为宿主机的 3306 已经被占用了。排查半天才发现是端口冲突而不是镜像的问题。所以 host 模式适合对网络性能要求高、且端口规划清晰的场景比如一些需要高吞吐的中间件容器。但在生产环境里我一般还是优先用 bridge 端口映射来获得网段隔离和网络策略控制。4.3 跨容器通信与容器间 DNS 解析跨容器通信最常见的做法是自定义 bridge 网络。默认的 bridge 网络虽然也提供通信但不支持容器名 DNS 解析。两个容器在同一个自定义 network 里可以直接用容器名互相访问docker network create my-net docker run -d --name app-db --network my-net mysql:8.0 docker run -d --name app-backend --network my-net myapp:latest这样app-backend里连接数据库时直接写jdbc:mysql://app-db:3306/mydb就能通。这依赖的是 Docker 内置的 DNS 服务它会在容器启动时根据容器名自动注册解析记录。使用自定义网络时不需要在代码里硬编码 IP因为容器重建后 IP 会变化但容器名可以保持稳定。这个知识点在 Docker Compose 环境下尤其重要。Compose 默认会为每个项目创建一个独立网络服务名就是容器名服务之间直接通过服务名互相调用。回答这里时顺手提一句“容器应视为一次性资源不要依赖 IP”面试官会觉得你的设计经验到位了。5. 数据持久化面试必问 Volume 的底层逻辑5.1 容器为什么不“自带”持久化容器文件系统层的生命周期和容器绑定容器删除后容器层的写入全部丢失。这不是缺陷而是设计使然容器的设计哲学是“不可变基础设施”应用代码和依赖打包在镜像里运行时产生的数据放外面。面试题到这里一般会问Docker 提供了哪几种数据持久化方式标准答案有三种Volume卷、Bind mount绑定挂载、tmpfs mount内存临时挂载。方式存储位置典型场景注意点VolumeDocker 管理目录数据库数据、应用上传文件推荐优先使用Bind mount宿主机任意目录开发热更新、日志目录路径写错会直接覆盖目录tmpfs内存临时缓存、敏感信息容器重启后数据消失5.2 Volume 和 Bind mount 的使用边界Volume 是 Docker 官方推荐的持久化方案因为它由 Docker 管理迁移备份方便。创建卷docker volume create my-app-data docker run -d -v my-app-data:/data myapp:latest用力简单说volume 里的数据不删卷就不会丢。我遇到过一个生产宕机后的恢复场景因为数据库容器的数据放在命名卷里即使容器被误删只要卷还在重新起一个容器挂载同名卷数据就完好无损。Bind mount 则是把宿主机目录直接映射进容器docker run -d -v /opt/app/config:/app/config myapp:latest它最大的坑是如果宿主机目录不存在Docker 会自动创建一个空目录这是很多版本的默认行为这就导致容器里原来镜像目录里已有的文件会被空目录“覆盖”。我踩过最惨的一次是把宿主机空目录 bind 到容器/etc/nginx/conf.dNginx 直接找不到任何站点配置客户端全部 502。所以用 bind mount 前务必先确认宿主机路径真实存在并且内容完整。5.3 文件权限问题容器用户与宿主机用户的博弈持久化场景里文件权限问题几乎必然出现。容器内默认以 root 或镜像指定用户如 UID 1000运行挂载卷的目录所有者如果是宿主机某个用户容器内进程可能没有写权限。我常用的解法是在 Dockerfile 里显式指定用户和组使容器内 UID 和宿主机保持一致RUN groupadd -g 1000 appuser useradd -u 1000 -g appuser appuser USER appuser这样容器内创建的文件的属主 UID 就是 1000宿主机上 UID 1000 的用户可以正常访问。如果是临时跑一个容器可以直接用-u参数指定 UIDdocker run -u $(id -u):$(id -g) -v /data:/data myapp:latest这个命令在开发环境里很实用但生产环境还是要规范镜像的用户配置。面试里能讲清楚“容器内 root 不等于宿主机 root但默认映射时特权边界很模糊”会是个不错的加分点。6. 资源限制与稳定性从面试题到生产经验6.1 内存限制引发的 OOM 排查Docker 对容器的内存限制通过 OOM 机制强制实施。当容器使用内存超过--memory限制时内核会杀掉容器内最耗内存的进程。这里有一个容易混淆的概念--memory是硬限制容器内进程超了就被杀--memory-swap则是内存加 swap 的总限制默认情况下等于两倍内存也就是允许用到 swap。我排查过一个非常典型的服务无响应问题。当时监控面板显示容器还在运行但外部请求完全超时。登录宿主机一看发现容器处于 OOMKilled 状态过几秒又自动重启循环往复。查了docker inspect里的OOMKilled字段才确认是内存配额不足。后来我把服务的 JVM 参数重新评估把堆内存从 2G 调到 1.5G同时把容器内存上限从 2G 提到 4G预留出线程栈、元空间和 native 内存的余量问题才稳定下来。6.2 CPU 限制的真正含义CPU 的--cpus参数限制的是 CPU 时间配额。比如--cpus1.5表示容器最多使用 1.5 个 CPU 核心的时间片而不是只能使用 1.5 个物理核心。这是基于 CFS 调度器配合 CPU 配额实现的具体是通过 cpu.cfs_quota_us 和 cpu.cfs_period_us 两个参数控制。有一次我性能压测容器内应用用 C 语言写了个纯计算任务理论上能用满 8 核的 25%但实测只有不到 12%。后来发现是宿主机上其他容器的 CPU 限制干扰还有一个原因是容器内部的多线程应用没有感知到 CPU 配额Golang 的 runtime 默认认为宿主机的核数很多创建了大量线程反而增加了调度开销。解决方式是让应用感知容器 CPU 限额比如设置 GOMAXPROCS或者运行时根据实际配额动态调整。面试里提到这个“容器内看到的 CPU 数和实际配额不一致”的坑会让面试官眼前一亮。6.3 重启策略自动恢复还是隐藏故障Docker 的重启策略有 no、on-failure、unless-stopped、always 四种。很多人图省事直接--restartalways但这样有一个隐患如果容器因为代码 bug 崩溃always 会不断重启它造成“看起来在运行、实际上反复崩溃”的假象。我建议生产环境里根据服务类型选择策略需要开机自启且必须保持运行的服务unless-stopped希望在异常退出后自动重试的批处理任务on-failure:3无状态 API 服务配合编排平台用平台的重启机制这里要特别说一个容易踩的坑--restartalways不会因为手动 stop 而停止自动重启逻辑。如果你手动docker stop了容器之后 Docker 服务如果重启容器会被自动拉起来这可能不是你想要的。所以当你想彻底停掉一个服务时最好先docker update --restartno再 stop或者直接用编排系统控制副本数为 0。7. 镜像加速与安装问题高频踩坑排查实录7.1 镜像下载慢的常见解法镜像拉取慢是几乎每个刚入门的开发者都会遇到的痛点。Docker 默认从官方镜像仓库拉取国内网络的访问体验通常不稳定。常见的解法是配置镜像加速器把镜像仓库地址替换为可用的加速器地址。修改 Docker 守护进程配置以 Linux 为例编辑/etc/docker/daemon.json{ registry-mirrors: [https://your-mirror-address] }然后重启 Dockersudo systemctl daemon-reload sudo systemctl restart docker如果你使用 Docker Desktop可以直接在设置界面的 Docker Engine 配置里填同样的 JSON它会自动应用并重启。这里的核心原理是Docker 拉镜像时先访问 registry-mirrors 里配置的加速器加速器作为镜像仓库的反向代理把镜像文件从上游拉下来缓存再转发给本机。由于加速器通常有更优的网络链路拉取速度会快很多。但要注意一点镜像加速器只对 Docker Hub 官方镜像有效。如果拉取的是某个私有仓库或第三方仓库的镜像比如registry.example.com/myapp:latest加速器是不起作用的。还有一个小技巧镜像名带版本 tag 要比拉 latest 快很多因为 latest 的 manifest 不会缓存命中需要重新回源查询。我在服务器上初始化环境时都会先把常用的基础镜像如 alpine、node、mysql 固定版本号提前拉一遍避免现场拉取耽误时间。7.2 Windows 上 Docker Desktop 启动失败排查Windows 环境里Docker Desktop 启动失败是一个高频问题常见报错是 “Docker Desktop failed to start because virtualization support wasnt detected” 或 “virtualization support not detected”。这通常意味着你的电脑没有开启硬件虚拟化。排查链路并不复杂确认 CPU 是否支持并已开启虚拟化。打开任务管理器切到性能页签点击 CPU查看虚拟化状态是否为“已启用”。如果显示“已禁用”需要进 BIOS 开启 Intel VT-x 或 AMD SVM。确认 Windows 的 Hyper-V 或 Windows 虚拟机监控程序平台是否已启用。在“启用或关闭 Windows 功能”里勾选“Hyper-V”和“虚拟机平台”然后重启系统。如果使用 Workstation 或 VirtualBox 等虚拟化软件要注意这类软件和 Hyper-V 存在冲突。Docker Desktop 依赖 Hyper-V 或 WSL 2 后端和某些虚拟化软件同时启用时会互相抢虚拟化资源导致启动失败。这种情况关闭其中一个即可。我在实际帮别人排查时最常碰到的原因其实是 BIOS 里虚拟化开关没开。品牌机出厂默认关闭很常见尤其是办公机型。这个排查流程本身也适合写进面试答案里因为面试官可能会问“如果 Docker 服务启动失败你的排查顺序是什么”能说出“先看虚拟化开关再看系统组件再看服务日志”这种链路说明你有真实排障经验。7.3 权限问题permission denied 怎么解Linux 环境下连接 Docker 守护进程报permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock是新手高频问题原因是当前用户不在 docker 用户组里。标准解法是sudo usermod -aG docker $USER newgrp docker这里有两个点需要特别交代。第一加入 docker 用户组意味着该用户拥有等同于 root 的权限因为 docker 组用户可以操控所有容器和镜像甚至可以挂载宿主机目录到容器里读取任意文件。所以生产服务器上不要把普通业务账号随便加进 docker 组更不要把 docker 套接字暴露到非信任网络。第二如果你已经在 docker 组里但还是报权限错检查一下 Docker 服务是否在运行sudo systemctl status docker服务没启动时docker ps也会报类似的连接错误很多人误以为是权限问题白白改了一通。还有一个特殊情况是 SElinux 或 AppArmor 策略导致的权限失败这类问题在新装的系统上容易出现。遇到时可以先临时把 SElinux 设为 permissive 模式验证一下sudo setenforce 0 docker run hello-world如果这样就通了那就说明是策略拦截需要去配置对应的容器策略文件而不是长期关闭 SElinux。这个排查思路比一上来就setenforce 0要稳妥得多。8. 面试中的实战加分从命令操作到架构思维8.1 会 docker inspect 的人排障快一倍很多候选人知道docker ps、docker logs但很少主动提docker inspect。这个东西是排障神器它可以返回容器的完整配置信息和运行时状态包括挂载、网络、环境变量、资源限制、重启次数、健康检查状态等。实际排查时我最常用的几个 inspect 查询# 查看挂载卷 docker inspect -f {{json .Mounts}} container-name # 查看环境变量 docker inspect -f {{json .Config.Env}} container-name # 查看重启次数 docker inspect -f {{.RestartCount}} container-name # 查看端口映射 docker inspect -f {{json .NetworkSettings.Ports}} container-name尤其在检查容器启动几次失败这种场景RestartCount一看便知。有一次线上容器反复重启人肉看日志根本来不及我用docker inspect -f {{.RestartCount}}确认了重启次数在持续增加又通过docker logs --since 5m和docker inspect的State.OOMKilled字段锁定了内存超限整个排查过程不到十分钟。面试时能脱口而出docker inspect的常用查询方式比单纯背命令要有说服力得多这说明你真的在生产环境里用过它定位问题。8.2 Docker Compose多容器编排的基本功现在的招聘 JD 里基本都要求 Docker Compose。面试官常问什么时候该用 Compose它和直接敲 docker run 有什么区别我的回答是Compose 的价值在于用声明式配置取代手工命令把多个相关联容器的定义、依赖、网络、卷统一管理在一个 YAML 文件里。最简单的例子services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass volumes: - db-data:/var/lib/mysql networks: - backend app: build: . ports: - 8080:8080 depends_on: - db networks: - backend volumes: db-data: networks: backend:这一套配置解决了三个问题服务间怎么互联通过 network、数据怎么持久化通过 volume、启动顺序怎么控制depends_on。尤其要注意depends_on只控制启动顺序不代表依赖服务已经完全可用。如果 app 启动后立刻连数据库而数据库还在初始化连接失败就会导致 app 退出重试。生产做法通常是给 app 加健康检查和重试逻辑或者等 db 的 healthcheck 通过后再启动。Compose 里另一个高频坑是环境变量覆盖。YAML 里写死密码是安全问题推荐用env_file或宿主机环境变量注入。我在面试里经常提到一点Compose 项目应该作为“可复制的基础设施”来管理配置文件不用改代码逻辑就能在不同环境间迁移这才叫编排而不是简单地把几个 docker run 拼在一起。8.3 容器健康检查让服务状态“可信”最后一个基础但常被低估的知识点是健康检查。很多人启动容器后只看STATUS是不是Up但Up只代表进程在跑不代表服务真的可用。类似“进程是活的但消息队列连不上”的情况很常见容器明明是 Up但对外表现已经是一个废人了。标准方案是定义 HEALTHCHECKHEALTHCHECK --interval30s --timeout3s --start-period5s --retries3 \ CMD curl -f http://localhost:8080/health || exit 1或者在使用 Compose 时在服务里配置services: app: image: myapp:latest healthcheck: test: [CMD, curl, -f, http://localhost:8080/health] interval: 30s timeout: 3s retries: 3配置之后docker ps的 STATUS 列会从 Up 变成 Up (healthy)调度平台也会拿这个状态来决定何时重启服务。这个知识点虽然不难但能把“关注服务可用性”的工程意识体现出来比我见过很多单纯看 STATUS 的新人强得多。9. 面试应答技巧怎样把知识组织成“答案链”9.1 先说结论再补细节面试和写文档不一样面试官时间有限更希望你在第一句就给出核心结论。比如问到“容器和虚拟机有什么区别”不要从 Docker 的发展历史开始讲直接说“容器共享宿主机内核虚拟机有独立内核容器隔离靠内核的 Namespace 和 Cgroups虚拟机靠 Hypervisor 虚拟化硬件”。然后再展开细节因为共享内核容器更轻量、启动更快但隔离性也比虚拟机弱如果业务需要强隔离或者运行异构操作系统还是得用虚拟机。这种“结论—原因—延伸”的结构在面试里非常讨喜。9.2 主动给“为什么”不要等追问基础问题如果只答“是”或“不是”很难让面试官看到你的思考深度。比如问到“端口映射怎么实现的”不要说“就是 -p 8080:80”而是补一句“它底层是 Docker 在宿主机上配置 iptables 的 DNAT 规则将宿主机端口的流量转发到容器 IP 和端口上同时 docker-proxy 也参与转发”。当你能说出“为什么”面试官就会觉得你不只是用过命令而是理解了系统的工作方式。这也是我在实际带团队时更看重的素质。9.3 承认边界比硬编答案更可信最后一条建议遇到不确定的细节直接承认自己没实操过然后给出你的推断和验证思路。面试最怕的是编造生产经验和命令行参数。比如有人被问到“跨主机容器通信怎么做”如果没接触过 overlay 网络可以诚实地说“我主要做单机多容器的编排跨主机场景我了解可以用 Swarm 或 Kubernetes 的方案但没在生产环境实际配过。如果我要去落地我第一步会先用 Docker 的 overlay 网络在测试环境搭一个小集群验证一下。”这比给一个错的答案好得多。面试不是考背诵而是考察你解决问题的能力和思维的完整性。这些基础题的底层逻辑其实就是一句话理解容器的设计哲学比记住命令参数更重要。像命名空间和 cgroups 解决的是“隔离与限制”镜像分层解决的是“构建与分发”Volume 解决的是“生命周期与持久化”端口映射和网络模式解决的是“对外通讯”。把这几条主线串起来面试官问什么基础题你都能绕回这个框架里去答既清晰又有深度。下一篇我准备把镜像构建优化、容器排错实战、和 Kubernetes 关联的高频题继续拆开聊到时候见。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →