无法从 docker-compose 连接到远程 PostgreSQL 数据库

问题描述 投票:0回答:1

我有以下

compose.yaml

services:
  pg-local:
    image: postgres:14.7
    volumes:
      - pgdata:/var/lib/postgresql/data
    env_file:
      - .env.local_postgres_docker_env
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 30s
      timeout: 5s
      retries: 3

  configuration-manager:
    build:
      context: ..
    ports:
      - "5000:8080"
    volumes:
      - ~/.aws:/root/.aws
    depends_on:
      db-replicator:
        condition: service_started
    env_file:
      - .env.config_manager_docker_env

  db-migrator:
    build:
      context: ..
    volumes:
      - .:/migrations
    depends_on:
      pg-local:
        condition: service_healthy
    env_file:
      - .env.config_manager_docker_env
    command: bash -c 'poetry run flask db upgrade && echo "Migration completed successfully"'

  db-replicator:
    build:
      context: ./postgres
    depends_on:
      db-migrator:
        condition: service_completed_successfully
    env_file:
      - .env.local_postgres_docker_env
      - .env.production_postgres_secrets
    command: >
      bash -c '
      PGPASSWORD=${PROD_POSTGRES_PASSWORD} pg_dump -v --host=${PROD_HOST} --username=${PROD_USER} --dbname=${PROD_DB_NAME} --clean --create --no-password --file=/tmp/dump.sql && 
      PGPASSWORD=${POSTGRES_PASSWORD} psql --host=pg-local --username=${POSTGRES_USER} < /tmp/globals.sql' &&
      PGPASSWORD=${POSTGRES_PASSWORD} psql --host=pg-local --username=${POSTGRES_USER} < /tmp/dump.sql'

volumes:
  pgdata:

pg-local
db-migrator
服务运作良好! 但是,执行
db-replicator
时,
pg_dump
服务失败,并出现以下错误:

pg_dump: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory

所有服务的所有环境变量都已明确定义(使用 `docker compose config 检查)

  • 我尝试使用其他网络
  • 我试过了
    network_mode: host
  • 我尝试使用
    docker run ...
    (而不是
    docker compose
    )运行相关图像,并且成功了。
postgresql docker docker-compose
1个回答
0
投票

Compose 中的环境变量处理可能有点复杂。 它分两个阶段发生:

    使用主机环境和
  1. $VARIABLE 文件,在文件中的任何位置使用
     替换 
    .env
     引用
    ,并忽略任何特定于容器的设置。
  2. 使用每个容器的
    environment:
    env_file:
    设置,它为主容器进程构建环境,该进程可能是一个 shell。

在您的设置中,如果您正在运行

command: bash -c '... $VARIABLE ...'
,Compose 会替换
first
步骤中的 $VARIABLE 引用;外壳看不到它。 如果
$PROD_HOST
可能仅在
.env.local_postgres_docker_env
文件中设置,那么当 Compose 根据主机环境进行替换时,它不会出现,您将得到一个空字符串。

这里的直接答案是通过在需要将文字

$$
字符传递到容器中的每个地方写入
$
来转义美元符号。

command: >
  bash -c '
  PGPASSWORD=$${PROD_POSTGRES_PASSWORD} pg_dump -v --host=$${PROD_HOST} --username=$${PROD_USER} --dbname=$${PROD_DB_NAME} --clean --create --no-password --file=/tmp/dump.sql && 
  PGPASSWORD=$${POSTGRES_PASSWORD} psql --host=pg-local --username=$${POSTGRES_USER} < /tmp/globals.sql' &&
  PGPASSWORD=$${POSTGRES_PASSWORD} psql --host=pg-local --username=$${POSTGRES_USER} < /tmp/dump.sql'

更实际的是,我可能会避免直接在 Compose 文件中编写这样的复杂脚本。 由于您似乎要为此步骤构建自定义图像,因此我会将其编写为 shell 脚本(将这些命令移至

postgres/replicate.sh
文件中)并使其成为图像的默认
CMD

# postgres/Dockerfile
...
COPY replicate.sh /usr/local/bin/replicate
CMD ["replicate"]

使用专用脚本中的命令并且该脚本是 Dockerfile 默认值

CMD
,您不会有特殊的转义问题,并且不需要 Compose
command:
覆盖。

我还可能考虑完全删除这些单独的容器,并将这些数据库维护步骤移至主应用程序容器的入口点包装脚本中;例如,参见这个答案

© www.soinside.com 2019 - 2024. All rights reserved.