programing

도커가 postgresql이 실행될 때까지 기다립니다.

linuxpc 2023. 5. 21. 11:01
반응형

도커가 postgresql이 실행될 때까지 기다립니다.

저는 프로젝트에서 django와 함께 postgresql을 사용하고 있습니다.저는 그것들을 다른 컨테이너에 넣었고 문제는 제가 django를 실행하기 전에 postgres를 기다려야 한다는 것입니다.이 시간에 저는 그것을 하고 있습니다.sleep 5command.shcontainer.django 파일입니다.을 할 수 있다는 패키지가 방법을 선호합니다. netcat과 netcat의 차이점은 무엇입니까? curl그리고.wgetPostgres 프로토콜을 지원하지 않기 때문에 이 작업을 수행할 수 없습니다.할 수 있는 방법이 있습니까?

저는 이 문제를 조사하는 데 몇 시간이 걸렸고 해결책을 찾았습니다.depends_on다른 서비스를 실행하려면 서비스 시작을 고려하십시오.그렇게 되는 것보다 더 빨리db시작되면 의 시됨앱, 에 연결하려고 .db연결을 수신할 준비가 되지 않았습니다.확인하실 수 있습니다.db연결을 기다리는 앱 서비스의 상태입니다.여기 제 해결책이 있습니다. Docker-compose version2.1을 하고 있습니다. :) ::) 2을 사용하고 도커 컴포지션 버전 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 파일을 생성할 필요가 없습니다.

이렇게 하면 Postgres가 시작될 때까지 성공적으로 대기합니다(특히 6행).교체하기만 하면 됩니다.npm startPostgres가 시작된 후에 당신이 하고 싶은 어떤 명령으로도.

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

가지고 계신다면,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

가장 간단한 솔루션은 짧은 bash 스크립트입니다.

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

당신의 솔루션 티지아노의 문제는 컬이 기본적으로 설치되어 있지 않다는 것이고 나는 추가적인 것들을 설치하는 것입니다.어쨌든 나는 비리얼이 말한 대로 했습니다.필요한 사람이 있다면 여기 대본이 있습니다.

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)

의 신의에서.Dockerfilewait를 추가하고 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.ymla를 추가합니다.WAIT_HOSTS 서비스에대한 :api 파일:

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

자세한 내용은 해당 설명서를 참조하십시오.

응용 프로그램 이미지에 포함하여 TCP 연결을 허용할 때까지 지정된 호스트 및 포트를 폴링할 수 있는 wait-for-it 작은 래퍼 스크립트입니다.

아래 명령을 사용하여 도커 파일에서 복제할 수 있습니다.

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

도커-docker.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

왜 컬 안 해요?

이와 같은 것:

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

저한테는 효과가 있어요.

도커 합성 정의에 헬스 체크를 추가하여 문제를 해결할 수 있었습니다.

  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

백엔드 응용 프로그램 자체에 Postgre가 있는 경우SQL 클라이언트에서 명령을 사용할 수 있습니다.until를 들어,과 같은 구조를 가정합니다. 예를 들어, 다음과 같은 프로젝트 디렉토리 구조를 가지고 있다고 가정합니다.

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

docker-compose.yml

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

a 리고a.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

'http서 '명은'입니다.psql --list예를 들어그 때 달리기docker-compose build그리고.docker-compose up출력을 합니다.

여기에 이미지 설명 입력

의결를기다니의 나오는지 .psql --list는 은령다만표니다시됩에음명다▁appears 뒤에만 .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잘못을 저지르다the database system is starting up.

간단히 말해서, an을 사용합니다.until pg_isready루프(여기서도 권장됨)가 선호되는 접근 방식 IMO입니다.

다른 답변과 같이 몇 가지 해결책이 있습니다.

, 와 Fail-Fast를 하도록 하세요.restart: on-failure서비스가 DB에 대한 연결을 열어서 처음에 실패할 수 있습니다.그냥 실패하게 둬.도커가 녹색이 될 때까지 서비스를 다시 시작합니다.서비스를 단순하고 비즈니스 중심으로 유지합니다.

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

재시작 정책을 확인합니다.

다음을 제외하고는 다른 솔루션이 작동하지 않았습니다.

