Docker 等待 postgresql 运行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35069027/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 06:09:37  来源:igfitidea点击:

Docker wait for postgresql to be running

postgresqldocker

提问by Quba

I am using postgresql with django in my project. i've got them in different containers and the problem is that i need to wait for postgres before running django. At this time i am doing it with sleep 5in command.sh file for django container. I also found that netcat can do the trick but i would prefer way without additional packages. curl and wget can't do this because they do not support postgres protocol. Is there a way to do it?

我在我的项目中使用 postgresql 和 django。我将它们放在不同的容器中,问题是我需要在运行 django 之前等待 postgres。此时,我sleep 5在 django 容器的 command.sh 文件中执行此操作。我还发现 netcat 可以做到这一点,但我更喜欢没有额外包的方式。curl 和 wget 不能这样做,因为它们不支持 postgres 协议。有没有办法做到这一点?

采纳答案by Quba

Problem with your solution tiziano is that curl is not installed by default and i wanted to avoid installing additional stuff. Anyway i did what bereal said. Here is the script if anyone would need it.

您的解决方案 tiziano 的问题是默认情况下未安装 curl,我想避免安装其他内容。无论如何,我做了bereal所说的。如果有人需要,这里是脚本。

import socket
import time
import os

port = int(os.environ["DB_PORT"]) # 5432

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
while True:
    try:
        s.connect(('myproject-db', port))
        s.close()
        break
    except socket.error as ex:
        time.sleep(0.1)

回答by Mário Pinhal

If you have psqlyou could simply add the following code to your .sh file:

如果你有,psql你可以简单地将以下代码添加到 .sh 文件中:

RETRIES=5

until psql -h $PG_HOST -U $PG_USER -d $PG_DATABASE -c "select 1" > /dev/null 2>&1 || [ $RETRIES -eq 0 ]; do
  echo "Waiting for postgres server, $((RETRIES--)) remaining attempts..."
  sleep 1
done

回答by Alister

This will successfully wait for Postgres to start. (Specifically line 6). Just replace npm startwith whatever command you'd like to happen after Postgres has started.

这将成功等待 Postgres 启动。(特别是第 6 行)。只需用npm start您希望在 Postgres 启动后发生的任何命令替换即可。

services:
  practice_docker: 
    image: dockerhubusername/practice_docker
    ports: 
      - 80:3000
    command: bash -c 'while !</dev/tcp/db/5432; do sleep 1; done; npm start'
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgres://postgres:password@db:5432/practicedocker
      - PORT=3000   
  db:
    image: postgres
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=practicedocker

回答by Vinicius Chan

I've spent some hours investigating this problem and I got a solution. Docker depends_onjust consider service startup to run another service. Than it happens because as soon as dbis started, service-app tries to connect to ur db, but it's not ready to receive connections. So you can check dbhealth status in app service to wait for connection. Here is my solution, it solved my problem. :) Important: I'm using docker-compose version 2.1.

我花了几个小时调查这个问题,我得到了一个解决方案。Dockerdepends_on只是考虑服务启动来运行另一个服务。之所以会发生这种情况,是因为一旦db启动, service-app 就会尝试连接到 ur db,但还没有准备好接收连接。因此您可以db在应用服务中检查健康状态以等待连接。这是我的解决方案,它解决了我的问题。:) 重要提示:我使用的是 docker-compose 2.1 版。

version: '2.1'

services:
  my-app:
    build: .
    command: su -c "python manage.py runserver 0.0.0.0:8000"
    ports:
       - "8000:8000"
    depends_on:
      db:
        condition: service_healthy
    links:
      - db
    volumes:
      - .:/app_directory

  db:
    image: postgres:10.5
    ports:
      - "5432:5432"
    volumes:
      - database:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  database:

In this case it's not necessary to create a .sh file. I hope it helps you guys ;) cya

在这种情况下,不需要创建 .sh 文件。我希望它可以帮助你们;) cya

回答by Pifagorych

The simplest solution is a short bash script:

最简单的解决方案是一个简短的 bash 脚本:

while ! nc -z HOST PORT; do sleep 1; done;
./run-smth-else;

回答by veeresh yh

wait-for-itsmall wrapper scripts which you can include in your application's image to poll a given host and port until it's accepting TCP connections.

等待它的小型包装脚本,您可以将其包含在应用程序的映像中以轮询给定的主机和端口,直到它接受 TCP 连接。

can be cloned in Dockerfile by below command

