工程化与工具链 #Docker#CI/CD#部署

Docker 容器化部署实战:从开发到生产的一键发布

· 5 min read
Docker

一、容器化部署的核心价值

传统服务器部署模式,长期存在无法规避的问题:本地开发正常、测试环境报错、生产环境直接挂崩,本质都是环境差异、依赖版本不一致、运行配置不统一导致的。

尤其是我们上一篇搭建的 Monorepo 多包项目,依赖复杂、模块联动多,传统部署极易出现构建不一致、包版本错乱的问题。而 Docker 容器化的核心优势,就是将项目代码、依赖、运行环境、配置统一打包为标准化镜像,彻底抹平环境差异。

除此之外,容器化部署还具备这些优势:

  • 环境一致性:开发、测试、生产环境完全统一,规避「本地能跑线上报错」的经典问题

  • 部署轻量化:无需配置服务器全局环境,镜像开箱即用,部署效率大幅提升

  • 服务隔离性:多个服务独立容器运行,互不干扰,故障影响范围可控

  • 适配自动化:完美对接 CI/CD 流水线,支撑代码提交后自动构建、自动部署

二、生产级 Dockerfile 编写(多阶段构建优化)

多阶段构建是 Docker 部署 Node/前端项目的核心最优解。通过拆分「构建阶段」和「运行阶段」,舍弃构建依赖、缓存文件、编译工具等冗余内容,大幅压缩镜像体积,提升部署速度、降低安全风险。

下面是适配 Node.js/Next 项目的生产级参考 Dockerfile,在原有基础上补充非 root 运行、健康检查、时区配置、环境优化等生产必备能力,可根据项目框架微调:

# 第一阶段:构建阶段(完整安装依赖、执行项目构建)
FROM node:20-alpine AS builder

# 设置容器时区,统一日志时间
ENV TZ=Asia/Shanghai
WORKDIR /app

# 优先拷贝依赖文件,利用Docker缓存机制,优化构建速度
COPY package.json pnpm-lock.yaml ./

# 安装pnpm并安装依赖(适配pnpm工程化项目,兼容上文Monorepo架构)
RUN npm install -g pnpm && pnpm install --frozen-lockfile

# 拷贝全量项目代码
COPY . .

# 执行项目构建
RUN pnpm build

# 第二阶段:运行阶段(仅保留运行所需最小资源)
FROM node:20-alpine AS runner

ENV TZ=Asia/Shanghai
ENV NODE_ENV=production
WORKDIR /app

# 安全优化:不使用root用户运行容器,降低安全风险
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001

# 从构建阶段拷贝必要产物,舍弃所有构建冗余文件
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/package.json ./

# 切换至普通用户
USER nodejs

# 暴露服务端口
EXPOSE 3000

# 健康检查:保障服务稳定运行,异常自动感知
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD wget -q -O - http://localhost:3000/ || exit 1

# 容器启动命令
CMD ["node", "dist/main.js"]

核心优化说明

  • 优先拷贝依赖文件,命中 Docker 分层缓存,重复构建无需重新安装依赖

  • 采用非 root 用户运行,规避容器权限过高的安全隐患

  • 新增时区配置、健康检查,适配线上生产稳定运行要求

  • 仅拷贝运行必需文件,最终镜像体积极小,启动速度更快

三、配置 .dockerignore(必备优化,减少构建冗余)

很多部署报错、镜像体积过大的问题,都源于缺少 .dockerignore 配置。该文件用于过滤无需参与构建的文件,减少构建上下文体积、规避冗余文件打包,在项目根目录新建即可:

# 依赖目录
node_modules
.pnpm-store

# 构建产物(构建阶段会重新生成,无需本地打包文件)
dist
.next
build

# 版本控制
.git
.gitignore

# 日志、临时文件
logs
*.log
tmp
.cache

# 环境配置(容器内单独配置,避免本地环境泄露)
.env
.env.local
.env.development

四、Docker Compose 多服务编排(生产可用完整版)

单容器部署仅适合简单项目,真实业务场景大多需要联动数据库、缓存等多个服务。docker-compose 可以统一管理多服务启动顺序、环境变量、数据持久化、网络互通,替代手动启停容器,是中小型项目的首选编排方案。

以下是适配「Node项目+PostgreSQL数据库」的完整生产级编排配置,补充重启策略、资源限制、健康检查、网络隔离等能力:

# docker-compose.yml
version: "3.8"

# 统一网络,实现服务内网互通
networks:
  app-network:
    driver: bridge

# 数据持久化卷
volumes:
  pgdata:
    driver: local

