Docker 容器化最佳实践
学习如何用 Docker 容器化应用,包括 Dockerfile 编写、多阶段构建和性能优化
Docker 是什么?
Docker 是一个开源容器化平台,可以把应用和依赖打包进轻量、可移植的容器里。
它解决的核心问题是:开发环境、测试环境和生产环境不一致时,应用行为很容易变得不可预测。
基础概念
Image
镜像是容器的模板,包含运行应用需要的文件、依赖和配置。
Container
容器是镜像的运行实例,提供隔离且轻量的运行环境。
Dockerfile
Dockerfile 是用来构建镜像的文本文件,也是容器化流程里最常被维护的部分。
编写高效 Dockerfile
基础结构
# Use official base image
FROM node:18-alpine
# Set working directory
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Expose port
EXPOSE 3000
# Start command
CMD ["node", "server.js"]
最佳实践
1. 使用多阶段构建
把构建环境和运行环境分开,可以显著减小最终镜像体积。
# Build stage
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Runtime stage
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --only=production
CMD ["node", "dist/server.js"]
2. 优化层缓存
把不常变化的指令放在前面,可以更好利用 Docker 的层缓存。
# Good practice: Copy dependency files first
COPY package*.json ./
RUN npm ci
# Then copy application code (changes frequently)
COPY . .
3. 使用 .dockerignore
通过 .dockerignore 排除不需要进入镜像上下文的文件:
node_modules
npm-debug.log
.git
.env
*.md
.vscode
4. 减小镜像体积
- 优先使用 Alpine 这类轻量基础镜像
- 清理不必要的缓存和临时文件
- 合并相关 RUN 指令
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
Docker Compose
多容器应用可以用 Docker Compose 管理服务编排、环境变量和依赖关系。
docker-compose.yml 示例
version: "3.8"
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://db:5432/myapp
depends_on:
- db
restart: unless-stopped
db:
image: postgres:15-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=myapp
restart: unless-stopped
volumes:
pgdata:
常用命令
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
# Rebuild
docker-compose build
安全最佳实践
1. 不要使用 root 用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
USER nodejs
2. 扫描漏洞
# Use Trivy to scan images
docker run aquasec/trivy image myapp:latest
3. 用 Secrets 管理敏感信息
不要把密码、Token 或密钥硬编码在 Dockerfile 里。
性能优化
1. 资源限制
services:
web:
deploy:
resources:
limits:
cpus: "0.5"
memory: 512M
reservations:
memory: 256M
2. 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD node healthcheck.js || exit 1
3. 日志管理
services:
web:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
CI/CD
下面是一个 GitHub Actions 构建和推送镜像的例子:
name: Build and Push Docker Image
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t myapp:latest .
- name: Push to Registry
run: |
docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASS }}
docker push myapp:latest
常见问题排查
容器无法启动
# View container logs
docker logs <container-id>
# Enter container for debugging
docker exec -it <container-id> sh
网络问题
# Check network configuration
docker network ls
docker network inspect bridge
存储空间不足
# Clean up unused resources
docker system prune -a
# Check disk usage
docker system df
总结
Docker 提供了一种稳定、可复现的应用交付方式。写好 Dockerfile、控制镜像体积、避免 root 用户、做好日志和健康检查,是容器化实践里最容易带来收益的部分。