容器化的价值

三年前,我们的部署流程还是”把代码丢给运维,祈祷不要出问题”。环境差异、依赖冲突、配置混乱,每次上线都是一场战斗。

引入 Docker 后,“一次构建,到处运行”不再是空话。

Dockerfile 编写原则

原则1:使用官方基础镜像

# 推荐
FROM node:18-alpine

# 不推荐
FROM ubuntu:latest
RUN apt-get update && apt-get install -y nodejs

Alpine 版本的镜像体积更小,安全性更高。

原则2:合理利用缓存

COPY package*.json ./
RUN npm ci
COPY . .

先复制依赖文件,再复制源代码。这样只有 package.json 变化时才会重新安装依赖。

原则3:多阶段构建

# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci && npm run build

# 运行阶段
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/main.js"]

最终镜像只包含编译后的代码,不包含源码和开发依赖。

镜像优化技巧

1. 使用 .dockerignore

node_modules
.git
.env
*.log
dist

避免把不必要的文件打包进镜像。

2. 合并 RUN 指令

RUN apt-get update && apt-get install -y \
    curl \
    vim \
    && rm -rf /var/lib/apt/lists/*

减少镜像层数,控制最终体积。

3. 使用非 root 用户

RUN useradd -m -s /bin/bash appuser
USER appuser

提升容器安全性。

生产环境配置

健康检查

HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:3000/health || exit 1

资源限制

docker run -m 512m --cpus=1 myapp

日志管理

# 限制日志大小
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

容器编排入门

从单机到集群,Docker Compose 是过渡的好选择:

version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
    depends_on:
      - db
  
  db:
    image: postgres:15-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

一条命令启动整个应用栈:

docker-compose up -d

总结

容器化不是银弹,但确实解决了环境一致性的老大难问题。关键实践:

  • 镜像体积越小越好
  • 安全性和可维护性并重
  • 开发环境和生产环境保持一致