services:
  # 业务应用服务
  app:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgres://user:pass@db:5432/myapp
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app-network
    # 生产级重启策略:异常自动重启
    restart: always
    # 资源限制,避免单容器占用过高服务器资源
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
    # 应用健康检查
    healthcheck:
      test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:3000/"]
      interval: 30s
      timeout: 5s
      retries: 3

  # PostgreSQL 数据库服务
  db:
    image: postgres:16-alpine
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=myapp
      - TZ=Asia/Shanghai
    networks:
      - app-network
    restart: always
    # 数据库健康检查,确保启动完成后再启动应用
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d myapp"]
      interval: 10s
      timeout: 5s
      retries: 5

关键优化点

  • 通过健康检查控制服务启动顺序,解决应用启动早于数据库导致的连接报错问题

  • 配置独立网络,实现服务内网互通、端口对外可控暴露

  • 增加资源限制、自动重启,适配线上长期稳定运行

  • 完善数据库初始化配置,无需手动建库建用户

五、本地容器调试常用命令

配置完成后,可通过简单命令完成本地构建、启动、调试,验证项目容器化可用性:

# 构建镜像并后台启动所有服务
docker-compose up -d --build

# 查看服务运行日志
docker-compose logs -f app

# 重启业务服务
docker-compose restart app

# 停止并销毁所有容器(保留数据卷)
docker-compose down

# 彻底清空容器+数据卷(重置环境)
docker-compose down -v

六、GitHub Actions 完整 CI/CD 自动部署流水线

原生简易的构建脚本无法适配生产自动化部署,这里补齐完整可落地的 CI/CD 配置,实现代码提交后,自动构建镜像、推送镜像、远程部署的全流程自动化,可根据服务器部署方式微调。

在项目根目录创建 .github/workflows/deploy.yml

name: Docker Build & Deploy

# 触发时机:main分支推送代码、合并PR时自动执行
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      # 拉取项目代码
      - name: Checkout code
        uses: actions/checkout@v4

      # 配置Docker构建缓存,大幅提升构建速度
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      # 登录镜像仓库(可替换为阿里云/腾讯云私有镜像仓库)
      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      # 构建并推送镜像
      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: your-docker-name/my-node-app:latest

      # 远程服务器自动部署(可选,适配自有服务器)
      - name: Deploy to server
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SERVER_SSH_KEY }}
          script: |
            cd /your-project-path
            docker-compose pull
            docker-compose up -d

使用说明:只需在 GitHub 仓库 Secrets 中配置对应的镜像仓库账号、服务器密钥等信息,即可实现全自动部署,无需人工干预。

七、生产环境部署方案选型

根据项目规模,可选择不同的生产编排方案,适配不同业务场景:

1. 中小型项目:Docker Compose

轻量化、运维成本低、上手简单,足够适配个人项目、中小型团队业务,支持服务自重启、数据持久化、基础故障自愈,是日常开发落地的首选方案。

2. 中大型项目:Docker Swarm / K8s

针对高并发、多实例、需要弹性扩容的项目,可升级为容器集群编排。支持滚动更新、零停机部署、自动扩缩容、精细化资源调度、集群故障转移,适配企业级线上业务。

八、生产落地最佳实践

结合线上运维经验,整理一套通用的容器化部署规范,可根据团队规范微调适配:

  • 精简镜像体积:统一使用 alpine 轻量镜像,搭配多阶段构建、.dockerignore 过滤冗余文件,减少镜像漏洞风险

  • 禁止 root 运行:所有业务容器均使用普通用户启动,最小化容器权限,规避安全漏洞

  • 强制健康检查:所有核心服务配置健康检查,自动识别服务异常,配合重启策略实现自愈

  • 日志标准化:业务日志统一输出到容器 stdout/stderr,对接服务器日志收集工具,方便排查线上问题

  • 环境分离:开发、测试、生产使用独立环境变量,容器内不打包本地敏感配置,避免信息泄露

  • 资源限制:线上容器必须配置 CPU、内存限制,防止单服务占用全部服务器资源,导致集群雪崩

  • 禁止硬编码配置:数据库地址、账号密码、密钥等敏感信息,统一通过环境变量注入,不写死在代码/配置文件中

九、常见踩坑与解决方案

  • 服务启动报错:数据库连接失败:大概率是应用启动早于数据库,通过 depends_on + 健康检查 约束启动顺序即可解决

  • 镜像体积过大:检查 .dockerignore 配置,开启多阶段构建,替换 alpine 基础镜像

  • 容器重启后数据丢失:核心数据必须配置数据卷挂载,避免数据存储在容器内部

  • 本地正常线上报错:统一容器时区、Node版本、依赖版本,彻底抹平环境差异

十、总结

Docker 容器化的核心价值,是实现了项目交付的标准化、可复用、可自动化。从手写 Dockerfile 精简镜像,到 docker-compose 统一服务编排,再结合 GitHub Actions 实现 CI/CD 全自动发布,整套流程可以彻底解决传统部署的环境混乱、效率低下、上线风险高的问题。


Zarathustra
Zarathustra
前端工程师
返回文章