文档
前言
在入门篇中,我们学习了 Docker 的核心概念和基本操作。本篇深入两个关键子系统:网络和存储。理解它们是跑好生产级容器的前提。
第一章:Docker 网络深入
1.1 五种网络驱动对比
| 驱动 | 适用场景 | 跨主机 | DNS | 隔离性 |
|---|---|---|---|---|
| bridge | 单机容器通信(默认) | ❌ | ✅ 内置 | 中等 |
| host | 高性能、直接使用宿主机网络 | ❌ | ❌ | 无 |
| overlay | 跨主机容器通信(Swarm) | ✅ | ✅ | 高 |
| macvlan | 容器直接接入物理网络(IP/MAC 独立) | ✅ | ❌ | 高 |
| none | 完全禁用网络 | ❌ | ❌ | 最高 |
1.2 自定义 Bridge 网络(生产推荐)
# 创建自定义网络
docker network create \
--driver bridge \
--subnet=172.28.0.0/16 \
--ip-range=172.28.5.0/24 \
--gateway=172.28.5.1 \
my-net
# 同一网络的容器互 Ping(自动 DNS 解析)
docker run -d --name app1 --network my-net nginx
docker run -d --name app2 --network my-net alpine ping app1
# PING app1 (172.28.5.2): 56 data bytes ← 自动域名解析!
默认 bridge 网络不支持 DNS 解析,必须用
--link(已废弃)。自定义网络默认启用 DNS。
1.3 容器间通信模式
场景 1:同一自定义网络
ContainerA ←→ ContainerB [通过容器名直接通信]
场景 2:不同网络
ContainerA (net1) ←→ ContainerB (net2) [不通,需要 docker network connect]
场景 3:容器 ↔ 宿主机
Container → host.docker.internal (macOS/Windows)
Container → 172.17.0.1 (Linux 默认网关)
场景 4:容器 ↔ 外部服务
默认 NAT 出站,无需配置
1.4 端口映射原理
# -p 宿主机端口:容器端口
docker run -p 8080:80 nginx
# 流量路径:
# 外部请求 → 宿主机:8080 → iptables DNAT → 容器IP:80
# 查看 iptables 规则
iptables -t nat -L DOCKER -n
1.5 网络排错工具箱
# 查看网络列表
docker network ls
# 查看网络详情(含连接容器 IP)
docker network inspect my-net
# 进容器排查
docker exec -it app1 sh
# 容器内:
nslookup app2 # 测试 DNS
ping app2 # 测试连通性
ip addr show # 查看容器网卡
netstat -tlnp # 查看监听端口
第二章:Docker 存储深入
2.1 三种存储类型对比
| 类型 | 数据位置 | 生命周期 | 跨容器 | 性能 | 适用场景 |
|---|---|---|---|---|---|
| Volume | /var/lib/docker/volumes/ |
独立于容器 | ✅ | 好 | 生产数据持久化 |
| Bind Mount | 宿主机任意路径 | 独立于容器 | ✅ | 最好 | 开发热更新 |
| tmpfs | 内存 | 随容器 | ❌ | 极佳 | 临时缓存/密钥 |
2.2 Volume 最佳实践
# 创建命名卷
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/exports/data \
nfs-vol
# 使用卷
docker run -d \
-v db-data:/var/lib/mysql \
-v app-logs:/var/log/app \
--name mysql mysql:8
# 备份卷数据
docker run --rm \
-v db-data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/db-backup.tar.gz -C /data .
# 恢复卷数据
docker run --rm \
-v db-data:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/db-backup.tar.gz -C /data
# 卷迁移
# 1. 源主机导出
docker run --rm -v db-data:/data alpine tar czf - -C /data . > db.tar.gz
# 2. 传输到目标主机
scp db.tar.gz target-host:
# 3. 目标主机导入
docker volume create db-data
docker run --rm -v db-data:/data -v $(pwd):/src alpine sh -c "cd /data && tar xzf /src/db.tar.gz"
2.3 Bind Mount 开发场景
# docker-compose.yml(开发模式)
services:
web:
image: node:20-alpine
working_dir: /app
command: npm run dev
volumes:
- ./src:/app/src # 代码热更新
- /app/node_modules # 匿名卷,不覆盖 node_modules
ports:
- "3000:3000"
2.4 tmpfs 安全场景
# 敏感数据不落盘
docker run --rm \
--tmpfs /run/secrets:rw,noexec,nosuid,size=64m \
alpine sh -c "echo 'secret-key' > /run/secrets/key && cat /run/secrets/key"
# Docker Compose
services:
app:
tmpfs:
- /tmp:size=128M,noexec
- /run/secrets:size=1M,ro
第三章:Dockerfile 安全最佳实践
3.1 十条黄金法则
# 1. 使用特定版本,不用 latest
FROM node:20.11.1-alpine3.19
# 2. 非 root 运行
RUN addgroup -g 1000 app && adduser -u 1000 -G app -s /bin/sh -D app
USER app
# 3. 固定依赖版本
COPY package-lock.json ./
RUN npm ci --production
# 4. 最小化层数(用 && 串联)
RUN apk add --no-cache curl && \
curl -sSf https://example.com/script.sh | sh && \
apk del curl
# 5. 使用 .dockerignore
# node_modules/
# .git/
# *.md
# 6. COPY 优于 ADD(ADD 会自动解压 tar)
# 7. HEALTHCHECK
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget -qO- http://localhost:8080/health || exit 1
# 8. 使用多阶段构建减小攻击面(见例程)
# 9. 不写入密钥
# 用 BuildKit secrets:
# RUN --mount=type=secret,id=npmrc npm install
# 10. 扫描漏洞
# docker scan my-image
3.2 镜像安全扫描
# Docker 官方扫描(需要 Docker Hub 登录)
docker scan my-app:latest
# Trivy(开源,推荐)
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image my-app:latest
# Hadolint(Dockerfile 静态分析)
docker run --rm -i hadolint/hadolint < Dockerfile
第四章:资源限制与监控
4.1 资源限制
# 硬限制(超出 OOM Kill)
docker run --memory=256m --cpus=1.5 nginx
# Docker Compose
services:
app:
deploy:
resources:
limits:
cpus: '2.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 128M
4.2 实时监控
# 容器资源概况
docker stats
# 单个容器进程
docker top my-container
# 实时日志
docker logs -f --tail 100 my-container
思考题
- Docker 的 bridge 网络与 host 网络在性能上有什么差异?什么时候必须用 host?
- 如果两个容器不在同一网络,如何让它们通信?有哪些实现方式?
- Volume 和 Bind Mount 在 Docker Desktop(macOS)上的性能差异为什么特别大?
npm ci和npm install在 Dockerfile 中应该用哪个?为什么?- 如何安全地在构建阶段使用私有 npm registry 的 token?
下一步
- 学习 Docker Compose 生产部署模式
- 学习 Docker Swarm / Kubernetes 编排
- 学习 BuildKit 高级缓存策略