我在我的项目中使用带有django的postgresql。我已经将它们放在不同的容器中,问题是我需要在运行django之前等待postgres。这时我在django容器的command.sh文件中使用sleep 5
。我还发现netcat可以做到这一点,但我更喜欢没有额外包的方式。 curl和wget不能这样做,因为他们不支持postgres协议。
有办法吗?
答案 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
答案 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 build
和docker-compose up
将为您提供以下输出:
请注意,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
的结果如下:
也就是说,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 answer 和 nc
或 pg_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)