可以通过以下命令在 Dockerfile 中克隆

RUN git clone https://github.com/vishnubob/wait-for-it.git

docker-compose.yml

docker-compose.yml

version: "2"
services:
   web:
     build: .
     ports:
       - "80:8000"
     depends_on:
       - "db"
     command: ["./wait-for-it/wait-for-it.sh", "db:5432", "--", "npm",  "start"]
   db:
     image: postgres

回答by Kurt Peek

If the backend application itself has a PostgreSQL client, you can use the pg_isreadycommand in an untilloop. For example, suppose we have the following project directory structure,

如果后端应用程序本身具有 PostgreSQL 客户端,则可以pg_isreadyuntil循环中使用该命令。例如,假设我们有以下项目目录结构,

.
├── backend
│?? └── Dockerfile
└── docker-compose.yml

with a docker-compose.yml

docker-compose.yml

version: "3"
services:
  postgres:
    image: postgres
  backend:
    build: ./backend

and a backend/Dockerfile

和一个 backend/Dockerfile

FROM alpine
RUN apk update && apk add postgresql-client
CMD until pg_isready --username=postgres --host=postgres; do sleep 1; done \
    && psql --username=postgres --host=postgres --list

where the 'actual' command is just a psql --listfor illustration. Then running docker-compose buildand docker-compose upwill give you the following output:

其中“实际”命令仅psql --list用于说明。然后运行docker-compose builddocker-compose up将为您提供以下输出:

enter image description here

enter image description here

Note how the result of the psql --listcommand only appears after pg_isreadylogs postgres:5432 - accepting connectionsas desired.

请注意psql --list命令的结果如何仅出现在所需的pg_isready日志之后postgres:5432 - accepting connections

By contrast, I have found that the nc -zapproach does not work consistently. For example, if I replace the backend/Dockerfilewith

相比之下,我发现这种nc -z方法并不一致。例如,如果我backend/Dockerfile

FROM alpine
RUN apk update && apk add postgresql-client
CMD until nc -z postgres 5432; do echo "Waiting for Postgres..." && sleep 1; done \
    && psql --username=postgres --host=postgres --list

then docker-compose buildfollowed by docker-compose upgives me the following result:

然后docker-compose build跟着docker-compose up给我以下结果:

enter image description here

enter image description here

That is, the psqlcommand throws a FATALerror that the database system is starting up.

也就是说,该psql命令会抛出一个FATAL错误,即the database system is starting up.

In short, using an until pg_isreadyloop (as also recommended here) is the preferable approach IMO.

简而言之,使用until pg_isready循环(这里也推荐)是 IMO 的首选方法。

回答by tiziano

Why not curl?

为什么不卷曲?

Something like this:

像这样的东西:

while ! curl http://$POSTGRES_PORT_5432_TCP_ADDR:$POSTGRES_PORT_5432_TCP_PORT/ 2>&1 | grep '52'
do
  sleep 1
done

It works for me.

这个对我有用。

回答by Nicu Surdu

In your Dockerfileadd waitand change your start command to use it:

Dockerfile添加等待并更改启动命令以使用它:

ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.7.3/wait /wait
RUN chmod +x /wait

CMD /wait && npm start

Then, in your docker-compose.ymladd a WAIT_HOSTSenvironment variable for your api service:

然后,在您的 api 服务中docker-compose.yml添加一个WAIT_HOSTS环境变量:

services:
  api: 
    depends_on:
      - db
    environment:
      - WAIT_HOSTS: postgres:5432
  postgres:
    image: postgres
    ports:
      - "5432:5432"

This has the advantage that it supports waiting for multiple services:

这样做的好处是它支持等待多个服务:

environment:
  - WAIT_HOSTS: postgres:5432, mysql:3306, mongo:27017

For more details, please read their documentation.

有关更多详细信息,请阅读他们的文档

回答by wilsonpage

#!/bin/sh

POSTGRES_VERSION=9.6.11
CONTAINER_NAME=my-postgres-container

# start the postgres container
docker run --rm \
  --name $CONTAINER_NAME \
  -e POSTGRES_PASSWORD=docker \
  -d \
  -p 5432:5432 \
  postgres:$POSTGRES_VERSION

# wait until postgres is ready to accept connections
until docker run \
  --rm \
  --link $CONTAINER_NAME:pg \
  postgres:$POSTGRES_VERSION pg_isready \
    -U postgres \
    -h pg; do sleep 1; done