Docker正在等待postgresql运行

Docker正在等待postgresql运行,postgresql,docker,Postgresql,Docker,在我的项目中,我正在使用postgresql和django。我把它们放在不同的容器中,问题是在运行django之前我需要等待postgres。此时,我正在使用django容器的command.sh文件中的sleep5执行此操作。我还发现netcat可以做到这一点,但我更喜欢没有额外软件包的方式curl和wget无法执行此操作,因为它们不支持postgres协议。 有办法吗?为什么不卷曲 大概是这样的: while ! curl http://$POSTGRES_PORT_5432_TCP_ADD

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

为什么不卷曲

大概是这样的:

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

你的解决方案tiziano的问题是默认情况下没有安装curl,我想避免安装额外的东西。不管怎样,我还是照贝雷尔说的做了。这是脚本,如果有人需要的话

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)

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

是文档


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

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

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

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
服务:
实习码头工人:
图片:dockerhubusername/practice\u docker
端口:
- 80:3000

命令:bash-c'while 最简单的解决方案是一个简短的bash脚本:

while ! nc -z HOST PORT; do sleep 1; done;
./run-smth-else;
可以在应用程序映像中包含的小包装脚本,用于轮询给定的主机和端口,直到它接受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

我花了几个小时研究这个问题,找到了解决办法。 DOCKER <代码> RealsSon < /COD> >考虑服务启动来运行另一个服务。这是因为只要启动
db
,服务应用程序就会尝试连接到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:
在这种情况下,不需要创建.sh文件。 我希望这对你们有帮助;)
cya

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

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

version: "3"
services:
  postgres:
    image: postgres
  backend:
    build: ./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
其中“实际”命令只是一个
psql--list
,用于说明。然后运行
docker compose build
docker compose up
将为您提供以下输出:

请注意,
psql--list
命令的结果如何仅在
pg_isready
logs
postgres:5432-根据需要接受连接之后显示

相比之下,我发现
nc-z
方法并不一致。例如,如果我将
后端/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
给出以下结果:

也就是说,
psql
命令抛出一个
FATAL
错误,数据库系统正在启动


简而言之,使用
直到pg_isready
循环(也是推荐的)是更好的方法。在
Dockerfile
中添加并更改start命令以使用它:

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\u HOSTS
环境变量:

服务:
应用程序编程接口:
取决于:
-博士后
环境:
-等等主持人:postgres:5432
博士后:
图片:博士后
端口:
- "5432:5432"
这样做的优点是它支持等待多个服务:

环境:
-等等,主机:postgres:5432,mysql:3306,mongo:27017
有关详细信息,请阅读。

#/垃圾箱/垃圾箱
POSTGRES_版本=9.6.11
CONTAINER\u NAME=我的postgres容器
#启动postgres容器
docker run--rm\
--名称$CONTAINER\u名称\
-e POSTGRES_密码=docker\
-d\
-p 5432:5432\
博士后:$postgres\u版本
#等待postgres准备好接受连接
直到docker逃跑\
--rm\
--链接$CONTAINER\u NAME:pg\
博士后:$postgres\u版本pg\u已准备就绪\
-美国博士后\
-h pg;做睡眠1;完成
灵感来自@tiziano和
nc
pg\u的缺失,似乎在最近的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.'

通过向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

来源:

睡眠直到
pg\u isready
返回true。不幸的是,这并不总是可靠的。如果您的postgres容器至少指定了一个initdb脚本,那么即使
pg_isready
已返回true,它也可能尚未就绪

相反,您可以做的是等待该实例的docker日志返回一个
PostgreSQL初始化进程完成;准备启动。
string,然后继续执行
pg\u isready
检查

例如:

start\u postgres(){
docker compose up-d——无需重新创建postgres
}
等待博士后(){
直到docker撰写日志| grep-q“PostgreSQL初始化过程完成;准备启动。”\
&&docker compose exec-T postgres sh-c“PGPASSWORD=\$postgres\u PASSWORD PGUSER=\$postgres\u USER pg\u isready--dbname=\$postgres\u DB”>/dev/null 2>&1;do
printf“\r正在等待postgres容器可用…”
睡眠1
完成
printf
# 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"]