Compute Engine上Docker容器PostgreSQL连接超时问题求助
我正在开发一个基于PostgreSQL和Node.js Express的Web应用,已将其容器化并推送至Artifact Registry,且已将相关镜像拉取至虚拟机中。我的docker-compose文件配置如下:
services: postgres: image: postgres:latest container_name: postgres environment: POSTGRES_DB: web_app_db POSTGRES_USER: developer POSTGRES_PASSWORD: test1234 ports: - "5432:5432" volumes: - postgres-data:/var/lib/postgresql/data network: - my-nw api: image: web-api command: > sh -c ' npm run upgrade-docker && if [ "$SEED" = "true" ]; then npm run seed-roles ./src/environments/.env.docker && npm run seed-stores ./src/environments/.env.docker && npm run seed-products ./src/environments/.env.docker fi && npm run start ./src/environments/.env.docker ' environment: - WORKDIR=$PWD - PORT=80 - SEED=true volumes: - ./src:/app/src - ./dist:/app/dist depends_on: - postgres network: - my-nw networks: my-nw: driver: bridge volumes: postgres-data:
执行docker compose up -d postgres后,PostgreSQL服务正常启动并暴露5432端口;但执行docker compose up api时,Web API启动后无法连接PostgreSQL,最终出现连接超时错误:
api | Error: connect ETIMEDOUT 172.22.0.2:5432 api | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16) { api | errno: -110, api | code: 'ETIMEDOUT', api | syscall: 'connect', api | address: '172.22.0.2', api | port: 5432 }
我已尝试将API容器中的数据库主机名从postgres改为0.0.0.0、localhost,也尝试使用默认网络替代自定义my-nw网络,但均无效。可以通过主机机器执行psql -U developer -h localhost -p 5432连接PostgreSQL,且该docker-compose文件在本地机器可正常运行,但在虚拟机中失败,请问是否存在配置遗漏?
排查与解决建议
1. 修正docker-compose网络配置语法错误
你的docker-compose文件中,postgres和api服务里的network字段是单数,正确语法应为复数networks。将两处network: - my-nw修改为networks: - my-nw,否则容器无法加入自定义的my-nw网络,导致服务名无法解析通信。
2. 等待PostgreSQL服务就绪后再启动API
depends_on仅保证postgres容器启动,不确保PostgreSQL服务完全就绪。虚拟机性能可能弱于本地,数据库启动较慢,API启动时数据库还未准备好就会超时。可以:
- 在API启动命令中加入等待逻辑,比如使用
wait-for-it脚本:
修改api的command为:
确保sh -c ' wait-for-it postgres:5432 -t 30 && npm run upgrade-docker && if [ "$SEED" = "true" ]; then npm run seed-roles ./src/environments/.env.docker && npm run seed-stores ./src/environments/.env.docker && npm run seed-products ./src/environments/.env.docker fi && npm run start ./src/environments/.env.docker 'wait-for-it脚本已包含在web-api镜像中,或通过volume挂载到容器内。 - 在Node.js代码中添加数据库连接重试逻辑,直到连接成功。
3. 确认PostgreSQL监听配置
进入postgres容器检查监听地址:
docker exec -it postgres bash grep listen_addresses /var/lib/postgresql/data/postgresql.conf
正常应返回listen_addresses = '*',确保PostgreSQL允许所有地址连接。
4. 检查虚拟机防火墙规则
虚拟机的iptables或安全组可能拦截容器间的网络流量。确认docker网段(如172.22.0.0/16)的入站/出站规则允许通信。
5. 验证API的数据库连接配置
确保.env.docker文件中数据库主机配置为postgres(服务名),而非IP或localhost。在docker自定义网络中,服务名会被自动解析为对应容器的IP,这是容器间通信的正确方式。
6. 检查容器网络归属
执行以下命令查看容器所属网络:
docker inspect postgres | grep Networks docker inspect api | grep Networks
确认两个容器都加入了my-nw网络,否则服务名无法解析。
内容的提问来源于stack exchange,提问作者Divya

