如何通过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
相关产品推荐
相关产品推荐

