【容器原理与架构】

Q1. 请描述 docker run 背后的完整执行链路。 ⭐⭐

预期回答:CLI → dockerd → containerd → shim → runc → kernel (Namespace/Cgroups)

追问1:containerd-shim 的作用是什么?为什么不能让 dockerd 直接管理容器进程?

containerd-shim 的核心作用是 解耦容器生命周期与 daemon。它作为容器进程的父进程(PPID),接管 stdio、信号和退出状态。若 dockerd 崩溃或重启,shim 仍存活,容器不会被 kill。若由 dockerd 直接 fork 容器,daemon 重启会导致容器成为孤儿进程,被 init 回收。


追问2:runc 启动后就退出了,容器进程如何保持运行?其父 PID 是多少?

runc 在调用 exec 后即退出。容器主进程由 containerd-shim 接管,因此其父 PID(PPID)是 shim 进程的 PID。可通过 ps -o ppid= -p <container-pid> 验证。


追问3:如果 dockerd 崩溃重启,正在运行的容器会受影响吗?为什么?

不会。因为容器进程由 containerd-shim 托管,而 containerd 本身也设计为高可用组件。Docker 20.10+ 默认启用 live-restore 模式,即使 dockerd 重启,容器网络和进程均不受影响。


Q2. 什么是 OCI 规范?Docker 与它的关系是什么? ⭐⭐

预期回答:OCI = Open Container Initiative,包含 Image Spec / Runtime Spec / Distribution Spec;Docker 是贡献者和兼容实现

追问1:如何验证一个镜像是 OCI 格式而非旧 Docker v2 Schema?

使用 crane manifest <image>skopeo inspect --raw docker://<image> 查看 manifest 的 mediaType

  • OCI:application/vnd.oci.image.manifest.v1+json
  • Docker v2 Schema 2:application/vnd.docker.distribution.manifest.v2+json


追问2:BuildKit 默认生成的是 Docker Image Spec 还是 OCI Image Spec?

BuildKit 默认输出 OCI 格式。可通过 --output type=oci,dest=image.tar 显式指定,但即使不指定,推送到兼容 Registry(如 Harbor 2.0+)也会自动转为 OCI。


追问3:能否用非 Docker 工具(如 crane)拉取并运行 OCI 镜像?如何操作?

可以。例如:

# 拉取 OCI 镜像
skopeo copy docker://nginx:alpine oci:nginx-oci

# 用 runc 运行(需先解压 rootfs)
umoci unpack --image nginx-oci:latest bundle
runc run mynginx

Q3. runc 是什么?它和 containerd 的职责边界在哪里? ⭐⭐⭐

预期回答:runc 是 OCI Runtime 实现,负责创建容器进程;containerd 负责生命周期管理、镜像、任务调度

追问1:runc 是否常驻内存?它如何接收启动指令?

runc 是 一次性 CLI 工具,不常驻内存。它通过命令行参数接收指令(如 runc run <id>),配置来自当前目录的 config.json


追问2:如何用纯 runc(无 Docker/containerd)运行一个容器?请写出步骤。

mkdir myctr && cd myctr
mkdir rootfs
docker export $(docker create alpine) | tar -C rootfs -xvf -
runc spec  # 生成 config.json
sudo runc run myctr


追问3:Kubernetes 中 kubelet 如何调用 runc?中间经过哪些组件?

kubelet → CRI(gRPC)→ containerd → containerd-shim → runc。containerd 作为 CRI 实现,将 PodSpec 转为 OCI config,再调用 runc 创建容器。


Q4. 为什么说“容器只是一个受限制的 Linux 进程”? ⭐⭐

预期回答:容器本质是普通进程,通过 Namespace 隔离视图、Cgroups 限制资源、Capabilities 控制权限

追问1:如何在宿主机上找到某个容器的主进程 PID?

docker inspect <container> --format='{{.State.Pid}}'
# 或
cat /proc/$(pgrep -f "containerd-shim.*<container>")/children


追问2:该进程的 /proc/<pid>/ns/ 目录下有哪些文件?分别代表什么?

常见文件:pid, net, mnt, uts, ipc, user, cgroup。每个符号链接指向内核 namespace inode,如 net -> net:[4026532345]


追问3:能否让两个容器共享同一个 PID Namespace?如何实现?

可以。使用 --pid=container:<other-container-id>。Kubernetes 中通过 shareProcessNamespace: true 实现 Pod 内共享。


【Namespace 隔离机制】

Q5. User Namespace 如何提升容器安全性? ⭐⭐⭐

预期回答:实现 UID/GID 映射,容器内 root ≠ 宿主机 root,防止逃逸提权

追问1:Docker 在 Linux 上默认启用 User Namespace 吗?如何开启?

默认不启用。需在 /etc/docker/daemon.json 中配置:

{
  "userns-remap": "default"
}


追问2:启用后,容器挂载宿主机目录(-v)会出现什么问题?如何解决?

