You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Docker Compose部署全栈应用时API无法连接PostgreSQL数据库

Docker Compose部署全栈应用时API无法连接PostgreSQL的问题

在Docker Compose部署全栈应用过程中,API无法连接PostgreSQL数据库。已配置DATABASE_URL且该配置在其他设备可正常运行,尝试将localhost改为db、更换端口等操作均无效。以下是相关配置信息及问题排查方案:

.env文件内容

JWT_SECRET="palavrasecreta"
NODE_ENV=production
DATABASE_URL=postgres://postgres:1234@db:5432/postgres

docker-compose.yml配置

version: "3"
services:
  app-front-end:
    build: charllenger-front/.
    container_name: front-end-ui
    expose:
      - 3000
    ports:
      - 3000:3000
    links:
      - api
  api:
    container_name: charllenger-back-end-Api
    build: Full-Stack-charlenger-API/.
    volumes:
      - ./src:/app/src
    expose:
      - 3001
    ports:
      - 3001:3001
    depends_on:
      - db
    command: bash -c 'yarn migration:run && yarn dev'
    links:
      - db

  db:
    container_name: charllenger-Api-postgres
    image: "postgres"
    env_file:
      - Full-Stack-charlenger-API/.env
    expose:
      - 5432
    ports:
      - 5432:5432

TypeORM DataSource配置

import { DataSource } from "typeorm";

require("dotenv").config();

export const AppDataSource = new DataSource({
  type: "postgres",
  host: "database", // 此处存在配置冲突问题

  url: process.env.DATABASE_URL,
  ssl:
    process.env.NODE_ENV === "production"
      ? { rejectUnauthorized: false }
      : false,

  synchronize: false,
  logging: true,
  entities:
    process.env.NODE_ENV === "production"
      ? ["src/entities/*.js"]
      : ["src/entities/*.ts"],
  migrations:
    process.env.NODE_ENV === "production"
      ? ["src/migrations/*.js"]
      : ["src/migrations/*.ts"],
});

AppDataSource.initialize()
  .then(() => {
    console.log("Data Source Initialized");
  })
  .catch((err) => {
    console.error("Error during data source Initialization", err);
  }
);

Migration文件内容

import { MigrationInterface, QueryRunner } from "typeorm";

export class initialMigration1673714934213 implements MigrationInterface {
    name = 'initialMigration1673714934213'

    public async up(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`CREATE TABLE "transaction" ("transaction_id" uuid NOT NULL, "value" numeric NOT NULL, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "debitedAccountAccountId" uuid, "creditedAccountAccountId" uuid, CONSTRAINT "PK_6e02e5a0a6a7400e1c944d1e946" PRIMARY KEY ("transaction_id"))`);
        await queryRunner.query(`CREATE TABLE "user" ("user_id" uuid NOT NULL, "username" character varying NOT NULL, "password" character varying NOT NULL, "account" uuid, CONSTRAINT "REL_4ab2df0a57a74fdf904e0e2708" UNIQUE ("account"), CONSTRAINT "PK_758b8ce7c18b9d347461b30228d" PRIMARY KEY ("user_id"))`);
        await queryRunner.query(`CREATE TABLE "account" ("account_id" uuid NOT NULL, "balance" double precision NOT NULL, CONSTRAINT "PK_ea08b54a9d7322975ffc57fc612" PRIMARY KEY ("account_id"))`);
        await queryRunner.query(`ALTER TABLE "transaction" ADD CONSTRAINT "FK_bbbfcdb3330cc4e5846f2d23200" FOREIGN KEY ("debitedAccountAccountId") REFERENCES "account"("account_id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
        await queryRunner.query(`ALTER TABLE "transaction" ADD CONSTRAINT "FK_4ece0117a7c2689832bab37209b" FOREIGN KEY ("creditedAccountAccountId") REFERENCES "account"("account_id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
        await queryRunner.query(`ALTER TABLE "user" ADD CONSTRAINT "FK_4ab2df0a57a74fdf904e0e27086" FOREIGN KEY ("account") REFERENCES "account"("account_id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`ALTER TABLE "user" DROP CONSTRAINT "FK_4ab2df0a57a74fdf904e0e27086"`);
        await queryRunner.query(`ALTER TABLE "transaction" DROP CONSTRAINT "FK_4ece0117a7c2689832bab37209b"`);
        await queryRunner.query(`ALTER TABLE "transaction" DROP CONSTRAINT "FK_bbbfcdb3330cc4e5846f2d23200"`);
        await queryRunner.query(`DROP TABLE "account"`);
        await queryRunner.query(`DROP TABLE "user"`);
        await queryRunner.query(`DROP TABLE "transaction"`);
    }

}

报错信息

无法连接到数据库,提示连接超时,目标地址为database:5432(与DATABASE_URL中的db:5432不匹配)。

解决方案

1. 修复DataSource的连接配置冲突

TypeORM中同时设置host和url会导致参数冲突,优先使用单独的host配置。解决方式二选一:

  • 删除host: "database"这一行,完全通过DATABASE_URL指定连接信息;
  • 将host值改为"db",与docker-compose中PostgreSQL服务的名称一致。

2. 确保PostgreSQL服务就绪后再启动API

depends_on仅保证容器启动顺序,不保证PostgreSQL服务完全就绪。可以:

  • 在API的启动命令中添加等待脚本,比如使用pg_isready检查数据库状态:
    command: bash -c 'until pg_isready -h db -p 5432 -U postgres; do sleep 1; done; yarn migration:run && yarn dev'
    
  • 为PostgreSQL服务添加健康检查,让docker-compose等待服务就绪后再启动API:
    db:
      # ...其他配置
      healthcheck:
        test: ["CMD-SHELL", "pg_isready -U postgres"]
        interval: 5s
        timeout: 5s
        retries: 5
    api:
      # ...其他配置
      depends_on:
        db:
          condition: service_healthy
    

3. 验证环境变量加载

在API容器启动命令中添加环境变量打印,确认DATABASE_URL是否正确加载:

command: bash -c 'echo $DATABASE_URL; yarn migration:run && yarn dev'

4. 补充PostgreSQL必要环境变量

postgres官方镜像需要POSTGRES_USER、POSTGRES_PASSWORD、POSTGRES_DB这三个环境变量才能正确初始化数据库。可以在.env文件中添加:

POSTGRES_USER=postgres
POSTGRES_PASSWORD=1234
POSTGRES_DB=postgres

内容的提问来源于stack exchange,提问作者Luiz Paulo Reis Cardoso

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 04:15:28