连接到 docker 容器内的 PostgreSQL 时连接调用失败 (aiohttp)

Connect call failed while connecting to PostreSQL inside docker container (aiohttp)

我有一个简单的 REST API,它使用 aiohttp、sqlalchemy 和 PostgreSQL。

我曾经在本地 运行 我的应用程序,在 docker 容器中使用 postgresql。我使用 localhost:5432

连接到它

现在我正在尝试将我的应用程序添加到 docker-compose,但我在从它连接到 postgresql 时遇到了问题。

这是我的撰写文件:

version: "3"

services:

  db:
    image: postgres:9.4
    container_name: db
    restart: always
    ports:
      - "5432:5432"
    command:
      - "postgres"
      - "-c"
      - "listen_addresses=*"
    environment:
      POSTGRES_DB: library
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: pass

  innerio:
    container_name: innerio
    restart: 'on-failure'
    build: .
    volumes:
      - .:/innerio
    command: python3 api/models.py && python3 main.py
    ports:
      - "8080:8080"
    depends_on:
      - db

我的 aiohttp 运行宁部分:

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    app = loop.run_until_complete(main(loop))
    run_app(app, host='0.0.0.0', port=8080)

以及包含数据库信息的字符串:

DB_ADDRESS = 'postgresql://admin:pass@db:5432/library'

使用上面的设置,我得到这个错误:

innerio | raise OSError(err, f'Connect call failed {address}')

innerio | ConnectionRefusedError: [Errno 111] Connect call failed ('172.22.0.2', 5432)

我错过了什么?

您的应用程序可能在 postgres 实际侦听之前尝试连接到数据库。您已经在撰写文件中设置了一个 depends_on 键,但这几乎没有任何作用:这意味着您的应用程序在您的 postgres 容器启动之前不会启动,但这与是否或不是 postgres 实际上准备好服务请求。

理想情况下,您编写的应用程序应使其在面对数据库连接失败时保持健壮。这不仅可以解决启动问题,还允许您在应用程序处于活动状态时重新启动数据库容器。

最简单的解决方案——仅解决启动问题的解决方案——是将数据库连接置于循环中,例如:

while True:
  try:
    connect_to_database()
    break
  except ConnectionRefusedError:
    log_error('database connection refused, retrying in 5 seconds...')
    time.sleep(5)

我在从我的 Python 脚本连接到 RabbitMQ 时遇到了类似的问题。另一种方法是在您的服务的 command 中执行 shell 脚本,例如:

command: sh your.script.sh

在其中您可以使用 netcat 检查是否已建立与数据库的正确连接,例如:

#!/bin/sh

## Repeat command until port 5432 on address db is not ready.
until nc -z -v -w30 db 5432
do
echo "Waiting for database connection for 5 seconds..."

## Wait for 5 seconds before check again.
sleep 5
done
echo "Database server ready..."

#### run your server afterwards

成功完成后,您可以执行启动服务器的命令。