从自托管镜像仓库拉取私有镜像后,Nest.js应用无法连接PostgreSQL数据库
问题分析
报错 getaddrinfo ENOTFOUND db 的核心原因是:Nest.js应用容器无法通过主机名db找到PostgreSQL容器。本地docker compose up能正常运行,是因为Docker Compose会自动创建共享网络,让app和db服务处于同一网络内,容器名可直接作为主机名解析;而单独拉取镜像运行时,应用容器与数据库容器不在同一网络(甚至未启动数据库容器),因此无法解析db主机名。
解决方案
1. 用Docker Compose部署生产环境(推荐)
创建生产专用的docker-compose.prod.yml,将构建好的镜像作为app服务来源,同时保留db服务,确保两者在同一网络内:
services: app: image: 你的自托管镜像仓库地址/镜像名:版本号 ports: - "3000:3000" environment: - SERVER_HOST=0.0.0.0 - SERVER_PORT=3000 - DB_HOST=db - DB_PORT=5432 - DB_USER=postgres - DB_PASS=password - DB_NAME=discussion - DB_SYNC=true - DB_AUTOLOAD=true depends_on: db: condition: service_healthy db: image: postgres environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=password - POSTGRES_DB=discussion healthcheck: test: [ "CMD", "pg_isready", "-q", "-d", "discussion", "-U", "postgres" ] timeout: 45s interval: 10s retries: 10
运行命令:
docker compose -f docker-compose.prod.yml up -d
2. 手动指定Docker网络(适合调试)
若需手动启动容器,先创建自定义网络,让应用与数据库容器加入同一网络:
- 创建自定义网络:
docker network create app-network
- 启动PostgreSQL容器并加入网络:
docker run -d \ --name db \ --network app-network \ -e POSTGRES_USER=postgres \ -e POSTGRES_PASSWORD=password \ -e POSTGRES_DB=discussion \ postgres
- 启动Nest.js应用容器并加入同一网络:
docker run -d \ --name app \ --network app-network \ -p 3000:3000 \ -e DB_HOST=db \ 你的自托管镜像仓库地址/镜像名:版本号
3. 修改DB_HOST为宿主机IP(仅测试用)
若数据库运行在宿主机或使用Docker host网络模式,可将DB_HOST改为宿主机IP(如192.168.1.100),但该方式依赖宿主机环境,不适合生产:
docker run -d \ -p 3000:3000 \ -e DB_HOST=你的宿主机IP \ 你的自托管镜像仓库地址/镜像名:版本号
优化建议
- 不要将.env打包进镜像:当前GitLab CI构建时将
.env复制进镜像,导致DB_HOST=db的配置被硬绑定,灵活性差。建议在Dockerfile中排除.env,运行容器时通过环境变量传递数据库配置。 - 用环境变量注入配置:生产环境中,数据库连接信息(如
DB_HOST、DB_PASS)应通过环境变量注入,而非硬编码在镜像中,以适配不同部署环境。
内容的提问来源于stack exchange,提问作者Mohammad Hossein Dolatabadi
相关产品推荐
相关产品推荐

