项目容器化实战

9.1 Python 项目(Flask + PostgreSQL)

项目结构

myapp/
├── app.py
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
└── .dockerignore

Dockerfile

FROM python:3.12-slim
 
WORKDIR /app
 
# 安装系统依赖
RUN apt-get update && \
    apt-get install -y --no-install-recommends gcc libpq-dev && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*
 
# 安装 Python 依赖(利用缓存)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
 
# 复制代码
COPY . .
 
# 非 root 用户
RUN useradd -m appuser
USER appuser
 
EXPOSE 5000
 
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]

requirements.txt

flask==3.0.0
gunicorn==21.2.0
psycopg2-binary==2.9.9

docker-compose.yml

services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      DATABASE_URL: postgresql://user:pass@db:5432/mydb
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped
 
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
      interval: 10s
      timeout: 5s
      retries: 5
 
volumes:
  pg_data:

.dockerignore

__pycache__
*.pyc
.env
.git
*.md

常用命令

# 启动
docker compose up -d
 
# 查看日志
docker compose logs -f web
 
# 进入容器调试
docker compose exec web python -c "import flask; print(flask.__version__)"
 
# 查看数据库
docker compose exec db psql -U user -d mydb

9.2 Node.js 项目(Express + Redis)

Dockerfile(多阶段构建)

# 阶段 1:构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
 
# 阶段 2:生产运行
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
USER appuser
EXPOSE 3000
CMD ["node", "dist/server.js"]

docker-compose.yml

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      - REDIS_HOST=redis
      - NODE_ENV=production
    depends_on:
      - redis
    restart: unless-stopped
 
  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
 
volumes:
  redis_data:

9.3 Java 项目(Spring Boot + MySQL)

Dockerfile(多阶段构建)

# 阶段 1:构建
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package -DskipTests
 
# 阶段 2:运行
FROM eclipse-temurin:21-jre-alpine
RUN addgroup -S spring && adduser -S spring -G spring
WORKDIR /app
COPY --from=builder --chown=spring:spring /app/target/*.jar app.jar
USER spring
EXPOSE 8080
 
ENTRYPOINT ["java", "-jar", "app.jar"]
# JVM 容器感知
# Spring Boot 3.x 自动检测容器内存限制
# 旧版需要:ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-jar", "app.jar"]

docker-compose.yml

services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/mydb
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: secret
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 512M
 
  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: mydb
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
 
volumes:
  mysql_data:

9.4 Go 项目(静态二进制)

# 阶段 1:构建
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o server .
 
# 阶段 2:运行(scratch = 空镜像,最小体积)
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/server /server
EXPOSE 8080
ENTRYPOINT ["/server"]
# 最终镜像大小:~15MB

9.5 开发环境模板

# docker-compose.dev.yml
services:
  web:
    build:
      context: .
      target: development
    volumes:
      - ./app:/app
      - /app/node_modules
    command: npm run dev
    ports:
      - "3000:3000"
      - "9229:9229"
    environment:
      - NODE_ENV=development
      - DEBUG=app:*
# 启动开发环境
docker compose -f docker-compose.dev.yml up
 
# 生产环境
docker compose -f docker-compose.prod.yml up -d

9.6 .dockerignore 通用模板

# 版本控制
.git
.gitignore
.svn
 
# IDE
.vscode
.idea
*.swp
*.swo
 
# 依赖
node_modules
vendor
__pycache__
*.pyc
.mypy_cache
.pytest_cache
 
# 环境配置
.env
.env.local
.env.*.local
 
# 文档
*.md
LICENSE
CHANGELOG.md
 
# Docker 相关
Dockerfile
docker-compose*.yml
.dockerignore
 
# 测试
test/
tests/
coverage/