使用docker exec命令行无法运行psql命令从文件中运行查询

3

我有一个bash文件,应该将postgres docker容器上线,然后运行一个.sql文件来创建数据库。但是它报错了。

psql: error: provision-db.sql: No such file or directory

我已经检查了路径,文件存在于这个Bash脚本的同一级别。以下是我的Bash文件的内容。

#!/usr/bin/env bash

docker-compose up -d db

# Ensure the Postgres server is online and usable
until docker exec -i boohoo.postgres pg_isready --host="${POSTGRES_HOST}" --username="${POSTGRES_USER}"
do
    echo "."
    sleep 1
done

docker exec -i boohoo.postgres psql -h "${POSTGRES_HOST}" -U "${POSTGRES_USER}" -a -q -f provision-db.sql

这是 provision-db.sql 文件。

DROP DATABASE "boo-hoo";
CREATE DATABASE "boo-hoo";
GRANT ALL PRIVILEGES ON DATABASE "boo-hoo" TO postgres;

这是docker-compose.yml文件的一部分。
version: '3.3'

services:
  db:
    container_name: boohoo.postgres
    hostname: postgres.boohoo
    image: postgres
    ports:
      - "15432:5432"
    environment:
      POSTGRES_USER: "postgres"
      POSTGRES_PASSWORD: "postgres"

文件如何进入容器?您是否可以直接从主机运行 psql 而不需要 docker exec - David Maze
2
假设 provision-db.sql 文件存在于您的主机而不是容器中,那么使用以下命令即可将该文件导入 boohoo.postgres 容器内的 PostgreSQL 数据库:cat provision-db.sql | docker exec -i boohoo.postgres psql -h "${POSTGRES_HOST}" -U "${POSTGRES_USER}" -a -q -f - - ckaserer
@ckaserer 当我尝试这样做时,它不允许我在提示时输入数据库密码,并显示“FATAL:用户的密码身份验证失败”。 - Sadan A.
@DavidMaze 如果我直接从 Bash 脚本运行 psql,它将如何连接到容器数据库? - Sadan A.
通过在您的 docker-compose.yml 文件中的 ports: 行中使用第一个端口号,并使用 -h 127.0.0.1 指向当前主机。 - David Maze
@DavidMaze 我尝试了以下命令但没有成功。psql -h 127.0.0.1 -p 15432 -U postgres -a -q -f provision-db.sql。它说服务器是否在运行并接受端口15432上的TCP/IP连接。 - Sadan A.
2个回答

2

简短版

这个有效。

cat provision-db.sql | docker exec -i boohoo.postgres bash -c 'psql -U ${POSTGRES_USER} -w -a -q -f -'

长篇版本

这里有多个事情。

1)为什么下面的命令找不到provision-db.sql文件?

docker exec -i boohoo.postgres psql -h "${POSTGRES_HOST}" -U "${POSTGRES_USER}" -a -q -f provision-db.sql

因为 provision-db.sql 文件在您的主机上而不是容器中。因此,当您在容器内执行 psql 命令时,它找不到该文件

2) 为什么我的第一个解决方案没有起作用?

cat provision-db.sql | docker exec -i boohoo.postgres psql -h "${POSTGRES_HOST}" -U "${POSTGRES_USER}" -a -q -f - 应该可以解决问题,假设 provision-db.sql 存在

这是因为变量 ${POSTGRES_USER}${POSTGRES_PASSWORD} 在您的主机上被计算,并且我猜它们在那里没有设置。另外,我忘记了指定 -w 标志以避免密码提示

3) 为什么这样可以工作?

cat provision-db.sql | docker exec -i boohoo.postgres bash -c 'psql -U ${POSTGRES_USER} -w -a -q -f -'

好的,让我们逐步进行。

首先,我们打印位于主机上的 provision-db.sql 的内容到标准输出并通过 | 管道将其传递给下一个命令。

docker-exec 在指定的容器(boohoo.postgres)中执行命令。通过指定 -i 标志,我们允许来自主机的标准输入流传输到容器的标准输入流 <- 这很重要。

在容器中,我们执行 bash -c,它只是一个包装器,避免在主机上评估 bash 变量。我们想要容器中的变量,并通过将其放入单引号中来实现。

docker-exec boohoo.postgres bash -c "echo $POSTGRES_USER"

评估名为POSTGRES_USER的主机环境变量。
docker-exec boohoo.postgres bash -c "echo $POSTGRES_USER"

评估名为POSTGRES_USER的容器环境变量。
接下来,我们只需要使我们的postgres命令有序。
psql -U ${POSTGRES_USER} -w -a -q -f -

-U 指定用户
-w 不要求密码
-q 静默执行
-f - 处理从标准输入中获取的任何内容


0

-fpsql 的一个选项,而不是 docker exec 的选项。由于 psql 在容器内运行,因此只有当文件也在容器内时,它才能访问该文件。


谢谢您解释问题,但是这个答案并没有解决问题。 - Sadan A.
好的。但是一旦你理解了问题,解决方案就变得微不足道了。 - Laurenz Albe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接