一、Docker 基础概念类
1. Docker 是什么?它和虚拟机的区别?
详细答案
Docker 是开源的容器化平台,核心区别:
| 维度 | Docker 容器 | 虚拟机 (VM) |
|---|---|---|
| 虚拟化层级 | OS 级别(共享宿主机内核) | 硬件级别(Hypervisor 虚拟硬件) |
| 启动速度 | 秒级(轻量级) | 分钟级(需启动完整 OS) |
| 资源占用 | 低(MB 级) | 高(GB 级) |
| 隔离性 | 进程级(较弱) | 完全隔离(更强) |
| 镜像大小 | 小(仅应用+依赖) | 大(完整 OS+应用) |
示例:
- Docker 运行 Nginx:
docker run -d nginx(1秒启动) - VM 运行 Nginx:需先启动 Ubuntu VM 再安装 Nginx
拓展:
容器本质是隔离的进程,通过 Linux 命名空间(Namespaces)和控制组(Cgroups)实现
2. Docker 的核心组件有哪些?
详细答案
| 组件 | 作用 |
|---|---|
| Docker 守护进程 (dockerd) | 管理容器生命周期 |
| Docker 客户端 (docker) | 用户命令行工具 |
| Docker 镜像 | 只读模板(包含应用+环境) |
| Docker 容器 | 镜像的运行实例 |
| Docker Registry | 镜像仓库(如 Docker Hub) |
工作流程:
客户端 → 守护进程 → 创建/运行容器
3. 什么是 Docker 镜像(Image)?
详细答案
- 定义:只读的模板,包含运行容器所需的所有文件(代码、库、环境变量)
- 特性:
- 分层存储(每层可复用)
- 内容寻址(通过 SHA256 校验)
- 构建:通过 Dockerfile 创建
示例:
# 查看本地镜像
docker images
# 输出:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest abc123456 2 weeks ago 133MB
4. 什么是 Docker 容器(Container)?
详细答案
- 定义:镜像的运行实例,包含:
- 可写层(在镜像层之上)
- 隔离的进程空间
- 网络/IP 配置
- 生命周期:
创建 → 运行 → 暂停 → 停止 → 删除
示例:
docker run -d --name my-nginx nginx # 创建并运行容器
docker ps # 查看运行中容器
5. 什么是 Docker 仓库(Registry)?
详细答案
- 作用:集中存储和分发 Docker 镜像
- 类型:
- 公共仓库:Docker Hub(默认)
- 私有仓库:Harbor、AWS ECR
- 操作:
docker pull:下载镜像docker push:上传镜像
示例:
docker pull ubuntu:22.04 # 从 Docker Hub 下载
docker push mycompany/app:v1 # 上传到私有仓库
6. Docker Hub 和私有仓库的区别?
详细答案
| 对比项 | Docker Hub | 私有仓库 (如 Harbor) |
|---|---|---|
| 访问权限 | 公开(部分私有需付费) | 完全私有控制 |
| 速度 | 受网络限制 | 内网高速访问 |
| 安全性 | 依赖 Docker 公司 | 自主控制安全策略 |
| 适用场景 | 公共基础镜像 | 企业专有镜像 |
私有仓库部署:
docker run -d -p 5000:5000 --name registry registry:2
7. Docker 的常用命令有哪些?
详细答案
| 类别 | 命令 | 作用 |
|---|---|---|
| 生命周期 | docker run | 创建并启动容器 |
docker stop / docker start | 停止/启动容器 | |
docker rm | 删除容器 | |
| 镜像管理 | docker build | 构建镜像 |
docker rmi | 删除镜像 | |
docker pull / docker push | 拉取/推送镜像 | |
| 信息查看 | docker ps -a | 查看所有容器 |
docker logs | 查看容器日志 | |
docker exec | 进入运行中容器 |
8. Docker 镜像分层原理是什么?
详细答案
- 分层结构:镜像由多个只读层(Layer)堆叠组成
- 写时复制 (Copy-on-Write):
- 容器启动时添加可写层
- 修改文件:从底层复制到可写层再修改
- 优点:
- 节省磁盘空间(层复用)
- 加速镜像分发(仅传输新层)
示例:
FROM ubuntu:22.04 # 层1:基础镜像 (100MB)
RUN apt-get update # 层2:更新包列表 (5MB)
COPY app.py /app # 层3:添加代码 (1MB)
总镜像大小 ≈ 106MB(非 100+5+1=106MB,因共享基础层)
9. 镜像的只读层和可写层是什么?
详细答案
| 层级 | 描述 | 容器操作 |
|---|---|---|
| 只读层 | 镜像原有层(不可修改) | 读取文件直接访问 |
| 可写层 | 容器运行时添加的层(临时) | 所有修改在此层进行 |
| 数据卷 | 外部挂载的持久化存储 | 绕过可写层直接读写 |
写入流程:
读取文件 → 存在于可写层? → 是:直接操作 / 否:从只读层复制到可写层再操作
10. Docker 的 ENTRYPOINT 和 CMD 区别?
详细答案
| 指令 | 作用 | 覆盖方式 |
|---|---|---|
| ENTRYPOINT | 定义容器启动时的默认执行程序 | --entrypoint 参数 |
| CMD | 定义传递给 ENTRYPOINT 的默认参数 | 运行时命令行参数覆盖 |
组合规则:
- 二者共存时:
CMD作为ENTRYPOINT的参数 - 仅
CMD:可作为独立命令执行
示例:
# Dockerfile
ENTRYPOINT ["echo"]
CMD ["Hello World"]
# 运行
docker run app # 输出:Hello World
docker run app "Goodbye" # 输出:Goodbye
11. Docker 如何删除悬空镜像(dangling images)?
详细答案
- 悬空镜像:无标签且未被任何容器引用的中间层镜像
- 删除命令:
docker image prune # 交互式删除 docker rmi $(docker images -f "dangling=true" -q) # 批量删除 - 产生原因:构建新镜像时旧镜像失去标签
示例:
# 查看悬空镜像
docker images -f "dangling=true"
12. Docker 中 COPY 和 ADD 的区别?
详细答案
| 指令 | 功能 | 特性 |
|---|---|---|
| COPY | 复制本地文件到镜像 | 仅支持基本复制 |
| ADD | 额外支持: | 1. 自动解压 tar 文件 |
| 2. 从 URL 下载文件 |
最佳实践:
- 优先使用
COPY(更透明) - 仅需解压或下载时用
ADD
示例:
COPY app.py /app # 复制文件
ADD data.tar.gz /data # 复制并自动解压
13. 什么是 Dockerfile?
详细答案
- 定义:文本文件包含构建镜像的指令序列
- 作用:
- 自动化镜像构建
- 确保环境一致性
- 构建命令:
docker build -t myapp:v1 .
基础结构:
# 指定基础镜像
FROM ubuntu:22.04
# 设置工作目录
WORKDIR /app
# 复制文件
COPY . .
# 安装依赖
RUN apt-get update && apt-get install -y python3
# 定义启动命令
CMD ["python3", "app.py"]
14. Dockerfile 常见指令有哪些?
详细答案
| 指令 | 作用 | 示例 |
|---|---|---|
| FROM | 指定基础镜像 | FROM python:3.9-slim |
| RUN | 执行命令 | RUN pip install requests |
| COPY | 复制文件 | COPY . /app |
| ADD | 高级复制(解压/下载) | ADD data.tar.gz /data |
| ENV | 设置环境变量 | ENV PORT=8080 |
| EXPOSE | 声明监听端口 | EXPOSE 80 |
| CMD | 容器启动命令 | CMD ["flask", "run"] |
| ENTRYPOINT | 容器入口程序 | ENTRYPOINT ["/entrypoint.sh"] |
| USER | 切换运行用户 | USER appuser |
15. WORKDIR 和 RUN cd 的区别?
详细答案
| 方式 | 特点 | 示例 |
|---|---|---|
| WORKDIR | 持久化工作目录(影响后续指令) | WORKDIR /app |
| RUN cd | 仅对当前 RUN 指令有效(后续指令重置) | RUN cd /app && do_something |
最佳实践:
始终使用 WORKDIR 确保路径一致性
错误示例:
RUN cd /app # 仅当前层有效
RUN pwd # 输出仍是 / (不是 /app)
16. Docker 中 EXPOSE 和 -p 的区别?
详细答案
| 项目 | 作用 | 范围 |
|---|---|---|
| EXPOSE | 声明容器监听的端口(元数据) | Dockerfile 内部 |
| -p | 映射宿主机端口到容器端口(实际可访问) | 运行时参数 |
示例:
# Dockerfile
EXPOSE 8080
# 运行时映射端口
docker run -p 80:8080 myapp
此时外部通过宿主机 80 端口访问容器 8080 端口
17. 如何查看容器运行的日志?
详细答案
- 命令:
docker logs [选项] 容器名/ID - 常用选项:
-f:实时跟踪日志--tail N:显示最后 N 行-t:显示时间戳
示例:
docker logs -f --tail 100 my_container
日志驱动:
支持 JSON-file(默认)、Syslog、Fluentd 等
18. 如何进入一个正在运行的容器?
详细答案
两种方式:
- 交互式 Shell:
docker exec -it my_container /bin/bash - 执行单条命令:
docker exec my_container ls /app
区别:
exec:在运行中容器执行新进程attach:附加到容器主进程(退出会导致容器停止)
19. 如何将本地目录挂载到容器中?
详细答案
两种挂载方式:
- 绑定挂载(Bind Mount):
docker run -v /host/path:/container/path nginx- 直接映射主机目录
- 适合开发环境(代码热更新)
- 数据卷(Volume):
docker volume create my_vol docker run -v my_vol:/container/path nginx- Docker 管理的持久化存储
- 适合生产环境(安全/易备份)
权限控制:
- 只读挂载:
:ro后缀(如-v data:/app:ro)
20. 如何限制容器的 CPU 和内存使用?
详细答案
通过 --cpus 和 --memory 参数限制:
docker run -d \
--cpus=1.5 \ # 限制使用 1.5 核 CPU
--memory=512m \ # 限制内存为 512MB
--memory-swap=1g \ # 内存+Swap 总计 1GB
nginx
资源监控:
docker stats my_container
# 输出示例:
CONTAINER CPU % MEM USAGE / LIMIT MEM %
nginx 0.01% 5MiB / 512MiB 0.98%
底层机制:
- 通过 Linux cgroups 实现资源隔离
- OOM 处理:内存超限时容器被强制终止
二、Docker 网络与存储
21. Docker 网络模式有哪些?分别适用什么场景?
详细答案
Docker 支持 5 种网络模式:
| 模式 | 描述 | 适用场景 |
|---|---|---|
| bridge | 默认模式,容器通过虚拟网桥连接 | 单主机容器隔离通信 |
| host | 容器直接使用宿主机网络栈 | 高性能网络需求(如负载测试) |
| none | 禁用所有网络 | 安全敏感场景(离线数据处理) |
| overlay | 跨主机容器网络(Swarm/K8s) | 多节点集群服务通信 |
| macvlan | 容器分配独立 MAC 地址(类似物理设备) | 容器需直接暴露在物理网络 |
查看模式:
docker network ls
22. bridge 网络模式和 host 网络模式的区别?
详细答案
| 特性 | bridge 模式 | host 模式 |
|---|---|---|
| 网络隔离 | 容器有独立 IP 和网络命名空间 | 共享宿主机网络命名空间 |
| 性能 | 较低(NAT 转发开销) | 高(无额外转发) |
| 端口映射 | 需 -p 参数暴露端口 | 容器端口直接使用宿主机端口 |
| 安全性 | 较高(默认隔离) | 较低(直接暴露) |
| IP 分配 | Docker 分配私有 IP(172.17.0.0/16) | 使用宿主机 IP |
示例:
# bridge 模式(默认)
docker run -d -p 8080:80 nginx
# host 模式
docker run -d --network=host nginx # 直接使用宿主机80端口
23. overlay 网络模式是什么?什么时候用?
详细答案
- 定义:基于 VXLAN 实现的跨主机容器网络,允许不同物理机上的容器直接通信
- 核心组件:
- 键值存储(Consul/etcd)同步网络状态
- Docker Swarm 模式自动管理
- 使用场景:
- Docker Swarm 集群服务通信
- Kubernetes Pod 跨节点通信(需 CNI 插件)
创建流程:
- 初始化 Swarm:
docker swarm init - 创建 overlay 网络:
docker network create -d overlay my-overlay - 在集群中启动服务:
docker service create --network=my-overlay nginx
优势:
- 容器 IP 跨主机可达
- 内置服务发现(通过服务名访问)
24. 容器如何相互通信?
详细答案
三种通信方式:
- 同一 bridge 网络:通过容器 IP 或容器名直接访问
docker run -d --name web --network=my-bridge nginx docker run -it --network=my-bridge alpine ping web - Link 连接(已废弃):
--link参数(不推荐) - 自定义网络:创建用户定义的 bridge 网络
docker network create app-net docker run -d --net=app-net --name app1 myapp docker run -d --net=app-net --name app2 myapp
最佳实践:
- 使用自定义网络替代默认 bridge
- Swarm/K8s 集群使用 overlay 网络
25. Docker 如何暴露容器端口?
详细答案
两种暴露方式:
- 运行时映射 (
-p/--publish):# 映射宿主机8080→容器80 docker run -d -p 8080:80 nginx # 随机映射 docker run -d -p 80 nginx - Dockerfile 声明 (
EXPOSE):EXPOSE 80 # 元数据声明,实际暴露仍需 -p
查看映射:
docker port <container> # 查看端口绑定
26. 什么是 Docker Volume?
详细答案
- 定义:由 Docker 管理的持久化数据存储机制
- 特点:
- 独立于容器生命周期(容器删除后保留)
- 支持备份、迁移和共享
- 存储在宿主机特定目录(Linux:
/var/lib/docker/volumes/)
- 操作命令:
docker volume createdocker volume lsdocker volume inspect
示例:
docker volume create db_data
docker run -d -v db_data:/var/lib/mysql mysql
27. Volume、Bind Mount、tmpfs mount 区别?
详细答案
| 类型 | 数据存储位置 | 特点 |
|---|---|---|
| Volume | Docker 管理目录 (/var/lib/docker/volumes) | 跨容器共享、易备份 |
| Bind Mount | 用户指定宿主机路径 | 直接访问主机文件系统 |
| tmpfs mount | 仅存内存(不持久化) | 高性能临时存储 |
使用场景对比:
- Volume:生产环境数据库存储
- Bind Mount:开发环境代码热更新
- tmpfs:敏感数据临时处理
挂载示例:
# Volume
docker run -v myvol:/data app
# Bind Mount
docker run -v /host/path:/container/path app
# tmpfs
docker run --tmpfs /app/cache app
28. 如何在多个容器之间共享数据?
详细答案
两种共享方式:
- Volume 共享:
docker volume create shared_data docker run -d -v shared_data:/data --name writer busybox sh -c "echo 'test' > /data/file" docker run -it -v shared_data:/data --name reader busybox cat /data/file - Bind Mount 共享:
# 多个容器挂载同一主机目录 docker run -v /host/data:/data container1 docker run -v /host/data:/data container2
注意事项:
- Volume 更适合生产环境(权限隔离)
- 避免并发写入冲突(需应用层处理)
29. 如何将容器的数据持久化?
详细答案
持久化方案:
- Volume 持久化(推荐):
docker volume create app_data docker run -d -v app_data:/app/data myapp - Bind Mount 持久化:
docker run -d -v /opt/app/data:/app/data myapp - 数据库导出:
docker exec mysql sh -c 'mysqldump -u root -p$MYSQL_ROOT_PASSWORD db > /backup/db.sql'
数据迁移:
# 备份 Volume
docker run --rm -v app_data:/source -v $(pwd):/backup alpine tar cvf /backup/app_data.tar /source
# 恢复 Volume
docker run --rm -v app_data:/target -v $(pwd):/backup alpine tar xvf /backup/app_data.tar -C /
30. OverlayFS 是什么?
详细答案
- 定义:Linux 联合文件系统(Union Filesystem),Docker 的默认存储驱动
- 核心机制:
- LowerDir:只读镜像层(可多层)
- UpperDir:容器可写层
- MergedDir:统一视图目录
- 写时复制 (Copy-on-Write):
- 读文件:优先从 UpperDir 读取,不存在则从 LowerDir 读取
- 写文件:复制到 UpperDir 修改
- 删文件:在 UpperDir 创建空白文件标记删除
优势:
- 节省磁盘空间
- 加速容器启动
- 支持快速创建容器副本
查看存储驱动:
docker info | grep "Storage Driver"
# 输出:Storage Driver: overlay2
三、Docker Compose 与编排
31. 什么是 Docker Compose?
详细答案
Docker Compose 是用于定义和运行多容器应用的工具,核心功能:
- 声明式配置:通过 YAML 文件定义服务、网络、卷
- 一键启停:单命令管理整个应用生命周期
- 服务依赖:自动处理容器启动顺序
- 环境隔离:不同项目使用独立网络
解决痛点:
- 替代繁琐的
docker run命令链 - 统一管理复杂应用的多个组件(如 Web + DB + Cache)
示例:
docker-compose up -d # 启动所有服务
docker-compose down # 停止并清理
32. Compose 的常用命令有哪些?
详细答案
| 命令 | 作用 |
|---|---|
docker-compose up | 创建并启动所有服务(-d 后台运行) |
docker-compose down | 停止并删除容器、网络 |
docker-compose ps | 查看运行中的服务容器 |
docker-compose logs | 查看服务日志(-f 实时跟踪) |
docker-compose build | 构建或重新构建服务镜像 |
docker-compose exec | 进入运行中的容器 |
docker-compose config | 验证并查看解析后的配置 |
常用组合:
# 重新构建并启动
docker-compose up -d --build
# 查看特定服务日志
docker-compose logs -f web
33. Docker Compose 文件的常用字段有哪些?
详细答案
| 字段 | 作用 | 示例 |
|---|---|---|
| version | 指定 Compose 文件版本 | version: '3.8' |
| services | 定义服务列表 | services: web: ... |
| image | 指定服务镜像 | image: nginx:1.25 |
| build | 构建镜像的 Dockerfile 路径 | build: ./app |
| ports | 端口映射 | ports: - "8080:80" |
| volumes | 数据卷挂载 | volumes: - db_data:/var/lib/mysql |
| environment | 设置环境变量 | environment: DEBUG: "true" |
| networks | 加入网络 | networks: - frontend |
| depends_on | 服务依赖关系 | depends_on: - db |
完整示例:
version: '3.8'
services:
web:
build: .
ports:
- "8000:5000"
depends_on:
- db
db:
image: postgres:14
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
34. depends_on 的作用是什么?
详细答案
- 作用:控制服务启动顺序(但不保证服务已就绪)
- 限制:
- 仅确保容器启动顺序(如先启动 DB 再启动 Web)
- 不检测服务可用性(需应用层重试逻辑)
- 替代方案:
- 使用健康检查(healthcheck)
- 脚本轮询服务端口(如 wait-for-it.sh)
示例:
services:
web:
depends_on:
db:
condition: service_healthy # 等待db健康
healthcheck:
test: curl -f http://localhost:5000 || exit 1
interval: 30s
db:
healthcheck:
test: pg_isready -U postgres
interval: 10s
35. 如何在 Compose 中配置网络?
详细答案
三种网络配置方式:
- 默认网络:自动创建名为
{project}_default的 bridge 网络 - 自定义网络:
services: web: networks: - frontend db: networks: - backend networks: frontend: driver: bridge backend: driver: bridge - 加入外部网络:
networks: default: external: name: existing_network
网络特性:
- 同网络内的容器可通过服务名互访
- 隔离不同项目的网络环境
36. Docker Compose 和 Kubernetes 的区别?
详细答案
| 维度 | Docker Compose | Kubernetes |
|---|---|---|
| 定位 | 单机多容器编排 | 集群级容器编排平台 |
| 适用场景 | 开发/测试环境 | 生产环境 |
| 扩展能力 | 简单服务依赖 | 自动扩缩、自愈、负载均衡 |
| 网络模型 | 单机网络(bridge/host) | 跨主机 CNI 网络(Calico/Flannel) |
| 存储管理 | 基础卷绑定 | PV/PVC/StorageClass 体系 |
| 高可用 | 不支持 | 内置节点/应用级高可用 |
| 配置文件 | docker-compose.yml | Deployment/Service YAML |
演进关系:
Compose → Swarm → Kubernetes(生产标准)
37. 如何在 Compose 中实现数据持久化?
详细答案
两种持久化方式:
- 命名卷(Named Volume):
services: db: image: mysql:8.0 volumes: - db_data:/var/lib/mysql volumes: db_data: # Docker 管理存储 - 绑定挂载(Bind Mount):
services: app: volumes: - ./data:/app/data # 映射主机目录
数据备份:
# 备份命名卷
docker run --rm -v db_data:/source -v $(pwd):/backup alpine tar cvf /backup/db_backup.tar /source
38. 如何在 Compose 中设置环境变量?
详细答案
四种设置方式:
- 直接声明:
services: web: environment: DEBUG: "true" PORT: 8080 - 变量文件:
env_file: .env # 从文件加载.env文件内容:DB_USER=admin DB_PASSWORD=secret - Compose 变量:
运行时指定:services: db: image: postgres:${POSTGRES_VERSION}POSTGRES_VERSION=14 docker-compose up - Shell 环境变量:
export DB_PASS=secret docker-compose up # 自动读取当前 shell 环境变量
优先级:
直接声明 > 变量文件 > Shell 环境变量
四、Docker 性能与安全
39. 如何优化 Docker 镜像大小?
详细答案
优化策略:
- 选择小型基础镜像:
FROM alpine:3.18 # 仅 5MB # 替代 ubuntu (75MB) - 多阶段构建:
# 阶段1:构建环境 FROM golang:1.20 AS builder COPY . . RUN go build -o app # 阶段2:运行环境 FROM alpine:3.18 COPY --from=builder /app /usr/bin/app - 合并 RUN 指令:
RUN apt-get update && \ apt-get install -y python3 && \ rm -rf /var/lib/apt/lists/* # 清理缓存 - 使用 .dockerignore:
# .dockerignore .git node_modules *.log
效果:
- 典型 Java 应用:从 650MB → 150MB
- Python 应用:从 300MB → 40MB
40. 如何减少镜像构建时间?
详细答案
加速方案:
- 构建缓存利用:
- 将高频变更层放在 Dockerfile 底部
- 固定依赖版本(避免缓存失效)
- 并行下载依赖:
RUN --mount=type=cache,target=/var/cache/apt \ apt-get update && apt-get install -y pkg1 pkg2 - BuildKit 特性:
DOCKER_BUILDKIT=1 docker build . # 启用并行构建 - 镜像层复用:
# 公共层单独构建 FROM base-image AS deps COPY requirements.txt . RUN pip install -r requirements.txt # 应用层 FROM deps AS app COPY . .
实测效果:构建时间减少 40-70%
41. Docker 容器启动慢的原因有哪些?
详细答案
常见原因:
- 镜像过大:下载和解压耗时
- 优化:使用小型镜像(Alpine/Distroless)
- 初始化脚本复杂:
- 优化:精简启动命令,异步初始化
- 磁盘 I/O 瓶颈:
- 优化:使用 SSD,避免主机 I/O 过载
- 网络延迟:
- 优化:本地镜像仓库,预拉取镜像
- 安全扫描:
- 优化:禁用不必要的扫描(如 Clair)
诊断命令:
docker run --rm alpine time dd if=/dev/zero of=test.img bs=1G count=1 # 测试磁盘IO
42. 如何分析容器的资源使用情况?
详细答案
分析工具:
- docker stats:实时监控
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" - cAdvisor:容器指标可视化
docker run -d --name=cadvisor \ -v /:/rootfs:ro \ -v /var/run:/var/run:ro \ google/cadvisor - Prometheus + Grafana:
- 采集指标:
container_cpu_usage_seconds_total - 内存:
container_memory_usage_bytes
- 采集指标:
- 进入容器分析:
docker exec -it my_container top
43. Docker 安全性如何保障?
详细答案
安全措施:
- 非特权用户:
USER appuser # 避免 root 运行 - 只读文件系统:
docker run --read-only alpine - Capabilities 限制:
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx - 安全扫描:
docker scan nginx # 使用 Snyk 扫描漏洞 - Seccomp/AppArmor:
docker run --security-opt seccomp=profile.json app
44. 容器逃逸是什么?如何防御?
详细答案
- 容器逃逸:攻击者突破容器隔离获取宿主机权限
- 防御方案:
- 内核升级:修复 CVE 漏洞(如 Dirty Pipe)
- 禁用危险配置:
docker run --privileged=false # 禁用特权模式 - 只读 rootfs:
docker run --read-only ... - 用户命名空间:
dockerd --userns-remap=default # 启用用户映射 - 安全策略:
- 使用 gVisor 或 Kata Containers 增强隔离
45. Docker 中的 Capabilities 是什么?
详细答案
- Capabilities:Linux 内核的权限细分机制(替代 root 全权)
- 默认限制:容器默认仅有 14 项 capabilities(非完整 root)
- 关键操作:
Capability 权限 CHOWN修改文件所有者 NET_RAW创建 RAW/PACKET 套接字 SYS_ADMIN挂载文件系统、命名空间操作
管理命令:
docker run --cap-add=SYS_PTRACE --cap-drop=NET_RAW debug-tool
46. 如何为容器配置只读文件系统?
详细答案
实现方式:
- 全局只读:
docker run --read-only alpine - 部分可写:
docker run --read-only -v /tmp:/tmp app # /tmp 可写 - Dockerfile 配置:
RUN mkdir /writeable && chmod a+rw /writeable VOLUME /writeable
适用场景:
- 安全敏感应用(减少攻击面)
- 无状态服务(日志输出到 stdout)
47. 什么是 rootless Docker?
详细答案
- 定义:无需 root 权限运行 Docker 守护进程和容器
- 价值:
- 安全:攻击者无法获取宿主机 root
- 兼容:普通用户可管理容器
- 安装:
curl -fsSL https://get.docker.com/rootless | sh - 限制:
- 部分网络模式不可用(如 host 模式)
- 性能损失约 10-20%
验证:
id # 显示普通用户
docker run hello-world
48. Docker Daemon 的工作原理?
详细答案
工作流程:
- 监听请求:
- 通过 UNIX 套接字
/var/run/docker.sock或 TCP 接收命令
- 通过 UNIX 套接字
- 路由处理:
- 创建/启动容器 → 调用 containerd
- 构建镜像 → 调用 BuildKit
- 容器管理:
- 状态同步:
- 存储状态到
/var/lib/docker - 事件通知(如容器启停)
- 存储状态到
关键组件:
- containerd:容器生命周期管理
- runc:OCI 容器运行时实现
- BuildKit:镜像构建引擎
五、实战与排错
49. 如何调试一个启动失败的容器?
详细答案
调试步骤:
- 查看状态:
docker ps -a | grep <container_name> - 检查日志:
docker logs <container_id> - 描述容器:
docker inspect <container_id>(关注State字段) - 进入容器:
# 尝试启动临时 shell docker run -it --rm --entrypoint=sh <image_name> - 检查启动命令:
docker inspect --format='{{.Config.Cmd}}' <image_name>
常见问题:
- 端口冲突:
docker run -p 8080:80但 8080 被占用 - 权限不足:
docker run --user 1000 - 挂载失败:
docker run -v /host/path:/container/path路径错误
50. 如何清理无用的镜像、容器和网络?
详细答案
清理命令:
| 资源类型 | 命令 |
|---|---|
| 停止的容器 | docker container prune |
| 悬空镜像 | docker image prune |
| 未使用镜像 | docker image prune -a |
| 未使用网络 | docker network prune |
| 构建缓存 | docker builder prune |
| 全部无用资源 | docker system prune --volumes(谨慎使用) |
定时清理(crontab):
# 每天凌晨清理
0 0 * * * docker system prune -af --filter "until=24h"
51. 如何将容器打包迁移到另一台机器?
详细答案
迁移方案:
- 容器转镜像:
docker commit <container_id> my_migrated_image docker save my_migrated_image > image.tar scp image.tar user@new-host:/path # 在新主机加载 docker load < image.tar - 数据卷迁移:
# 备份卷 docker run --rm -v db_data:/volume -v $(pwd):/backup alpine \ tar cvf /backup/db_data.tar /volume # 新主机恢复 docker run --rm -v db_data:/volume -v $(pwd):/backup alpine \ tar xvf /backup/db_data.tar -C /
最佳实践:
- 使用 Docker Registry 中转镜像
- 数据库迁移用
pg_dump/mysqldump替代卷复制
52. 如何在 Docker 容器中运行系统服务?
详细答案
两种模式:
- 前台运行(推荐):
CMD ["nginx", "-g", "daemon off;"] # 强制前台运行 - 使用 init 进程:
# 安装轻量级 init 系统 RUN apt-get install -y runit CMD ["/usr/sbin/runsvdir-start"]
注意事项:
- 避免使用
systemd(容器非完整系统) - 日志输出到 stdout 以便收集
53. 如何查看容器内的进程?
详细答案
三种方法:
- docker top:
docker top <container_id> # 输出: UID PID PPID C STIME TTY TIME CMD root 12345 123 0 14:30 ? 00:00 nginx - 进入容器:
docker exec -it <container_id> ps aux - 主机视角:
# 查找容器主进程 docker inspect -f '{{.State.Pid}}' <container_id> # 输出 12345 nsenter -t 12345 -p ps aux
54. 如何查看容器的环境变量?
详细答案
查看方法:
- 启动时打印:
docker run --rm <image> env - 运行中容器:
docker exec <container_id> env - inspect 命令:
docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' <container_id>
特殊变量:
HOSTNAME:容器主机名HOME:用户家目录PATH:可执行文件搜索路径
55. 如何升级正在运行的容器?
详细答案
标准流程:
- 拉取新镜像:
docker pull new-image:v2 - 停止旧容器:
docker stop old-container - 删除旧容器:
docker rm old-container - 启动新容器:
docker run -d --name new-container \ -v data_volume:/app/data \ new-image:v2
零停机方案:
- 蓝绿部署:
# 启动新版本容器(相同网络) docker run -d --name app-v2 --network=app-net app:v2 # 切换流量(如修改 Nginx 配置) docker exec nginx nginx -s reload # 停用旧版本 docker stop app-v1
56. 如何回滚容器版本?
详细答案
回滚策略:
- 镜像回滚:
docker run -d --name rollback-container \ old-image:v1 - 数据回滚:
- 数据库:从备份恢复
mysqldump - 文件卷:恢复快照或备份文件
- 数据库:从备份恢复
- 版本标签控制:
# 重新打标签 docker tag old-image:stable old-image:rollback docker run -d rollback-image:rollback
预防措施:
- 镜像仓库保留历史版本(如 Harbor 标签保留策略)
- 数据库定期备份
57. 如何在生产环境中部署 Docker?
详细答案
部署方案:
| 方案 | 适用场景 | 工具 |
|---|---|---|
| 单机管理 | 小型应用 | Docker Compose |
| 集群管理 | 中型应用 | Docker Swarm |
| 生产级编排 | 大型分布式系统 | Kubernetes(推荐) |
关键实践:
- 镜像安全:
- 私有仓库(Harbor)
- 漏洞扫描(Trivy)
- 资源隔离:
docker run -d --cpus=2 --memory=1g app - 日志收集:
docker run --log-driver=fluentd --log-opt fluentd-address=loghost:24224 - 监控告警:Prometheus + Grafana
58. 常见的 Dockerfile 优化技巧有哪些?
详细答案
优化技巧:
- 多阶段构建:
FROM node:18 AS build COPY . . RUN npm build FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html - 构建缓存:
# 先复制依赖文件(利用缓存) COPY package.json yarn.lock . RUN yarn install COPY . . # 代码变更频繁放后面 - 减少层数:
RUN apt-get update && \ apt-get install -y python3 && \ rm -rf /var/lib/apt/lists/* # 单层完成 - 使用小型镜像:
FROM python:3.11-slim # 替代完整版 - 非 root 用户:
RUN groupadd -r appuser && useradd -r -g appuser appuser USER appuser
优化效果:
- 构建时间减少 40%
- 镜像体积缩小 70%
- 安全性显著提升
六、进阶与集成
59. 什么是多阶段构建(Multi-stage build)?
详细答案
多阶段构建是一种 Dockerfile 优化技术,允许在单个 Dockerfile 中使用多个 FROM 指令,每个阶段独立构建,最终仅将必要文件复制到最终镜像。
核心价值:
- 减小镜像体积:构建工具和中间文件不会进入最终镜像
- 提升安全性:减少攻击面(不包含编译器等)
- 简化构建流程:单文件管理复杂构建链
示例:
# 阶段1:构建环境(含JDK)
FROM maven:3.8-jdk-11 AS builder
COPY . .
RUN mvn package -DskipTests
# 阶段2:运行环境(仅JRE)
FROM openjdk:11-jre-slim
COPY --from=builder /target/app.jar /app.jar
CMD ["java", "-jar", "/app.jar"]
最终镜像从 600MB → 150MB
60. Docker 和 CI/CD 如何结合?
详细答案
集成流程:
典型工具链:
| 阶段 | 工具 | Docker 命令 |
|---|---|---|
| 构建 | Jenkins/GitHub Actions | docker build -t app:v1 . |
| 扫描 | Trivy/Clair | docker scan app:v1 |
| 推送 | Harbor/Docker Hub | docker push harbor.com/app |
| 部署 | Argo CD/K8s | kubectl apply -f deploy.yaml |
GitHub Actions 示例:
name: CI/CD Pipeline
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Push to Harbor
run: docker push harbor.com/myapp:${{ github.sha }}
61. Docker 与 Kubernetes 的关系?
详细答案
层级关系:
核心关系:
- 运行时依赖:K8s 通过 CRI 接口调用 containerd(Docker 组件)运行容器
- 镜像标准:K8s 使用 OCI 镜像(Docker 镜像格式)
- 演进趋势:
- Docker → containerd → CRI-O(轻量级替代)
- K8s v1.24+ 默认移除 dockershim
最佳实践:生产环境直接使用 containerd 而非完整 Docker
62. 如何在 Kubernetes 中使用 Docker 镜像?
详细答案
使用流程:
- 构建镜像:
docker build -t myapp:v1 . - 推送仓库:
docker push registry.com/myapp:v1 - K8s 部署:
apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: template: spec: containers: - name: app image: registry.com/myapp:v1 # 使用Docker镜像 imagePullPolicy: IfNotPresent
关键配置:
imagePullSecrets:私有仓库认证imagePullPolicy:镜像拉取策略(Always/Never/IfNotPresent)
63. 为什么 Docker 要从 dockerd 迁移到 containerd?
详细答案
根本原因:
- 架构解耦:
- Docker → 大而全(构建/网络/存储)
- containerd → 专注容器运行时(更轻量)
- K8s 兼容:
- K8s 通过 CRI 标准调用运行时
- containerd 原生支持 CRI(dockerd 需 shim 转换)
- 性能提升:
- 减少调用链:kubelet → containerd(跳过 dockerd)
- 容器启动加速 30%
架构对比:
| 组件 | Docker 时代 | containerd 时代 |
|---|---|---|
| 容器运行时 | dockerd → containerd → runc | kubelet → containerd → runc |
| 镜像管理 | Docker Engine | containerd + ctr |
64. Docker Swarm 是什么?和 K8s 的区别?
详细答案
Docker Swarm:
- Docker 官方提供的轻量级容器编排工具
- 核心特性:
- 内置于 Docker Engine(
docker swarm init) - 声明式服务管理(docker-compose.yml)
- 自动负载均衡
- 内置于 Docker Engine(
与 K8s 对比:
| 维度 | Docker Swarm | Kubernetes |
|---|---|---|
| 学习曲线 | 简单(Docker 命令扩展) | 陡峭 |
| 功能范围 | 基础编排(服务/扩缩/网络) | 全功能(存储/网络/策略) |
| 集群规模 | ≤100 节点 | ≥1000 节点 |
| 社区生态 | 衰退(Docker 公司战略调整) | 繁荣(CNCF) |
| 适用场景 | 中小集群快速部署 | 企业级生产环境 |
Swarm 示例:
docker swarm init
docker service create --name web --replicas 3 -p 80:80 nginx
65. 如何构建支持多架构的镜像?
详细答案
两种实现方式:
- manifest 合并(手动):
# 构建不同架构镜像 docker buildx build --platform linux/amd64 -t app:amd64 . docker buildx build --platform linux/arm64 -t app:arm64 . # 创建多架构清单 docker manifest create app:multi \ --amend app:amd64 \ --amend app:arm64 docker manifest push app:multi - Buildx 自动构建(推荐):
docker buildx create --use # 启用Buildx docker buildx build \ --platform linux/amd64,linux/arm64 \ -t username/app:v1 \ --push . # 自动推送多架构镜像
验证:
docker manifest inspect username/app:v1
# 输出包含 amd64/arm64 架构
66. 如何在 Docker 中运行无 root 权限的应用?
详细答案
安全实践:
- Dockerfile 配置:
FROM alpine RUN addgroup -S appgroup && adduser -S appuser -G appgroup USER appuser # 切换到非root用户 CMD ["myapp"] - 运行时限制:
docker run -d \ --user 1000:1000 \ # 指定UID:GID --cap-drop=ALL \ # 移除所有特权 --read-only \ # 只读文件系统 myapp - rootless 模式:
# 安装rootless Docker curl -fsSL https://get.docker.com/rootless | sh systemctl --user start docker
权限验证:
docker run --rm alpine id
# 输出:uid=1000(appuser) gid=1000(appgroup)
1799

被折叠的 条评论
为什么被折叠?



