首页 > 解决方案 > 等待服务数据库在 Docker 中运行的其他服务之前运行

问题描述

我正在尝试运行我的应用程序,depends_on我在 Docker 中的 Postgresql 假设我的数据库 PostgreSQL 现在没有运行

在我的docker-compose.yml

version: "3"
services:
  myapp:
    depends_on:
      - db
    container_name: myapp
    build:
      context: .
      dockerfile: Dockerfile
    restart: on-failure
    ports:
      - "8100:8100"

  db:
    container_name: postgres
    restart: on-failure
    image: postgres:10-alpine
    ports:
      - "5555:5432"
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: 12345678
      POSTGRES_DB: dev

当我尝试docker-compose up -d是它创建postgres 然后创建该myapp服务但似乎我的 Postgresql 尚未运行,完成安装和运行后myapp,它说:

my database server not running yet

如何让myapp运行直到该db服务知道我的db运行?

标签: postgresqldockerdocker-compose

解决方案


文档depends_on说:

depends_on在开始之前不会等待db“准备好” myapp- 直到它已经开始。

因此,在运行您的应用程序之前,您必须自己检查您的数据库是否已准备好。

Docker 有一个文档解释了如何编写包装脚本来做到这一点:

#!/bin/sh
# wait-for-postgres.sh

set -e

host="$1"
shift
cmd="$@"

until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "postgres" -c '\q'; do
  >&2 echo "Postgres is unavailable - sleeping"
  sleep 1
done

>&2 echo "Postgres is up - executing command"
exec $cmd

然后,您可以在 docker-compose 文件中运行您的应用程序之前调用此脚本:

command: ["./wait-for-postgres.sh", "db", "python", "app.py"]

还有一些工具,例如wait-for-itdockerizewait-for


然而,这些解决方案有一些限制,Docker 说:

最好的解决方案是在您的应用程序代码中执行此检查,无论是在启动时还是由于任何原因失去连接时。

这种方法会更有弹性。

以下是我在 javascript 中使用重试策略的方法:

  async ensureConnection () {
    let retries = 5
    const interval = 1000

    while (retries) {
      try {
        await this.utils.raw('SELECT \'ensure connection\';')
        break
      } catch (err) {
        console.error(err)
        retries--
        console.info(`retries left: ${retries}, interval: ${interval} ms`)
        if (retries === 0) {
          throw err
        }
        await new Promise(resolve => setTimeout(resolve, interval))
      }
    }
  }

推荐阅读