权限错乱。因容器内 UID 0 映射为宿主机 UID 165536,无法访问宿主机属主为 root 的文件。
解决方案

  • 使用 idmapped mounts(Linux 5.12+)
  • 或 docker run --user $(id -u):$(id -g)


追问3:Kubernetes 支持 User Namespace 吗?当前社区进展如何?

尚未 GA。社区通过 KEP-127 推进,目前需手动配置且多租户场景复杂。


Q6. PID Namespace 嵌套有什么实际用途? ⭐⭐

预期回答:用于调试(nsenter)、构建沙箱(BuildKit)、多租户隔离

追问1:如何查看当前进程处于哪一层 PID Namespace?

递归读取 /proc/<pid>/ns/pid 的 inode 号,直到与 init 进程(PID 1)相同。


追问2:最大嵌套深度由哪个内核参数控制?

kernel.pid_max 控制最大 PID 数,但嵌套深度实际受限于 max_user_namespaces(默认 0 表示无限制,部分发行版设为 1024)。


追问3:在 Kubernetes Pod 中,initContainer 和主容器是否共享 PID Namespace?如何配置?

默认不共享。需在 PodSpec 中显式设置 shareProcessNamespace: true 才共享。


Q7. Mount Namespace 的核心作用是什么? ⭐⭐

预期回答:隔离文件系统挂载点,使容器拥有独立的 //proc/sys 等视图

追问1:为什么容器内的 /proc 是虚拟的?直接挂载宿主机 /proc 有何风险?

Mount Namespace 隔离了 /proc 挂载点,容器看到的是 仅包含自身进程的 procfs。若挂载宿主机 /proc,可查看所有进程,导致信息泄露。


追问2:如何让容器看到宿主机的真实 /proc?什么场景需要这样做?

docker run -v /proc:/host/proc:ro ...


追问3--privileged 模式会禁用哪些 Namespace?为什么危险?

不会禁用,而是 加入宿主机的所有 Namespace(等效于 --net=host --pid=host --ipc=host 等),并授予所有 Capabilities,极度危险。


【Cgroups 资源控制】

Q8. Cgroup v2 相比 v1 有哪些关键改进? ⭐⭐⭐

预期回答:统一单棵树、memory.low/min/max、PSI 原生支持、接口语义一致

追问1:Docker 如何指定使用 Cgroup v2?需满足哪些条件?

无需指定。只要宿主机启用 Cgroup v2(内核参数 systemd.unified_cgroup_hierarchy=1),Docker 20.10+ 自动适配。


追问2memory.reservation 对应 Cgroup v2 中的哪个参数?

对应 memory.low(软保护),不是硬限制。


追问3:能否用 Cgroup v2 限制容器对特定磁盘的 IOPS?Docker CLI 支持吗?

内核支持(通过 io.max),但 Docker CLI 不暴露该参数。需手动写入 cgroup 文件或通过 Kubernetes device plugins 实现。


Q9. 如何利用 PSI(Pressure Stall Information)监控容器资源争用? ⭐⭐⭐

预期回答:读取 /sys/fs/cgroup/.../memory.pressure,解析 some/full 指标

追问1some avg10=20.0 表示什么含义?

过去 10 秒内,至少有一个任务因内存不足而阻塞的时间占比为 20%。


追问2:Prometheus 如何采集 PSI 数据?需要什么 Exporter?

使用 node_exporter(v1.4+)自动暴露 node_cgroup_psi 指标,无需额外配置。


追问3:应用如何根据 PSI 实现自适应降级?举例说明。

应用定期读取 /sys/fs/cgroup/memory.pressure,若 some > 阈值,则关闭缓存、降低并发等。例如 Redis 可动态调整 maxmemory


Q10. 容器 OOM 时,是 kill 整个容器还是单个进程? ⭐⭐

预期回答:kill 整个 cgroup(即整个容器),因为所有进程属于同一 memory cgroup

追问1:如何避免关键进程被误杀?Cgroup v2 提供了什么机制?


Cgroup v2 提供 memory.oom.group:设为 1 时,OOM killer 会 kill 整个 cgroup;设为 0 时可单独 kill 进程(需配合 oom_score_adj)。

追问2:memory.oom.group 作用?


控制 OOM killer 粒度:1 = 整组 kill(默认),0 = 允许单进程 kill。

追问3:OOM 日志在哪里查看?如何关联到具体容器?
  • 内核日志:dmesg | grep -i "killed process"
  • systemd journal:journalctl -k --grep=oom
  • 关联容器:通过 PID 或 cgroup 路径反查


【镜像与存储】

Q11. Docker 镜像为什么采用分层设计? ⭐⭐

预期回答:节省存储、加速构建/拉取、支持镜像复用

追问1:两个基于相同 base 镜像的容器,是否共享底层 layer?


。只读层(lowerdir)由所有基于该镜像的容器共享,节省存储和内存(page cache 复用)。

