如何在使用docker-compose时从node容器连接到postgres容器

134次阅读
没有评论

问题描述

在使用docker-compose时遇到了问题:他想从一个node应用容器连接到一个postgres数据库容器,但在使用docker-compose后无法成功连接。以下是他的docker-compose.yml文件:

version: '3.7'
services:
  db:
    image: postgres:12.1
    ports:
      - "5432:5432"
    env_file:
      - "./.env"
    networks:
      - tcp-modbus
    volumes:
      - ./modbustcp.sql:/docker-entrypoint-initdb.d/init.sql
  redis:
    image: redis:5.0.6
    ports:
      - "6379:6379"
    networks:
      - tcp-modbus
  rabbit:
    image: "rabbitmq"
    environment:
      RABBITMQ_ERLANG_COOKIE: "SWQOKODSQALRPCLNMEQG"
      RABBITMQ_DEFAULT_USER: "*"
      RABBITMQ_DEFAULT_PASS: "*"
      RABBITMQ_DEFAULT_VHOST: "/"
    ports:
      - "15672:15672"
      - "5672:5672"
    volumes:
      - "./enabled_plugins:/etc/rabbitmq/enabled_plugins"
    networks:
      - tcp-modbus
  modbus-tcp:
    image: customImage
    ports:
      - "8080:3000"
    links:
      - "db"
    volumes:
      - "./modbus.env:/usr/src/app/.env"
    networks:
      - tcp-modbus
networks:
  tcp-modbus:
    driver: bridge

他使用typeorm来设置node应用的连接,但在docker化应用后,无法连接到postgresql容器。他猜测这可能与容器的主机名有关,因为他在连接postgresql容器时使用了localhost。他想知道是否可以使用容器网络作为连接postgresql的主机名。

解决方案

请注意以下操作可能因版本差异而异,同时在开始操作前请做好备份。

使用docker-compose的内部DNS解决方案

在docker-compose中,每个服务都有一个内部DNS名。在你的示例中,服务的名称也是DNS名称。例如,数据库的DNS名是db。如果在node应用中将其配置为主机名,那么应该能够访问数据库。

可以使用以下步骤来配置连接:
1. 在node应用中,将数据库主机名配置为db
2. 使用docker-compose构建和运行应用。

以下是一个示例的node应用配置:

const connectionOptions = {
  type: "postgres",
  host: "db", // 使用服务名称作为主机名
  port: 5432,
  username: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
  synchronize: true,
  logging: true,
  entities: ["src/entities/**/*.ts"],
  migrations: ["src/migrations/**/*.ts"],
  subscribers: ["src/subscribers/**/*.ts"],
  cli: {
    entitiesDir: "src/entities",
    migrationsDir: "src/migrations",
    subscribersDir: "src/subscribers",
  },
};

createConnection(connectionOptions)
  .then(async (connection) => {
    console.log("Connected to the database");
    // Your app logic here
  })
  .catch((error) => console.log("Error: ", error));

这样,你的node应用将会使用服务名称db作为主机名来连接到postgres数据库容器。

确保容器启动顺序

你提到在应用容器启动之前,其他服务容器已经启动。为了确保服务容器按照正确的顺序启动,你可以使用depends_on标签。然而,你提到rabbit容器在应用容器之后启动,可能是因为depends_on并不能完全控制容器的启动顺序。

解决这个问题的一种方法是编写一个启动脚本,以确保容器按照正确的顺序启动。以下是一个示例的bash脚本,它可以在容器A启动后启动其他服务容器:

#!/bin/bash
# 启动数据库容器
docker-compose up -d db
# 等待数据库容器完全启动
while ! docker exec db pg_isready; do
  sleep 1
done
# 启动其他服务容器
docker-compose up -d redis rabbit modbus-tcp
# 启动应用容器
docker-compose up -d node_app

在这个脚本中,我们首先使用docker-compose up -d db命令启动数据库容器。然后,使用一个循环来等待数据库容器完全启动(这里是通过运行pg_isready命令来测试)。一旦数据库容器就绪,我们再使用docker-compose up -d命令依次启动其他服务容器和应用容器。

请根据你的实际情况进行调整和修改。这种方法确保了容器按照正确的顺序启动,从而解决了容器启动顺序的问题。

请注意,上述解决方案可能会因为Docker版本、Compose版本等因素而略有不同。请根据你的实际情况进行调整。

正文完