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

Docker Compose部署PostgreSQL时库、用户权限配置失败求助

解决Dockerfile中PostgreSQL初始化命令失败的问题

你的问题核心在于Docker的RUN指令是独立执行的——每个RUN都会启动一个临时容器,执行命令后就销毁该容器的进程环境。所以你在一个RUN里启动Postgres,下一个RUN执行psql时,之前的Postgres进程已经不存在了,自然连不上。

下面提供两种可靠的解决方案,你可以根据需求选择:

方案一:在单个RUN中完成初始化(适合镜像构建时固化数据)

把初始化数据库、创建用户的操作和Postgres的启动/停止放在同一个RUN指令里,确保所有操作在同一个进程环境中完成:

修改你的PostgreSQL Dockerfile如下:

FROM archlinux/base
RUN yes | pacman -S postgresql
RUN mkdir /run/postgresql/
RUN chown -R postgres:postgres /run/postgresql/
USER postgres
# 合并初始化命令:initdb → 启动Postgres → 执行psql → 停止Postgres
RUN initdb -D /var/lib/postgres/data && \
    # 后台启动Postgres,把输出重定向到/dev/null避免日志污染
    /usr/bin/postgres -D /var/lib/postgres/data > /dev/null 2>&1 & \
    # 等待2秒确保服务完全启动(根据实际情况调整时间)
    sleep 2 && \
    psql -c 'CREATE DATABASE btgapp;' && \
    psql -c "CREATE USER simha WITH PASSWORD 'krishna';" && \
    psql -c 'GRANT ALL PRIVILEGES ON DATABASE btgapp TO simha;' && \
    # 优雅停止Postgres服务
    pg_ctl -D /var/lib/postgres/data stop
CMD ["/usr/bin/postgres","-D","/var/lib/postgres/data"]

原理说明:

  • 所有操作在同一个RUN中执行,Postgres启动后保持在后台,直到psql命令执行完成再停止
  • 初始化的数据会被固化到镜像的/var/lib/postgres/data目录中,后续启动容器时直接使用

方案二:使用初始化脚本(适合动态初始化,适配数据卷场景)

如果你的场景需要使用数据卷持久化Postgres数据(就像你docker-compose里的db-data卷),更推荐这种方式——初始化脚本只会在第一次启动容器且数据目录为空时执行,避免重复创建数据库/用户。

步骤1:创建初始化SQL脚本

在./postgresql目录下创建init.sql文件,内容如下:

CREATE DATABASE btgapp;
CREATE USER simha WITH PASSWORD 'krishna';
GRANT ALL PRIVILEGES ON DATABASE btgapp TO simha;

步骤2:创建入口脚本entrypoint.sh

同样在./postgresql目录下创建entrypoint.sh,内容如下:

#!/bin/bash
set -e

# 检查数据目录是否已经初始化(通过postgresql.conf文件判断)
if [ ! -f /var/lib/postgres/data/postgresql.conf ]; then
    # 初始化数据库
    initdb -D /var/lib/postgres/data
    # 执行所有放在/docker-entrypoint-initdb.d/目录下的SQL脚本
    for f in /docker-entrypoint-initdb.d/*.sql; do
        echo "Executing initialization script: $f"
        psql -U postgres -f "$f"
    done
fi

# 启动Postgres服务(保持前台运行,符合Docker容器的单进程要求)
exec /usr/bin/postgres -D /var/lib/postgres/data

步骤3:修改Dockerfile

更新你的PostgreSQL Dockerfile,复制脚本并设置入口:

FROM archlinux/base
RUN yes | pacman -S postgresql
RUN mkdir /run/postgresql/
RUN chown -R postgres:postgres /run/postgresql/
# 创建初始化脚本目录
RUN mkdir -p /docker-entrypoint-initdb.d/
COPY init.sql /docker-entrypoint-initdb.d/
COPY entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh
USER postgres
ENTRYPOINT ["entrypoint.sh"]

原理说明:

  • 容器启动时,entrypoint脚本会先检查数据目录是否已经初始化
  • 如果是第一次启动(数据卷为空),则执行initdb和初始化SQL脚本
  • 最后以前台方式启动Postgres,确保容器能持续运行(Docker要求容器主进程必须在前台)

这两种方案都能解决你遇到的连接失败问题,方案二更适合生产环境中使用数据卷的场景,而方案一则适合需要在镜像构建阶段就固化数据库结构的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:37:50