追问2:删除镜像某一层后,依赖该层的其他镜像会怎样?

Docker 采用 引用计数,只有当所有镜像都不引用该层时才真正删除。否则保留。
追问3:如何查看镜像各层大小?推荐工具?

docker history <image>
# 或使用第三方工具
dive <image>


Q12. OverlayFS 如何实现“写时复制”(Copy-on-Write)? ⭐⭐⭐

预期回答:lowerdir(只读)+ upperdir(可写)+ merged(联合视图);首次修改触发 copy-up

追问1:删除大文件后磁盘空间会释放吗?


不会立即释放。OverlayFS 仅在 upperdir 创建 whiteout 文件(.wh.filename),原始数据仍在 lowerdir。

追问2:whiteout (.wh.*)的作用是什么?


标记“该文件已被删除”,使 merged 视图中不可见。

追问3:如何避免 因频繁写入导致 upperdir 膨胀?

  • 使用 --tmpfs 存放临时数据
  • 定期重建镜像(CI 中清理中间层)
  • 避免在容器内频繁写入大文件


Q13. EROFS 作为存储驱动有何优势?适用场景? ⭐⭐

预期回答:只读压缩、节省 50% 存储、启动快 40%,适用于 immutable workload

追问1:EROFS 能否作为 OverlayFS 的 upperdir?为什么?


不能。EROFS 是只读文件系统,只能作 OverlayFS 的 lowerdir。

追问2:哪些云厂商使用 EROFS?


阿里云 ACK Edge、华为云 CCE Turbo、AWS Bottlerocket OS。

追问3:如何构建 EROFS 镜像层?


使用 mkfs.erofs 工具打包目录,再作为 OCI layer 推送(需自定义 builder)。


【安全与合规】

Q14. CVE-2019-5736 漏洞原理及修复方案? ⭐⭐⭐

预期回答:通过 /proc/self/exe 覆盖 runc 二进制;修复:memfd_create() + User Namespace

追问1:memfd_create() 如何防止文件覆盖?


将 runc 二进制复制到匿名内存 fd(无文件路径),攻击者无法通过 /proc/self/exe 覆盖。

追问2:Rootless Docker 模式是否免疫此漏洞?为什么?


。因以非 root 用户运行,容器内进程无权写宿主机任何文件。

追问3:除了 runc 修复,还有哪些纵深防御措施?

  • 启用 User Namespace
  • --read-only 根文件系统
  • drop ALL capabilities
  • AppArmor/SELinux 策略


Q15. 如何实现容器的最小权限原则? ⭐⭐

预期回答:非 root 用户、drop capabilities、只读根文件系统、seccomp、AppArmor

追问1:--cap-drop=ALL 为何导致 ping 失败?


ping 需要 CAP_NET_RAW 发送 raw socket。解决:--cap-add=NET_RAW 或改用 HTTP 健康检查。

追问2:如何自定义 seccomp profile?

# seccomp.json
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "syscalls": [{"names": ["open", "read", "write"], "action": "SCMP_ACT_ALLOW"}]
}
docker run --security-opt seccomp=./seccomp.json ...
追问3:AppArmor 和 SELinux 能同时启用吗?


不能。Linux LSM 框架一次只允许一个模块生效(除非使用 stacking,但 Docker 不支持)。


Q16. SBOM 如何防止供应链攻击? ⭐⭐⭐

预期回答:SBOM 列出组件清单,通过 Sigstore 签名,部署前验证完整性

追问1:如何为 Docker 镜像生成 SBOM?推荐工具?

syft nginx:alpine -o spdx-json > sbom.json
追问2:cosign 如何将 SBOM 附加为 OCI Artifact?

cosign attach sbom --sbom sbom.json nginx:alpine
追问3:Kubernetes 如何在 admission 阶段验证 SBOM 签名?


通过 admission controller(如 Kyverno + cosign)在 Pod 创建前验证 OCI Artifact 签名。


【网络与通信】

Q17. Docker 默认 bridge 网络的工作原理? ⭐⭐

预期回答:docker0 网桥 + veth pair + iptables SNAT/DNAT

追问1:容器间通信是否经过 iptables?如何优化性能?


同一网桥内不经过(走二层),跨网桥或出站需 SNAT/DNAT。

追问2:为什么 --link 已被废弃?替代方案是什么?


因依赖环境变量注入,破坏不可变性;现用 自定义 bridge 网络 + DNS 解析 替代。

追问3:如何让容器直接使用宿主机网络栈?有何风险?


docker run --network=host风险:端口冲突、安全边界消失。


Q18. eBPF 如何替代 iptables 实现容器网络策略? ⭐⭐⭐

预期回答:eBPF 程序挂载到 TC 或 XDP 层,实现无 iptables 的 L3/L4 策略(如 Cilium)

追问1:eBPF 性能提升多少?


Cilium 测试显示:吞吐提升 2–3 倍,延迟降低 50%,CPU 占用减少 40%。

