首页 > 解决方案 > 在 /docker-entrypoint-initdb.d/db_init.sh 中运行 psql 命令时出错(psql:无法连接到服务器:连接被拒绝)

问题描述

我曾经使用脚本 ( /docker-entrypoint-initdb.d/db_init.sh) 循环遍历复制到 postgres 容器中的文件夹中的数据库转储并恢复它们。它曾经工作得很好,但最近它停止了工作。

我收到以下错误:

postgres_server_1  | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/db_init.sh
postgres_server_1  | --> db_init.sh: Found /dumps/dataset_1.dump as dataset_1
postgres_server_1  | psql: could not connect to server: Connection refused
postgres_server_1  |    Is the server running on host "localhost" (127.0.0.1) and accepting
postgres_server_1  |    TCP/IP connections on port 5432?

db_init.sh脚本遍历包含数据库转储的文件夹并检查数据库是否已经存在。如果不是,它将恢复转储。

/docker-entrypoint-initdb.d/db_init.sh内容:

shopt -s nullglob
for i in /dumps/*.dump;
do
    db_name=${i##*/}
    db_name=${db_name%.dump}
    echo "--> db_init.sh: Found $i as $db_name"

    if psql -U postgres -h localhost -lqt | cut -d \| -f 1 | grep -qw ${db_name}; then
        echo "--> db_init.sh: Database ${db_name} already exists."
    else
        echo "--> db_init.sh: Setting up database: ${db_name}"
        createdb -U postgres -h localhost-T template0 ${db_name}
        psql -U postgres -h localhost ${db_name} < ${i}
    fi
done
echo "--> db_init.sh: Setup complete."

我正在使用 docker-compose 来启动 postgres 容器(以及其他一些容器)。

内容docker-compose.yml

version: '3'

services:
  postgres_server:
    image: postgres
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./data/dumps:/dumps:ro
      - ./scripts/db_init.sh:/docker-entrypoint-initdb.d/db_init.sh
    environment:
      - TZ=Europe/Berlin
    restart: always

volumes:
  postgres_data:
    driver: local

现在我不明白的是,为什么似乎通常与尝试从不同的机器或容器连接到 postgres 数据库相关联的连接错误。但是脚本本身在 postgres 容器中运行,并且一个卷将包含转储的目录连接到容器中。psql使用从容器内运行命令docker exec -it container_name bash可以正常工作,并且转储在那里。为什么psql命令在容器内手动执行时有效,但在通过执行时无效/docker-entrypoint-initdb.d/db_init.sh

标签: postgresqldockerdocker-compose

解决方案


看起来这个提交破坏了你的脚本。

解释:

PostgreSQL 不仅可以通过 TCP/IP 接受连接,还可以通过 UNIX 套接字接受连接。该-h localhost参数告诉psql使用 TCP 连接而不是 UNIX 套接字。

如果您查看当前的docker-entrypoint.sh版本,您会看到,在/docker-entrypoint-initdb.dPostgreSQL 中执行脚本期间,仅侦听 UNIX 套接字,并且启动日志显示:

LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"

这意味着psql -h localhost不会连接到数据库,因为 PostgreSQL 不侦听 IP 套接字。您必须使用psql -h localhost选项以使其使用 UNIX 套接字而不是 TCP 连接。

但为什么psql -h localhost手动运行有效?

如果你docker-entrypoint.sh再看一遍,你会看到当所有的 init 脚本被执行时,PostgreSQL 正在停止,然后在正常(操作)模式下再次启动,在这种模式下,它在 UNIX 和 IP 套接字上进行侦听:

LOG:  listening on IPv4 address "0.0.0.0", port 5432
LOG:  listening on IPv6 address "::", port 5432
LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"

因此,当启动过程完成后,您可以使用 TCP 连接连接到 PostgreSQL,从而进入容器并运行psql -h localhost成功。


推荐阅读