连接到 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
成功完成后,您可以执行启动服务器的命令。
我有一个简单的 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
成功完成后,您可以执行启动服务器的命令。