version : '3.8'
services :
  postgres :
    image : postgres:latest
    environment :
      - POSTGRES_DB=mydbname
      - POSTGRES_USER=myusername
      - POSTGRES_PASSWORD=mypassword
    healthcheck :
      test: [ "CMD", "pg_isready", "-q", "-d", "mydbname", "-U", "myusername" ]
      interval : 5s
      timeout : 5s
      retries : 5
  otherservice:
    image: otherserviceimage
    depends_on :
      postgres:
        condition: service_healthy

이 스레드 덕분에: https://github.com/peter-evans/docker-compose-healthcheck/issues/16

잠잘때까지pg_isreadytrue를 반환하지만 항상 신뢰할 수 있는 것은 아닙니다.postgres 컨테이너에 하나 이상의 initdb 스크립트가 지정된 경우 부트스트랩 절차 중에 시작된 postgres가 다시 시작되므로 아직 준비되지 않았을 수 있습니다.pg_isready이미 true로 반환되었습니다.

될 때까지 .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

.py "를 사용하여 를 사용할 수 수 없는 경우 py 명령 "check"를 사용하여 데이터베이스를 사용할 수 있는지 확인합니다(사용할 수 없는 경우 2초간 기다렸다가 다시 확인).예를 들어, 당신이 이것을 당신의 안에서 한다면,command.sh마이그레이션을 실행하기 전에 파일, 마이그레이션 명령을 실행하는 동안 Django에 유효한 DB 연결이 있습니다.

...
echo "Waiting for db.."
python manage.py check --database default > /dev/null 2> /dev/null
until [ $? -eq 0 ];
do
  sleep 2
  python manage.py check --database default > /dev/null 2> /dev/null
done
echo "Connected."
# Migrate the last database changes
python manage.py migrate
...

PS: 저는 껍데기 전문가가 아닙니다. 개선점을 제시해 주십시오.

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

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"]

한 줄 명령으로 실행하려는 경우.컨테이너에 연결하여 postgres가 실행 중인지 확인하면 됩니다.

docker exec -it $DB_NAME bash -c "\
until psql -h $HOST -U $USER -d $DB_NAME-c 'select 1'>/dev/null 2>&1;\
do\
  echo 'Waiting for postgres server....';\
  sleep 1;\
done;\
exit;\
"
echo "DB Connected !!"

@tiziano 답변과 부족함에 영감을 받았습니다.nc또는pg_isready되는 최근 이미지(python: 여기 과 같은 되는 것 .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.'

많은 방법으로 시도해보니 도커파일, 도커구성 yaml, bash스크립트가 있습니다.: 마막방도됩움니다이만법지▁with다▁only됩▁help.makefile.

docker-compose up --build -d postgres
sleep 2
docker-compose up --build -d app

컨테이너 내의 Postgres 데이터베이스가 준비될 때까지 기다리려고 했습니다. Java만 사용합니다.제가 한 일은 다음과 같습니다.

다음 레코드를 사용하여 Postgres 데이터베이스가 있는 컨테이너를 나타냅니다.

public record DBContainer(String containerId, String driverClassName, String url, String username, String password) {}

그런 다음 이 메서드는 컨테이너가 준비될 때까지 기다립니다.

private static void waitForPostgresContainerToBeReady(DBContainer dbContainer) throws InterruptedException {
    while (!containerIsReady(dbContainer)) {
        System.err.println(String.format("Container %s is not ready", dbContainer.containerId()));
        Thread.sleep(Duration.ofMillis(300));
    }
    System.out.println(String.format("Container %s is ready", dbContainer.containerId()));
}

추가 도우미 방법:

// Check if the postgres database whithin the container is ready by trying to open a connection to it.
private static boolean containerIsReady(DBContainer dbContainer) {
    try {
        DataSource dataSource = getDataSource(dbContainer);
        Connection connection = dataSource.getConnection();
        boolean isOpen = !connection.isClosed();
        if (isOpen) {
            connection.close();
        }
        return isOpen;
    } catch (SQLException e) {
        return false;
    }
}

// Get a datasource from a DBContainer
public static DataSource getDataSource(DBContainer container) {
    DataSource dataSource = DataSourceBuilder.create()
            .driverClassName(container.driverClassName())
            .url(container.url())
            .username(container.username())
            .password(container.password())
            .build();
    return dataSource;
}

언급URL : https://stackoverflow.com/questions/35069027/docker-wait-for-postgresql-to-be-running

반응형