容器启动时如何为MongoDB单节点副本集初始化数据
MongoDB单节点副本集自动初始化数据方案
问题背景
此前使用独立MongoDB实例,通过Docker Compose、自定义Dockerfile及导入脚本,可在容器启动时自动用./db/seed目录下的JSON文件初始化数据,但该架构无法使用MongoDB事务。
为启用事务,搭建了单节点副本集,通过healthcheck机制初始化副本集,但这导致导入脚本与副本集初始化存在竞态条件——数据导入时副本集未就绪引发错误,容器停止。
需求是无需手动执行mongoimport,仅通过docker compose up就能完成副本集的数据初始化并就绪。最终采用单独的mongo_seeder服务,依赖健康检查完成后的mongo服务,实现自动数据导入,无需再使用自定义Dockerfile。
原独立实例配置
Docker Compose配置
database: build: context: . dockerfile: ./db/Dockerfile.mongodb ports: - 12000:27017 volumes: - ./data/data:/data/db environment: - MONGO_INITDB_DATABASE=DB
自定义Dockerfile(./db/Dockerfile.mongodb)
FROM mongo:latest COPY ./db/seed /import COPY ./db/import/import.sh /docker-entrypoint-initdb.d/ RUN chmod 777 /docker-entrypoint-initdb.d/import.sh
导入脚本(./db/import/import.sh)
#!/bin/bash for f in /import/*.json do name=$(basename $f | cut -d'.' -f1) mongoimport --db=DB --collection=$name --jsonArray --file=$f done
单节点副本集初始配置(存在竞态问题)
Docker Compose配置
services: mongo: build: context: . dockerfile: ./db/Dockerfile.mongodb command: [--replSet, rs0, --bind_ip_all, --port, "12000"] ports: - 12000:12000 environment: - MONGO_INITDB_DATABASE=DB healthcheck: test: test $$(mongosh --port 12000 --quiet --eval "try {rs.initiate({_id:'rs0',members:[{_id:0,host:\"mongo:12000\"}]})} catch(e) {rs.status().ok}") -eq 1 interval: 10s start_period: 0s
导入脚本(./db/import/import.sh)
#!/bin/bash for f in /import/*.json do name=$(basename $f | cut -d'.' -f1) mongoimport --host=rs0/0.0.0.0:12000 --db=DB --collection=$name --jsonArray --file=$f done
此配置中,导入脚本随MongoDB容器启动执行,但副本集初始化依赖healthcheck异步完成,存在竞态条件,导致导入时副本集未就绪,容器报错停止。
最终解决方案配置
Docker Compose配置
services: mongo: image: mongo:latest command: [--replSet, rs0, --bind_ip_all, --port, "12000"] ports: - 12000:12000 environment: - MONGO_INITDB_DATABASE=DB healthcheck: test: test $$(mongosh --port 12000 --quiet --eval "try {rs.initiate({_id:'rs0',members:[{_id:0,host:\"mongo:12000\"}]})} catch(e) {rs.status().ok}") -eq 1 interval: 10s start_period: 0s mongo_seeder: image: mongo:latest depends_on: mongo: condition: service_healthy volumes: - ./tools/db:/tmp/db/ environment: - MONGO_INITDB_DATABASE=DB - MONGOIMPORT_HOST_STRING=rs0/mongo:12000 command: bash /tmp/db/import/import.sh
导入脚本(./tools/db/import/import.sh)
#!/bin/bash for f in /tmp/db/seed/*.json do name=$(basename $f | cut -d'.' -f1) mongoimport --host=$MONGOIMPORT_HOST_STRING --db=$MONGO_INITDB_DATABASE --collection=$name --jsonArray --file=$f done
核心改进:
- 拆分出独立的
mongo_seeder服务,使用官方Mongo镜像,无需自定义Dockerfile- 通过
depends_on的service_healthy条件,确保仅在Mongo副本集健康检查通过(即副本集就绪)后才执行数据导入- 导入脚本通过环境变量配置连接信息,更灵活
内容的提问来源于stack exchange,提问作者user23145140
相关产品推荐
相关产品推荐

