You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Docker Compose实现容器启动前的一次性初始化脚本?

最佳实践:用独立初始化容器完成前置操作

为什么要创建独立容器?

  • 完全解耦Worker业务逻辑与初始化操作,Worker容器无需包含初始化相关依赖、脚本,镜像体积更小,职责更单一
  • 精准控制初始化执行时机,确保所有Worker启动前数据准备完成
  • 便于单独维护、调试初始化脚本,无需修改Worker镜像

如何实现「仅运行一次后停止」?

1. 编写初始化脚本的Dockerfile

基于Node.js基础镜像打包初始化脚本及依赖,将脚本设置为容器启动命令。示例:

FROM node:18-alpine

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY init-scripts/ ./init-scripts/

# 容器启动时自动执行初始化脚本
CMD ["node", "./init-scripts/setup-db.js"]

容器启动后会执行指定脚本,脚本执行完成后进程自动退出,容器随之停止,天然满足「仅运行一次」的需求。

2. 用Docker Compose控制执行顺序

通过编排工具确保初始化容器执行成功后,再启动Worker容器。示例配置:

version: '3.8'
services:
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: app_user
      POSTGRES_PASSWORD: app_pass
      POSTGRES_DB: app_db
    volumes:
      - db-data:/var/lib/postgresql/data

  init-db:
    build: ./init-db
    depends_on:
      - db
    environment:
      DB_URL: postgres://app_user:app_pass@db:5432/app_db
    restart: "no" # 显式声明避免执行完成后自动重启

  worker1:
    build: ./worker1
    depends_on:
      init-db:
        condition: service_completed_successfully
    environment:
      DB_URL: postgres://app_user:app_pass@db:5432/app_db

  worker2:
    build: ./worker2
    depends_on:
      init-db:
        condition: service_completed_successfully
    environment:
      DB_URL: postgres://app_user:app_pass@db:5432/app_db

volumes:
  db-data:

核心要点:

  • Worker服务通过depends_on指定condition: service_completed_successfully,确保只有初始化容器执行成功(脚本无错误退出)才启动
  • 初始化容器restart设为no,防止意外重启重复执行

3. 避免重复执行的脚本逻辑

在初始化脚本中添加判断,防止容器重启后重复执行操作。示例:

// setup-db.js
async function initDB() {
  const db = await connectToDB();
  // 检查数据库是否已初始化
  const hasInitFlag = await db.query("SELECT EXISTS (SELECT 1 FROM init_flag)");
  if (hasInitFlag.rows[0].exists) {
    console.log("数据库已完成初始化,跳过操作");
    process.exit(0);
  }
  // 执行建表、填充初始数据等操作
  await db.query("CREATE TABLE IF NOT EXISTS users (...)");
  await db.query("INSERT INTO users (name) VALUES ('admin')");
  // 写入初始化标记
  await db.query("CREATE TABLE init_flag (id SERIAL PRIMARY KEY)");
  await db.query("INSERT INTO init_flag DEFAULT VALUES");
  
  console.log("初始化完成");
  process.exit(0);
}

initDB().catch(err => {
  console.error("初始化失败", err);
  process.exit(1);
});

4. 无编排工具时的手动执行方式

如果不用Docker Compose,可手动运行初始化容器,确认执行成功后再启动Worker:

# 构建初始化镜像
docker build -t app-init ./init-db
# 运行初始化容器(需与数据库在同一网络)
docker run --network app-network app-init
# 检查容器退出状态为0(执行成功)后,启动Worker容器
docker run -d --network app-network app-worker1

内容的提问来源于stack exchange,提问作者StackTracer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 01:40:51