为什么需要容器化
传统运维面临的最大痛点之一是环境一致性。开发环境正常、测试环境异常、生产环境崩溃——这类问题几乎每个运维都遇到过。Docker 通过将应用及其依赖打包成一个标准化的容器,从根本上解决了这个问题。
Docker 核心概念速览
| 概念 | 类比 | 说明 |
|---|---|---|
| 镜像 (Image) | 类 (Class) | 容器的模板,定义了运行环境 |
| 容器 (Container) | 实例 (Instance) | 镜像的运行实例,相互隔离 |
| 仓库 (Registry) | GitHub | 存放和分发镜像的地方 |
| Dockerfile | Makefile | 定义镜像构建步骤的脚本 |
Dockerfile 最佳实践
# 1. 使用官方精简镜像作为基础
FROM node:20-alpine AS builder
# 2. 设置工作目录
WORKDIR /app
# 3. 利用缓存层:先复制依赖文件
COPY package*.json ./
RUN npm ci --only=production
# 4. 再复制源代码
COPY . .
# 5. 多阶段构建减小镜像体积
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
# 6. 使用非 root 用户运行
RUN addgroup -g 1001 -S app && adduser -S app -u 1001 -G app
USER app
# 7. 声明端口
EXPOSE 3000
# 8. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]
网络模式深入
Docker 提供五种网络驱动,各有用武之地:
# 1. bridge (默认) — 单机容器互联
docker network create --driver bridge my-bridge
docker run -d --network my-bridge --name app1 nginx
# 2. host — 直接使用宿主机网络(性能最佳,无隔离)
docker run -d --network host nginx
# 3. overlay — 跨主机容器通信(Swarm/K8s 场景)
docker network create -d overlay my-overlay
# 4. macvlan — 容器分配独立 MAC 地址(传统网络对接)
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 my-macvlan
# 5. none — 完全隔离,手动配置
docker run -d --network none alpine
数据卷管理
# 具名卷(推荐,Docker 管理)
docker volume create app-data
docker run -v app-data:/data nginx
# 绑定挂载(开发环境)
docker run -v $(pwd)/logs:/var/log/nginx nginx
# tmpfs(敏感数据,仅内存)
docker run --tmpfs /tmp nginx
# 备份数据卷
docker run --rm -v app-data:/source -v $(pwd):/backup alpine \
tar czf /backup/app-data-$(date +%Y%m%d).tar.gz -C /source .
docker-compose 生产级编排
version: '3.8'
services:
web:
build: .
ports:
- "8080:3000"
environment:
- NODE_ENV=production
- DB_HOST=db
depends_on:
db:
condition: service_healthy
restart: unless-stopped
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
db:
image: mysql:8.0
volumes:
- db-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: app_prod
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
db-data:
生产环境检查清单
- 镜像安全扫描:
docker scan <image>或使用 Trivy - 资源限制:必须设置 CPU/内存上限,防止单个容器拖垮宿主机
- 日志轮转:配置
max-size和max-file,避免磁盘写满 - 非 root 运行:安全性基本原则
- 健康检查:配合编排工具实现自愈
- 只读根文件系统:
--read-only防止容器被篡改 - 密钥管理:使用 Docker Secrets 或外部 Vault
常用运维命令速查
# 清理无用的镜像/容器/卷/网络
docker system prune -a --volumes
# 查看容器资源使用
docker stats --no-stream
# 查看容器日志(带时间戳)
docker logs -f --tail 100 --timestamps <container>
# 进入运行中的容器
docker exec -it <container> sh
# 查看镜像层历史
docker history --no-trunc <image>
# 从容器创建镜像(用于排查)
docker commit <container> debug-image
docker run -it debug-image sh
核心原则:容器是无状态的,有状态的数据必须持久化到卷中。不要依赖容器的文件系统来存储重要数据。