Docker等待postgresql运行

时间:2016-01-28 18:17:59

标签: postgresql docker

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

16 个答案:

答案 0 :(得分:18)

如果您有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

答案 1 :(得分:13)

这将成功等待Postgres开始。 (特别是第6行)。只需将explicit替换为Postgres启动后您想要发生的任何命令。

npm start

答案 2 :(得分:8)

您的解决方案问题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)

答案 3 :(得分:8)

在您的Dockerfile中添加wait并更改您的启动命令以使用它:

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

CMD /wait && npm start

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

services:
  api: 
    depends_on:
      - postgres
    environment:
      - WAIT_HOSTS: postgres:5432

  postgres:
    image: postgres
    ports:
      - "5432:5432"

其优点是它支持等待多个服务:

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

有关更多详细信息,请阅读their documentation

答案 4 :(得分:5)

wait-for-it小型包装脚本,您可以将其包含在应用程序的图像中,以轮询给定的主机和端口,直到接受TCP连接为止。

可以通过以下命令

克隆到Dockerfile中
RUN git clone https://github.com/vishnubob/wait-for-it.git

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

答案 5 :(得分:4)

通过向 docker-compose 定义添加健康检查,我设法解决了我的问题。

  db:
    image: postgres:latest
    ports:
      - 5432:5432
    healthcheck:
      test: "pg_isready --username=postgres && psql --username=postgres --list"
      timeout: 10s
      retries: 20

然后在依赖的服务中可以查看健康状态:

  my-service:
    image: myApp:latest
    depends_on:
      kafka:
        condition: service_started
      db:
        condition: service_healthy

来源:https://docs.docker.com/compose/compose-file/compose-file-v2/#healthcheck

答案 6 :(得分:4)

提到的其他答案有几种解决方案。

最简单的解决方案是让它与 restart: on-failure 结合使用快速失败。您的服务将打开与数据库的连接,并可能在第一次失败。就让它失败吧。 Docker 将重新启动您的服务,直到它变绿。保持您的服务简单且以业务为中心。

version: '3.7'

services:

  postgresdb:
    hostname: postgresdb
    image: postgres:12.2
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=Ceo

  migrate:
    image: hanh/migration
    links:
      - postgresdb
    environment:
      - DATA_SOURCE=postgres://user:secret@postgresdb:5432/Ceo
    command: migrate sql --yes
    restart: on-failure # will restart until it's success

查看restart policies

答案 7 :(得分:2)

为什么不卷曲?

这样的事情:

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

它对我有用。

答案 8 :(得分:2)

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

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

带有docker-compose.yml

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

和一个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

其中“ actual”命令只是一个psql --list进行说明。然后运行docker-compose builddocker-compose up将为您提供以下输出:

enter image description here

请注意,psql --list命令的结果仅在pg_isready根据需要记录postgres:5432 - accepting connections后出现。

通过对比,我发现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

然后docker-compose build后跟docker-compose up的结果如下:

enter image description here

也就是说,psql命令引发了FATAL的{​​{1}}错误。

简而言之,使用the database system is starting up循环(也建议使用here)是IMO的首选方法。

答案 9 :(得分:1)

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

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

答案 10 :(得分:1)

我花了几个小时研究这个问题,然后找到了解决方案。 DockerDepends_on只是考虑启动服务来运行另一个服务。发生这种情况的原因是,一旦db启动,service-app就会尝试连接到ur 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:

在这种情况下,无需创建.sh文件。 希望对您有帮助;) cya

答案 11 :(得分:0)

#!/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

答案 12 :(得分:0)

受@tiziano answerncpg_isready 的启发,似乎在最近的 docker python 映像(此处为 python:3.9)中默认安装了 curl 并且我的 entrypoint.sh 中运行了以下检查:

postgres_ready() {
    $(which curl) http://$DBHOST:$DBPORT/ 2>&1 | grep '52'
}

until postgres_ready; do
  >&2 echo 'Waiting for PostgreSQL to become available...'
  sleep 1
done
>&2 echo 'PostgreSQL is available.'

答案 13 :(得分:0)

不幸的是,一直睡到 pg_isready 返回 true 并不总是可靠的。如果您的 postgres 容器至少指定了一个 initdb 脚本 postgres restarts after it is started during it's bootstrap procedure,那么即使 pg_isready 已经返回 true,它也可能尚未准备好。

您可以做的是,等待该实例的 docker 日志返回 PostgreSQL init process complete; ready for start up. 字符串,然后再进行 pg_isready 检查。

示例:

start_postgres() {
  docker-compose up -d --no-recreate postgres
}

wait_for_postgres() {
  until docker-compose logs | grep -q "PostgreSQL init process complete; ready for start up." \
    && docker-compose exec -T postgres sh -c "PGPASSWORD=\$POSTGRES_PASSWORD PGUSER=\$POSTGRES_USER pg_isready --dbname=\$POSTGRES_DB" > /dev/null 2>&1; do
    printf "\rWaiting for postgres container to be available ... "
    sleep 1
  done
  printf "\rWaiting for postgres container to be available ... done\n"
}

start_postgres
wait_for_postgres

答案 14 :(得分:0)

Nodejs 和 Postgres api 的示例。

#!/bin/bash
#entrypoint.dev.sh
echo "Waiting for postgres to get up and running..."
while ! nc -z postgres_container 5432; do
  # where the postgres_container is the hos, in my case, it is a Docker container.
  # You can use localhost for example in case your database is running locally.
  echo "waiting for postgress listening..."
  sleep 0.1
done
echo "PostgreSQL started"

yarn db:migrate

yarn dev
# Dockerfile
FROM node:12.16.2-alpine

ENV NODE_ENV="development"

RUN mkdir -p /app

WORKDIR /app

COPY ./package.json ./yarn.lock ./

RUN yarn install

COPY . .

CMD ["/bin/sh", "./entrypoint.dev.sh"]

答案 15 :(得分:-3)

也许您可以使用docker compose来管理您的容器。

Here是文档。

在其yaml文件中,您可以设置links属性以表示服务之间的依赖关系。然后,服务将按您的意愿启动。