追问2:Docker 原生支持 eBPF 吗?


不支持。需通过 CNI 插件(如 Cilium、Calico eBPF mode)实现。

追问3:如何用 bpftrace 跟踪容器网络包?

bpftrace -e 'tracepoint:net:netif_receive_skb { printf("pkt from %s\n", comm); }'


【日志与监控】

Q19. Docker 容器日志默认存储在哪里?如何轮转? ⭐⭐

预期回答/var/lib/docker/containers/<id>/<id>-json.log;通过 log-driver 配置轮转

追问1:如何限制 json-file 日志大小?

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
追问2:如何发送日志到 Loki?


使用 loki-docker-driver 或 Fluentd/Vector sidecar。

追问3:shim 如何处理 stdout/stderr?


shim 将容器进程的 stdout/stderr 重定向到 FIFO 或日志文件,并转发给 containerd。


【排错与调试】

Q20. 容器启动失败,如何快速定位原因? ⭐⭐

预期回答docker logsdocker inspect → 查看 exit code → 检查 cgroup OOM / seccomp deny

追问1:如何进入已退出容器调试?

# 获取容器 rootfs 路径
docker inspect <container> | grep MergedDir
# chroot 进入(需 root)
chroot /var/lib/docker/overlay2/.../merged /bin/sh
追问2:seccomp 拦截日志在哪?


需开启 audit:auditctl -a always,exit -F arch=b64 -S ...,日志在 /var/log/audit/audit.log

追问3:如何用 strace 跟踪容器进程?

strace -p $(docker inspect -f '{{.State.Pid}}' <container>)


【Build 与 CI/CD】

Q21. BuildKit 相比传统 builder 有哪些优势? ⭐⭐⭐

