如何在Docker中正确启动PostgreSQL实例并实现程序连接?
问题分析与解决方案
核心问题
你Dockerfile里的RUN su postgres -c 'postgres -D /var/lib/postgres/data' &是在镜像构建阶段执行的,构建完成后这个进程会被销毁,容器实际运行时PostgreSQL根本没启动——这是连接失败的主要原因。
另外还有几个次要问题:
- PostgreSQL默认只监听
localhost,但即使启动了,你指定的用户(ene)和数据库(mydb)还未创建 - 程序启动时,PostgreSQL可能还没完成初始化,直接连接会因服务未就绪失败
修复步骤
1. 编写启动脚本
创建start.sh脚本,负责初始化数据库(仅首次运行)、启动PostgreSQL、等待就绪后启动你的程序:
#!/bin/bash set -e # 仅当数据目录未初始化时执行initdb if [ ! -f /var/lib/postgres/data/postgresql.conf ]; then su postgres -c 'initdb --locale=C.UTF-8 --encoding=UTF8 -D /var/lib/postgres/data --data-checksums' # 修改PostgreSQL配置,允许本地TCP连接 su postgres -c "echo 'listen_addresses = ''*''' >> /var/lib/postgres/data/postgresql.conf" su postgres -c "echo 'host all all 127.0.0.1/32 scram-sha-256' >> /var/lib/postgres/data/pg_hba.conf" # 临时启动PostgreSQL以创建用户和数据库 su postgres -c "postgres -D /var/lib/postgres/data &" PG_PID=$! # 轮询等待PostgreSQL就绪 until su postgres -c "psql -c '\q'"; do echo "等待PostgreSQL启动..." sleep 2 done # 创建指定的用户、数据库并设置密码 su postgres -c "createuser -s $DATABASE_USER" su postgres -c "createdb -O $DATABASE_USER $DATABASE_NAME" su postgres -c "psql -c \"ALTER USER $DATABASE_USER WITH PASSWORD '$DATABASE_PASSWORD'\"" # 停止临时进程,后面统一管理 kill $PG_PID wait $PG_PID fi # 启动PostgreSQL后台运行 su postgres -c 'postgres -D /var/lib/postgres/data &' PG_PID=$! # 再次等待PostgreSQL就绪 until su postgres -c "psql -U $DATABASE_USER -d $DATABASE_NAME -c '\q'"; do echo "等待PostgreSQL就绪..." sleep 2 done # 启动你的程序 exec ./a.out # 捕获退出信号,优雅停止PostgreSQL trap "kill $PG_PID; wait $PG_PID" EXIT
2. 更新Dockerfile
修改Dockerfile,复制启动脚本并设置执行权限:
FROM archlinux:latest RUN pacman --sync -yu --noconfirm --needed base-devel curl postgresql postgresql-libs jansson WORKDIR /srv COPY main3.c /srv/ COPY start.sh /srv/ RUN gcc main3.c -lpq -ljansson -std=c99 -I/usr/include/postgresql RUN mkdir /run/postgresql && chown postgres: /run/postgresql RUN chmod +x start.sh EXPOSE 5432 EXPOSE 8000 EXPOSE 45510 CMD ["./start.sh"]
3. 调整运行命令
保持原有环境变量,可选添加数据卷避免容器重启后数据丢失:
docker run -p 127.0.0.1:8000:8000 \ -e DATABASE_HOST=127.0.0.1 \ -e DATABASE_PORT=5432 \ -e DATABASE_NAME=mydb \ -e DATABASE_USER=ene \ -e DATABASE_PASSWORD=as_shrimple_as_that \ -v postgres-data:/var/lib/postgres/data \ myexample
关键修改说明
- 启动脚本替代RUN命令:把PostgreSQL的启动逻辑移到容器运行时,确保容器启动时服务会被启动
- 初始化判断:仅首次运行时执行initdb,避免重复初始化
- 配置调整:修改PostgreSQL监听地址和认证规则,允许本地TCP连接
- 就绪等待:用
psql轮询确认服务就绪,避免程序启动时连接失败 - 自动创建资源:根据环境变量自动生成用户和数据库,无需手动操作
内容的提问来源于stack exchange,提问作者ene
相关产品推荐
相关产品推荐

