如何用Docker-Compose部署带.env初始化脚本的PostgreSQL并执行node-pg-migrate
解决PostgreSQL initdb脚本中环境变量占位符替换问题
以下是几种经过验证的可行方案,解决你遇到的${PGDATABASE}这类占位符无法替换的问题:
方案1:通过docker-compose command预替换脚本再启动PostgreSQL
官方PostgreSQL镜像不会自动处理initdb脚本中的环境变量占位符,我们可以在容器启动前先完成替换操作:
# docker-compose.yml services: postgres: image: postgres:15 env_file: .env # 加载.env中的数据库配置 volumes: - ./initdb.d:/initdb-templates # 将带占位符的脚本挂载到临时目录 - postgres-data:/var/lib/postgresql/data # 持久化数据库数据 command: > sh -c ' # 创建官方镜像默认的initdb目录(若不存在) mkdir -p /docker-entrypoint-initdb.d # 复制模板脚本并替换环境变量 for file in /initdb-templates/*.sql; do envsubst < "$file" > "/docker-entrypoint-initdb.d/$(basename "$file")" done # 执行官方PostgreSQL启动命令 exec postgres ' ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U ${PGUSER} -d ${PGDATABASE}"] interval: 5s timeout: 5s retries: 5 app: build: . env_file: .env depends_on: postgres: condition: service_healthy # 等待PostgreSQL完全就绪 command: > sh -c ' npm run migrate up npm start ' volumes: postgres-data:
方案2:自定义PostgreSQL镜像,在entrypoint中处理替换
如果需要更固化的镜像配置,可以自定义镜像并内置替换逻辑:
# Dockerfile.postgres FROM postgres:15 # 安装envsubst依赖(官方镜像默认无此工具) RUN apt-get update && apt-get install -y --no-install-recommends gettext-base && rm -rf /var/lib/apt/lists/* # 将带占位符的脚本复制到模板目录 COPY ./initdb.d /initdb-templates # 重写entrypoint,先替换脚本再启动服务 ENTRYPOINT ["/bin/sh", "-c", "\ mkdir -p /docker-entrypoint-initdb.d && \ for file in /initdb-templates/*.sql; do \ envsubst < \"$file\" > \"/docker-entrypoint-initdb.d/$(basename \"$file\")\"; \ done && \ exec docker-entrypoint.sh postgres \ "]
然后在docker-compose中使用这个自定义镜像:
services: postgres: build: context: . dockerfile: Dockerfile.postgres env_file: .env volumes: - postgres-data:/var/lib/postgresql/data ports: - "5432:5432" # 健康检查和其他配置同方案1
关键注意事项
- 确保
.env文件中的变量名与SQL脚本中的占位符完全匹配(比如PGDATABASE对应${PGDATABASE}) - 官方PostgreSQL镜像的
docker-entrypoint-initdb.d目录只会在容器首次启动(数据卷为空)时执行脚本,后续重启不会重复执行 - 必须通过
env_file或environment字段将环境变量传递到PostgreSQL容器,否则envsubst无法获取到值
内容的提问来源于stack exchange,提问作者Richard
相关产品推荐
相关产品推荐