预期回答:并行构建、远程缓存、secret mount、更小镜像、语法扩展(# syntax=docker/dockerfile:1.4)

追问1:如何启用 BuildKit?

export DOCKER_BUILDKIT=1
# 或 daemon.json
{ "features": { "buildkit": true } }
追问2:如何配置远程缓存?

docker build --build-arg BUILDKIT_INLINE_CACHE=1 \
  --cache-from type=registry,ref=user/app:cache \
  --cache-to type=registry,ref=user/app:cache .
追问3:--mount=type=secret 如何避免 secrets 泄露到镜像层?


secret 通过 tmpfs 挂载到构建上下文,不会写入任何 layer,构建结束后自动销毁。


Q22. 多阶段构建(multi-stage build)的原理和好处? ⭐⭐

预期回答:在一个 Dockerfile 中定义多个 FROM,仅复制最终产物,减少镜像体积

追问1:如何从 builder 阶段复制文件?
✅ 答:

COPY --from=builder /app/bin/myapp /usr/local/bin/


追问2:能否跨 Dockerfile 共享缓存?
✅ 答:

不能直接共享,但可通过远程缓存(--cache-from)复用。

追问3:Go 多阶段构建最佳实践?
✅ 答:

FROM golang:1.23 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .

FROM gcr.io/distroless/static
COPY --from=builder /app/myapp /myapp
ENTRYPOINT ["/myapp"]

追问1:如何从 builder 阶段复制文件?语法?
追问2:能否跨 Dockerfile 共享构建缓存?如何实现?
追问3:Go 应用多阶段构建的最佳实践?


Q23. Docker Compose v2 与 v1 的主要区别? ⭐

预期回答:Compose v2(Go 重写)性能更高、支持 profiles、与 containerd 深度集成;v1(Python)已弃用

追问1:Compose 文件中的 deploy 字段在非 Swarm 模式下生效吗?
不生效deploy 仅用于 Docker Swarm 或 Kubernetes(通过 Compose on K8s),本地 docker compose up 会忽略该字段。

追问2:如何用 Compose 实现健康检查和服务依赖?

services:
  web:
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 3

追问3:Compose 是否支持 secrets 和 configs?如何管理?

  • 本地模式:通过文件挂载模拟 secrets(secrets: + file:
  • Swarm 模式:原生支持加密 secrets 和 configs
  • 示例:
    secrets:
      db_password:
        file: ./db.pass
    services:
      app:
        secrets:
          - db_password

Q24. Rootless Docker 的工作原理和限制? ⭐⭐⭐

预期回答:以普通用户运行 dockerd,利用 User Namespace + slirp4netns 实现隔离,无需 root 权限

追问1:Rootless 模式下如何访问 privileged 端口(<1024)?
无法直接绑定。解决方案:

  • 使用端口转发(如 socat TCP-LISTEN:80,fork TCP:localhost:8080
  • 或配置 net.ipv4.ip_unprivileged_port_start=0(需 root 设置)

追问2:能否在 Rootless 模式下使用 --device
有限支持。只能访问当前用户有权限的设备(如 /dev/dri),且需手动配置 cgroup delegation。

追问3:Rootless 是否支持 Cgroup v2?如何配置?
支持,且推荐。需启用 cgroup delegation:

systemctl --user edit docker
# 添加:
[Service]
Delegate=cpu io memory pids

Q25. Docker 为何被 Kubernetes 弃用?现在用什么? ⭐⭐

预期回答:Docker 不符合 CRI 标准;K8s 从 v1.24 起移除 dockershim,改用 containerd 或 CRI-O

追问1:dockershim 是什么?何时被移除?
:dockershim 是 K8s 中将 CRI 请求转为 Docker API 的适配层;v1.24(2022年5月)正式移除

追问2:containerd 如何同时支持 Docker CLI 和 CRI?
:containerd 内置两个插件:

  • cri plugin → 供 kubelet 调用
  • docker shim → 供 dockerd 调用
    两者共用镜像存储和运行时(runc)

追问3:如何将现有 Docker 镜像迁移到 containerd-only 环境?
无需迁移!containerd 可直接拉取并运行 Docker Hub 镜像(OCI 兼容)。验证命令:

crictl pull nginx
crictl runp pod.json
crictl create <pod-id> container.json pod.json

Q26. 如何优化容器启动速度? ⭐⭐

预期回答:使用 Distroless/Alpine 镜像、启用 BuildKit 缓存、预拉镜像、使用 EROFS、减少 init 逻辑

追问1:lazy-pull(按需拉取)技术原理?哪些运行时支持?

  • 原理:仅拉取 metadata 和必要 layer,数据块按需从远程存储(如 S3)读取
  • 支持:Nydus(阿里)、Stargz(AWS)、OverlayBD(华为)
  • Docker 原生 不支持,需替换 snapshotter

追问2:如何测量容器从 create 到 ready 的时间?

time docker run --rm alpine echo "started"
# 或监控 events
docker events --since 1m | grep 'start\|die'

追问3:systemd-cgroup vs cgroupfs 哪个性能更好?
无显著差异systemd-cgroup 更适合 systemd 系统(避免资源竞争),但性能几乎相同。


Q27. 容器内的时间与时区为何重要?如何正确处理? ⭐

预期回答:容器默认 UTC,应用日志/调度依赖时区;应显式设置 TZ 或挂载宿主机时区文件

追问1:为什么不能直接挂载 /etc/localtime

  • Alpine 镜像无 glibc,/etc/localtime 可能无效
  • 更佳方案:设置 TZ=Asia/Shanghai 环境变量

追问2:Java 应用如何识别容器时区?

  • JVM 自动读取 /etc/timezone 或 TZ
  • 若未设置,默认使用 UTC
  • 推荐:-e TZ=Asia/Shanghai

追问3:Kubernetes 中如何统一设置 Pod 时区?

  • 方案1:initContainer 拷贝时区文件
  • 方案2:使用 volume 挂载 hostPath /usr/share/zoneinfo
  • 方案3:基础镜像内置时区(推荐)

Q28. 如何实现容器的优雅停机(Graceful Shutdown)? ⭐⭐⭐

预期回答:主进程需处理 SIGTERM,执行清理后退出;使用 exec 格式 ENTRYPOINT,避免 shell 中转

追问1docker stop 默认等待多久发送 SIGKILL?
10 秒。可通过 --time 参数调整:docker stop --time=30 <container>

追问2:Node.js 应用如何监听 SIGTERM?

process.on('SIGTERM', () => {
  server.close(() => process.exit(0));
});

追问3:Kubernetes 中 terminationGracePeriodSeconds 的作用?
:Pod 删除后,kubelet 等待该秒数再发 SIGKILL。默认 30s,应 ≥ 应用 shutdown 时间。


Q29. Docker Volume 与 Bind Mount 的本质区别? ⭐

预期回答:Volume 由 Docker 管理(路径在 /var/lib/docker/volumes/),Bind Mount 是任意宿主机路径

追问1:Volume 是否支持跨主机共享?
原生不支持。需使用网络存储插件(如 NFS、Ceph、AWS EFS driver)

追问2:如何备份一个 named volume?

docker run --rm -v myvol:/volume -v $(pwd):/backup alpine \
  tar czf /backup/backup.tar.gz -C /volume .

追问3:tmpfs mount 的适用场景?
:存放临时敏感数据(如 session、cache),重启即消失,不落盘。


Q30. 如何防止 Docker 镜像供应链攻击? ⭐⭐⭐

预期回答:使用 SBOM + Sigstore 签名 + Notary v2 + 镜像扫描(Trivy/Clair)

追问1:cosign 如何实现镜像签名?

cosign generate-key-pair
cosign sign --key cosign.key user/app:latest
cosign verify --key cosign.pub user/app:latest

追问2:Notary v2 与 Docker Content Trust (DCT) 的关系?
:DCT 基于 Notary v1,已弃用;Notary v2 是 OCI 原生签名标准,与 cosign 兼容。

追问3:如何在 CI 中阻断高危漏洞镜像?

trivy image --exit-code 1 --severity CRITICAL myapp:latest

Q31. 容器内 DNS 解析是如何工作的? ⭐⭐

预期回答:默认使用 Docker 内置 DNS(127.0.0.11),支持服务发现、自定义 nameserver

追问1:如何覆盖容器 DNS 服务器?

docker run --dns 8.8.8.8 --dns-search example.com alpine

追问2:为什么容器内 ping 通但 curl 失败?
:可能因 nsswitch.conf 顺序问题(先查 files 再 dns),或缺少 CA 证书。

追问3:Kubernetes 中 CoreDNS 如何与容器 DNS 协同?
:Pod 的 /etc/resolv.conf 由 kubelet 生成,nameserver 指向 CoreDNS Service IP。


Q32. 如何限制容器对宿主机资源的滥用? ⭐⭐

预期回答:通过 --cpus, --memory, --pids-limit, --blkio-weight 等参数限制

追问1--memory-swap 的作用是什么?
:控制内存+swap 总量。设为 -1 表示不限 swap;等于 --memory 表示禁用 swap。

追问2:能否限制容器磁盘使用量?
Docker 原生不支持。需依赖存储驱动(如 devicemapper 配额)或 Kubernetes ephemeral-storage limit。

追问3:如何防止 fork bomb?
:设置 --pids-limit=100,限制容器内最大进程数。


Q33. Docker Daemon 高可用如何实现? ⭐⭐⭐

预期回答:Docker Engine 本身无 HA;生产环境应:

  • 使用 Swarm/K8s 编排
  • 将 dockerd 作为 systemd 服务 + auto-restart
  • 镜像/卷存储到分布式文件系统(如 Ceph)

追问1:多个 dockerd 能否共享同一 /var/lib/docker
绝对禁止!会导致元数据损坏。每个 dockerd 必须独占存储目录。

追问2:如何实现 dockerd 故障自动恢复?

# /etc/systemd/system/docker.service.d/restart.conf
[Service]
Restart=always
RestartSec=5

追问3:Swarm Mode 是否提供 dockerd HA?
不提供。Swarm 管理的是 服务(service)HA,不是 dockerd 进程 HA。


Q34. 容器冷启动 vs 热启动的区别? ⭐

预期回答:冷启动 = 首次拉镜像+创建容器;热启动 = 镜像已存在,仅创建容器

追问1:如何预热容器?

  • CI 中预拉镜像:docker pull myapp:latest
  • 使用 initContainer 预加载缓存

追问2:Kubernetes 中如何预拉镜像?
:设置 imagePullPolicy: IfNotPresent + 节点预拉,或使用 prePull DaemonSet。

追问3:镜像分层如何影响冷启动时间?
:公共 base 层可复用,减少下载量;建议将变动少的层放前面。


Q35. 如何调试容器内网络不通的问题? ⭐⭐

预期回答:检查 iptables 规则、DNS 解析、路由表、安全组、CNI 插件状态

追问1:容器内无法 ping 外网,但宿主机可以,可能原因?

  • iptables FORWARD 链 DROP
  • sysctl net.ipv4.ip_forward=0
  • 云平台安全组限制

追问2:如何查看容器网络命名空间内的路由?

nsenter -t <container-pid> -n ip route

追问3docker network inspect 能看到什么信息?
:网桥名称、子网、网关、连接的容器、IP 分配等。


Q36. 容器内进程为何看不到宿主机的进程? ⭐

预期回答:因 PID Namespace 隔离,容器内 /proc 仅显示自身进程

追问1:如何让容器看到宿主机所有进程?
docker run --pid=host ...(危险!破坏隔离)

追问2top 命令在容器内显示的 CPU% 准确吗?
准确top 读取 /proc/stat,Cgroups 已虚拟化该视图。

追问3:如何监控宿主机进程 from 容器?
:挂载宿主机 proc:-v /proc:/host/proc:ro,然后读取 /host/proc


Q37. Dockerfile 中 COPY 与 ADD 的区别? ⭐

预期回答ADD 支持 URL 下载和自动解压 tar;COPY 仅本地文件复制,更透明安全

追问1:为什么官方推荐优先使用 COPY?
ADD 的隐式行为(如自动解压)易导致意外,不符合“显式优于隐式”原则。

追问2:ADD 能否下载 HTTPS 文件?
可以,但不推荐(构建不可重现,且 secrets 易泄露)。

追问3:如何安全下载外部依赖?
:在 RUN 中使用 curl/wget,并校验 checksum:


dockerfile

编辑

RUN curl -L https://.../bin.tgz -o bin.tgz && \
    echo "sha256 expected" | sha256sum -c && \
    tar -xzf bin.tgz -C /usr/local/bin

Q38. 容器内文件权限为何经常出错? ⭐⭐

预期回答:因 UID/GID 在容器内外不一致,尤其挂载卷时

追问1:如何解决挂载卷后权限 denied?

  • 方案1:容器内以匹配 UID 运行:--user $(id -u):$(id -g)
  • 方案2:构建时创建对应用户
  • 方案3:启用 User Namespace(需配置)

追问2:Dockerfile 中 RUN 创建的文件属主是谁?
:当前 USER(默认 root)。若后续切换用户,需 chown

追问3:Kubernetes 中如何动态设置卷权限?
:使用 securityContext.fsGroup,Kubelet 会自动 chown 卷目录。


Q39. 如何实现 Docker 镜像的多架构支持(如 ARM64)? ⭐⭐

预期回答:使用 Buildx + QEMU 模拟,构建 multi-platform 镜像并推送到 manifest list

追问1:如何启用 QEMU 模拟?


bash

编辑

docker run --privileged --rm tonistiigi/binfmt --install all

追问2:如何构建并推送多架构镜像?


bash

编辑

docker buildx create --use
docker buildx build --platform linux/amd64,linux/arm64 -t user/app:latest --push .

追问3:客户端如何自动拉取匹配架构的镜像?
:Docker 19.03+ 自动根据宿主机架构选择 manifest list 中的合适镜像。


Q40. 容器日志丢失的常见原因及解决方案? ⭐⭐

预期回答:日志驱动配置不当、磁盘满、容器崩溃太快、stdout 未 flush

追问1:json-file 日志默认无大小限制,如何避免占满磁盘?
:在 daemon.json 中配置:


json

编辑

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "5"
  }
}

追问2:应用日志写入文件而非 stdout,如何采集?

  • 方案1:sidecar 容器 tail 日志文件
  • 方案2:挂载 volume,宿主机 fluentd 采集

追问3:容器启动即退出,看不到日志怎么办?

  • 使用 docker logs --timestamps <container>
  • 或 docker run --rm ... || docker cp <container>:/app/log ./

【Dockerfile 专项题】

Q41. 编写一个安全的 Dockerfile 应遵循哪些最佳实践? ⭐⭐⭐

预期回答:使用非 root 用户、最小 base 镜像、合并 RUN、清理缓存、固定版本、只读根

Q41 追问1:为什么 apt-get update 和 install 必须同 RUN?


避免缓存失效导致安装旧包。若分开,修改 install 列表不会触发 update,可能装错版本。

Q41 追问2:如何避免 .git/.env 打包进镜像?


使用 .dockerignore 文件排除敏感路径。

Q41 追问3:HEALTHCHECK 最佳实践?

  • 使用轻量命令(如 curl -f http://localhost/health
  • 设置合理间隔(30s)、超时(5s)、重试(3 次)


Q42. 如何减小 Docker 镜像体积? ⭐⭐

预期回答:多阶段构建、Alpine/Distroless、清理包缓存、避免 COPY 大目录

Q42 追问1:Alpine 潜在问题?(glibc 兼容性)


使用 musl libc 而非 glibc,某些 Java/Python 二进制不兼容。

Q42 追问2:分析镜像大小工具?


dive, docker history, syft(SBOM 分析)

Q42 追问3:squash 镜像是否推荐?


不推荐。破坏分层缓存,CI/CD 中每次构建都需全量推送。


Q43. Dockerfile 中 ARG 和 ENV 的区别? ⭐⭐

预期回答:ARG 用于构建时变量(不出现在镜像中),ENV 用于运行时环境变量

Q43 追问1:能否在 RUN 中使用 ARG?


可以,但 ARG 在 RUN 结束后失效。

Q43 追问2:如何传递构建参数?

docker build --build-arg VERSION=1.2.3 .
Q43 追问3:敏感信息能否用 ARG?


绝对不行!ARG 会记录在镜像历史中,可通过 docker history 查看。


Q44. 如何在 Dockerfile 中安全地处理 secrets? ⭐⭐⭐

预期回答:使用 BuildKit 的 --mount=type=secret,避免写入镜像层

Q44 追问1:传统 COPY secret 为何不安全?


secret 会永久留在镜像层中,即使后续 RUN 删除,仍可通过历史层恢复。

Q44 追问2:secret 文件存储位置?


挂载到 /run/secrets/(tmpfs),构建结束后自动销毁。

Q44 追问3:K8s 如何集成?


通过 Tekton 或 Argo Workflows 的 secret volume 挂载到 BuildKit 构建上下文。


Q45. EXPOSE 指令真的会打开端口吗? ⭐

预期回答:不会!仅作为元数据声明,实际端口由 docker run -p 决定

Q45 追问1:不写 EXPOSE 能否 -p 发布端口?


可以。EXPOSE 仅为文档声明,不影响运行时。

Q45 追问2:对 docker-compose 影响?


compose 会自动将 EXPOSE 端口映射到随机宿主机端口(除非显式指定 ports)。

Q45 追问3:如何查看镜像声明端口?


docker inspect <image> | jq '.[].Config.ExposedPorts'


Q46. CMD 和 ENTRYPOINT 的区别与组合使用? ⭐⭐

预期回答:CMD 是默认参数,ENTRYPOINT 是主命令;组合实现“可配置命令”

Q46 追问1:exec vs shell 格式区别?

  • exec:["cmd", "arg"] → 直接 exec,PID 1
  • shell:"cmd arg" → 启动 /bin/sh -c,PID 1 是 shell
    推荐 exec
Q46 追问2:如何覆盖 ENTRYPOINT?


docker run --entrypoint /new/cmd image args

Q46 追问3:常见陷阱:在 ENTRYPOINT 中使用 shell 特性(如管道)


信号无法传递到子进程(如 trap 失效),且无法优雅停机。


Q47. 如何确保 Dockerfile 构建结果可重现(reproducible)? ⭐⭐⭐

预期回答:固定 base 镜像 digest、设置 SOURCE_DATE_EPOCH、避免随机文件顺序

Q47 追问1:为什么 tag 不可靠?


tag 可被覆盖(如 latest),digest(SHA256)唯一标识内容。

Q47 追问2:如何验证镜像 hash 相同?


比较 docker inspect --format='{{.Id}}' 或镜像 manifest digest。

Q47 追问3:BuildKit 如何帮助?


通过 SOURCE_DATE_EPOCH 和确定性构建(无随机文件顺序)保证可重现。


Q48. WORKDIR 和 RUN cd 的区别? ⭐

预期回答:WORKDIR 创建目录并设为 pwd,持久化到后续指令;RUN cd 仅在当前层有效

Q48 追问1:WORKDIR 能否用变量?


可以,但变量需在之前定义(ENV 或 ARG)。

Q48 追问2:WORKDIR 是否创建空目录?


。即使目录为空,也会出现在镜像中。

Q48 追问3:最佳实践:每个项目应有一个明确的 WORKDIR


统一使用 /app/opt/service 作为 WORKDIR。


Q49. 如何在 Dockerfile 中处理时区问题? ⭐

预期回答:COPY /etc/localtime 或设置 TZ 环境变量

Q49 追问1:Alpine 如何设置时区?

RUN apk add --no-cache tzdata && \
    cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone
Q49 追问2:为什么默认 UTC?


避免时区依赖,符合 12-Factor App 原则。

Q49 追问3:时区文件应打包还是挂载?


打包。挂载增加部署复杂度,且容器应 self-contained。


Q50. 如何为 Dockerfile 添加健康检查? ⭐⭐

预期回答:使用 HEALTHCHECK 指令,定义测试命令、间隔、超时、重试次数

Q50 追问1:健康状态有哪几种?

  • starting(刚启动)
  • healthy(通过检查)
  • unhealthy(连续失败)
Q50 追问2:Compose 如何依赖健康状态?

depends_on:
  db:
    condition: service_healthy
Q50 追问3:K8s readinessProbe 与 HEALTHCHECK 关系?


无直接关系。K8s 使用自己的 probe,忽略 Dockerfile 中的 HEALTHCHECK。


Q51. 如何避免 Dockerfile 中的缓存失效问题? ⭐⭐

预期回答:将变化频率低的指令放前面(如 apt-get install),高频放后面(如 COPY .)

Q51 追问1:COPY . 为何导致缓存失效?


任何上下文文件变动都会使该层及之后所有层缓存失效。

Q51 追问2:如何利用 .dockerignore?


排除 node_modules/, .git/, *.log, Dockerfile 等无关文件。

Q51 追问3:BuildKit cache mounts 优化?

RUN --mount=type=cache,target=/root/.npm npm install

依赖缓存在多次构建间复用。


Q52. 如何在 Dockerfile 中正确处理信号(如 SIGTERM)? ⭐⭐⭐

预期回答:使用 exec 格式 ENTRYPOINT,避免 shell 中转;主进程需处理 SIGTERM

Q52 追问1:为什么 shell 格式无法传递信号?


shell 进程(PID 1)未转发 SIGTERM 到子进程。

Q52 追问2:如何测试优雅停机?

docker stop <container>  # 观察应用是否打印 shutdown log
Q52 追问3:tini 作用?


作为 init 进程(PID 1),负责回收僵尸进程并转发信号。


📌 附:高频陷阱题(易错点)

  • Q53. docker stop 发送什么信号?等待多久 kill -9?
    → SIGTERM,默认等待 10 秒

  • Q54. 容器内 PID 1 的特殊性?
    → 负责回收僵尸进程;若不处理 SIGTERM,容器无法优雅退出

  • Q55. --tmpfstmpfs mount 的区别?
    → 功能相同,前者是 CLI 语法糖

  • Q56. 卷(volume)和绑定挂载(bind mount)的本质区别?
    → volume 由 Docker 管理,存储在 /var/lib/docker/volumes/;bind mount 是任意宿主机路径

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