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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:23:30