从入门走到生产环境:Docker 容器化笔记

别急着给从入门走到生产环境:Docker 容器化笔记下定义,先看这次卡在哪。

这次做 Docker 容器化改造,从入门到生产环境,。

基础 Docker

第一个容器

# 运行第一个容器
docker run hello-world

# 运行交互式容器
docker run -it ubuntu bash

# 后台运行容器
docker run -d nginx

# 查看运行的容器
docker ps

# 查看所有容器
docker ps -a

# 停止容器
docker stop <container-id>

# 删除容器
docker rm <container-id>

构建镜像

# Dockerfile
FROM node:16-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000

CMD ["node", "index.js"]
# 构建镜像
docker build -t myapp:latest .

# 查看镜像
docker images

# 删除镜像
docker rmi myapp:latest

Docker Compose

基础配置

version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgres://postgres:password@db:5432/myapp
    depends_on:
      - db
      - redis

  db:
    image: postgres:13
    environment:
      - POSTGRES_PASSWORD=password
    volumes:
      - db-data:/var/lib/postgresql/data

  redis:
    image: redis:alpine
    volumes:
      - redis-data:/data

volumes:
  db-data:
  redis-data:
# 启动服务
docker-compose up -d

# 查看日志
docker-compose logs -f app

# 停止服务
docker-compose down

# 重启服务
docker-compose restart app

生产环境

多阶段构建

# 构建阶段
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 生产阶段
FROM node:16-alpine AS production
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY package*.json ./
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/index.js"]

健康检查

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1
# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 10s

资源限制

version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

安全最佳实践

非 root 用户

FROM node:16-alpine
WORKDIR /app

# 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

# 复制文件并设置权限
COPY --chown=nodejs:nodejs . .

# 切换到非 root 用户
USER nodejs

CMD ["node", "index.js"]

最小化镜像

FROM node:16-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist

# 只安装运行时依赖
RUN apk add --no-cache dumb-init
ENTRYPOINT ["dumb-init", "--"]

CMD ["node", "dist/index.js"]

扫描漏洞

# 使用 Trivy 扫描
trivy image myapp:latest

# 使用 Anchore 扫描
docker run --rm anchore/anchore-engine:latest analyze --image myapp:latest --tag myapp:latest

# 使用 Clair 扫描
clairctl analyze myapp:latest

踩过的坑

坑一:镜像太大

镜像太大,拉取慢,启动慢。

解决:使用多阶段构建和最小化基础镜像。

# 使用 Alpine 基础镜像
FROM node:16-alpine

# 清理不必要的文件
RUN apt-get update && apt-get install -y \
    && rm -rf /var/lib/apt/lists/*

# 不要安装调试工具
# RUN apk add --no-cache strace gdb  # 不要这样做

坑二:权限问题

容器内权限不对,导致启动失败。

解决:正确设置文件权限。

# 设置文件权限
COPY --chown=1001:1001 . /app
USER 1001

坑三:日志问题

容器日志没有正确配置,难以排查问题。

解决:配置日志输出和轮转。

# 配置应用日志输出到 stdout
ENV LOGGING_LEVEL=info
ENV LOGGING_FORMAT=json

# 或使用日志收集器
RUN apk add --no-cache dumb-init
ENTRYPOINT ["dumb-init", "--"]

写在最后

Docker 容器化这东西,不只是打包,是标准化。

解决了

  • 环境一致性
  • 部署简化
  • 资源隔离

带来了

  • 学习成本
  • 安全问题
  • 监控问题

使用之前先评估:

  • 项目规模
  • 团队能力
  • 安全要求

不是所有应用都需要容器化,有时候传统部署更简单。


这次 Docker 容器化改造花了一个月,从入门到生产环境。改造完成后,部署时间从 30 分钟降到 5 分钟,环境问题减少了 80%。

版权声明: 本文首发于 指尖魔法屋-从入门走到生产环境:Docker 容器化笔记https://blog.thinkmoon.cn/post/99-docker-containerization-beginner-production-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!