programing

도커 mysql 컨테이너가 가동되고 mysql이 언제 쿼리를 받을 수 있는지 어떻게 알 수 있습니까?

goodsources 2022. 11. 19. 11:37
반응형

도커 mysql 컨테이너가 가동되고 mysql이 언제 쿼리를 받을 수 있는지 어떻게 알 수 있습니까?

나는 몇 개의 다른 도커 컨테이너를 배치하고 있는데, mysql이 첫 번째 컨테이너입니다.데이터베이스가 올라가면 바로 스크립트를 실행하고 다른 컨테이너를 빌드합니다.스크립트는 ( 공식 mysql 컨테이너에서) mysql을 설정하는 엔트리 포인트스크립트가 아직 실행 중일 때 실행하려고 했기 때문에 장애가 발생하고 있습니다.

sudo docker run --name mysql -e MYSQL_ROOT_PASSWORD=MY_ROOT_PASS -p 3306:3306 -d mysql
[..] wait for mysql to be ready [..]
mysql -h 127.0.0.1 -P 3306 -u root --password=MY_ROOT_PASS < MY_SQL_SCRIPT.sql

도커 컨테이너 안에서 엔트리의 poiny mysql 셋업 스크립트가 종료되는 신호를 기다리는 방법이 있습니까?Bash sleep은 차선책처럼 보인다.

EDIT: 이런 bash 스크립트를 사용합니다.가장 우아하고 일종의 짐승 같은 힘은 아니지만 마법처럼 작용한다.아마 누군가는 그게 유용하다고 생각할거야.

OUTPUT="Can't connect"
while [[ $OUTPUT == *"Can't connect"* ]]
do
    OUTPUT=$(mysql -h $APP_IP -P :$APP_PORT -u yyy --password=xxx <       ./my_script.sql 2>&1)
done

mysql-client 패키지를 설치하고 mysqladmin을 사용하여 타깃서버에 ping 할 수 있습니다.여러 개의 도커 컨테이너를 사용할 때 유용합니다.sleep과 조합하여 간단한 대기 루프를 만듭니다.

while ! mysqladmin ping -h"$DB_HOST" --silent; do
    sleep 1
done

이 little bash loop은 mysql이 열리기를 기다리며 추가 패키지를 설치할 필요가 없습니다.

until nc -z -v -w30 $CFG_MYSQL_HOST 3306
do
  echo "Waiting for database connection..."
  # wait for 5 seconds before check again
  sleep 5
done

이것은 다른 답변에 대한 코멘트에서 다소 언급되었지만, 나는 그것이 스스로 기입할 가치가 있다고 생각한다.

먼저 다음과 같은 방법으로 컨테이너를 실행할 수 있습니다.

docker run --name mysql --health-cmd='mysqladmin ping --silent' -d mysql

도커 파일에도 동등한 것이 있습니다.

with with with with withdocker ps ★★★★★★★★★★★★★★★★★」docker inspect이치노 이 는 mysql이라는 이 .mysqladmin컨테이너 내에서 사용할 수 있으므로 도커 호스트에 설치할 필요가 없습니다.

그런 다음 bash 스크립트를 루프하여 상태가 정상화될 때까지 기다릴 수 있습니다.다음 bash 스크립트는 Dennis에 의해 작성되었습니다.

function getContainerHealth {
  docker inspect --format "{{.State.Health.Status}}" $1
}

function waitContainer {
  while STATUS=$(getContainerHealth $1); [ $STATUS != "healthy" ]; do 
    if [ $STATUS == "unhealthy" ]; then
      echo "Failed!"
      exit -1
    fi
    printf .
    lf=$'\n'
    sleep 1
  done
  printf "$lf"
}

이제 스크립트로 다음을 수행할 수 있습니다.

waitContainer mysql

그러면 스크립트는 컨테이너가 가동될 때까지 기다립니다.컨테이너가 비정상적으로 되면 스크립트가 종료됩니다.예를 들어 도커호스트의 메모리가 부족하면 mysql이 충분한 용량을 할당할 수 없습니다.

가 찾은 '아, 아, 아는데요.mysqladmin ping접근 방식이 항상 신뢰할 수 있는 것은 아닙니다. 특히 새로운 DB를 도입하는 경우에는 더욱 그렇습니다.이 경우 서버에 ping을 수행할 수 있더라도 사용자/권한 테이블이 아직 초기화 중이면 연결하지 못할 수 있습니다.신음

while ! docker exec db-container mysql --user=foo --password=bar -e "SELECT 1" >/dev/null 2>&1; do
    sleep 1
done

지금까지 이 방법에는 문제가 없었습니다. 제안을 한 알 수 .mysqladmin ping★★★★★★ 。

포트의 문제는 포트가 열려 있지만 데이터베이스가 아직 준비되지 않았다는 것입니다.

다른 솔루션에서는 mysql o a mysql 클라이언트를 호스트 머신에 설치해야 하지만 실제로는 Docker 컨테이너 안에 이미 설치되어 있기 때문에 다음과 같은 것을 사용하는 것이 좋습니다.

옵션 1:

while ! docker exec mysql mysqladmin --user=root --password=pass --host "127.0.0.1" ping --silent &> /dev/null ; do
    echo "Waiting for database connection..."
     sleep 2
done

옵션 2(@VinGarcia에서):

while ! docker exec container_name mysql --user=root --password=pass -e "status" &> /dev/null ; do
    echo "Waiting for database connection..."
    sleep 2
done   

모든 Linux 디스트리뷰션에서 볼 수 있는 1개의 라이너:

while ! curl -o - db-host:3306; do sleep 1; done

다음 헬스 체크는 모든 mysql 컨테이너에 대해 기능합니다.

db:
    image: mysql:5.7.16
    healthcheck:
      test: ["CMD-SHELL", 'mysql --database=$$MYSQL_DATABASE --password=$$MYSQL_ROOT_PASSWORD --execute="SELECT count(table_name) > 0 FROM information_schema.tables;" --skip-column-names -B']
      interval: 30s
      timeout: 10s
      retries: 4
    extends:
        file: docker-compose-common-config.yml
        service: common_service

그래서 누가 이걸 올렸는지 모르겠어요.아무도 못 본 것 같아서...mysqladmin에는 wait 기능을 가진 명령어가 있습니다.이 명령어는 접속 테스트를 처리하고 내부적으로 재시도하여 완료 시 성공을 반환합니다.

sudo docker run --name mysql -e MYSQL_ROOT_PASSWORD=MY_ROOT_PASS -p 3306:3306 -d mysql
mysqladmin ping -h 127.0.0.1 -u root --password=MY_ROOT_PASS --wait=30 && mysql -h 127.0.0.1 -P 3306 -u root --password=MY_ROOT_PASS < MY_SQL_SCRIPT.sql

은 '우리'입니다.mysqladmin ping -h 127.0.0.1 -u root --password=MY_ROOT_PASS --wait=30 -v--wait접속이 성공할 때까지 대기하는 플래그와 재시도 횟수입니다.

도커 컨테이너 안에서 명령어를 실행하는 것이 이상적이지만, 원래 포스터 명령어를 너무 많이 수정하고 싶지 않았습니다.

초기화를 위해 make 파일에서 사용되는 경우

db.initialize: db.wait db.initialize


db.wait:
  docker-compose exec -T db mysqladmin ping -u $(DATABASE_USERNAME) -p$(DATABASE_PASSWORD) --wait=30 --silent

db.initialize:
  docker-compose exec -T db mysql -u $(DATABASE_USERNAME) -p$(DATABASE_PASSWORD) $(DATABASE_NAME) < dev/sql/base_instance.sql

제 Django 컨테이너가 mysql 컨테이너를 시작한 직후에 연결하려고 했을 때도 같은 문제가 있었습니다.vishnubob의 wait-for.it.sh 스크립트를 사용하여 해결했습니다.계속하기 전에 IP 및 호스트가 준비되기를 기다리는 셸 스크립트입니다.다음은 제가 사용하는 어플리케이션 예시입니다.

./wait-for-it.sh \
    -h $(docker inspect --format '{{ .NetworkSettings.IPAddress }}' $MYSQL_CONTAINER_NAME) \
    -p 3306 \
    -t 90

이 스크립트에서는 mysql 컨테이너에 mysql 포트 3306(기본 mysql 포트)에서 최대 90초(준비되면 정상적으로 실행됨)를 대기하도록 요청하고 있으며, mw를 제외한 다른 변수가 mysql_CONTENER_NAME에 대해 도커에 의해 할당되어 있습니다.

mysql 컨테이너를 기다리는 도커 컨테이너가 파이썬 이미지(예를 들어 Django 응용 프로그램)에 기반하고 있는 경우 아래 코드를 사용할 수 있습니다.

장점은 다음과 같습니다.

  • 이는 wait-for-it.sh에 기반한 것이 아닙니다.이것은 mysql의 IP와 포트가 준비될 때까지 대기하지만 이는 mysql 초기화가 자동으로 완료되었음을 의미하지는 않습니다.
  • 컨테이너에 존재해야 하는 mysql 또는 mysqladmin 실행 파일을 기반으로 하는 셸 스크립트가 아닙니다.컨테이너가 파이썬 이미지를 기반으로 하기 때문에 이미지 위에 mysql을 설치해야 합니다.아래 솔루션에서는 컨테이너에 이미 존재하는 기술인 순수 비단뱀을 사용합니다.

코드:

import time

import pymysql


def database_not_ready_yet(error, checking_interval_seconds):
    print('Database initialization has not yet finished. Retrying over {0} second(s). The encountered error was: {1}.'
          .format(checking_interval_seconds,
                  repr(error)))
    time.sleep(checking_interval_seconds)


def wait_for_database(host, port, db, user, password, checking_interval_seconds):
    """
    Wait until the database is ready to handle connections.

    This is necessary to ensure that the application docker container
    only starts working after the MySQL database container has finished initializing.

    More info: https://docs.docker.com/compose/startup-order/ and https://docs.docker.com/compose/compose-file/#depends_on .
    """
    print('Waiting until the database is ready to handle connections....')
    database_ready = False
    while not database_ready:
        db_connection = None
        try:
            db_connection = pymysql.connect(host=host,
                                            port=port,
                                            db=db,
                                            user=user,
                                            password=password,
                                            charset='utf8mb4',
                                            connect_timeout=5)
            print('Database connection made.')
            db_connection.ping()
            print('Database ping successful.')
            database_ready = True
            print('The database is ready for handling incoming connections.')
        except pymysql.err.OperationalError as err:
            database_not_ready_yet(err, checking_interval_seconds)
        except pymysql.err.MySQLError as err:
            database_not_ready_yet(err, checking_interval_seconds)
        except Exception as err:
            database_not_ready_yet(err, checking_interval_seconds)
        finally:
            if db_connection is not None and db_connection.open:
                db_connection.close()

사용방법:

  1. 파일python 파일)에 합니다.wait-for-mysql-db.py예를 들어 응용 프로그램의 소스 코드 안에 있습니다.
  2. 스크립트 작성(python pythonstartup.py예를 들어, 먼저 위의 코드를 실행한 후 응용 프로그램을 시작합니다.
  3. 응용 프로그램 컨테이너의 Docker 파일이 이 두 개의 python 스크립트를 응용 프로그램의 소스 코드와 함께 Docker 이미지로 패키지하는지 확인하십시오.
  4. command: ["python3", "startup.py"].

이 솔루션은 MySQL 데이터베이스용으로 작성되었습니다.다른 데이터베이스용으로 약간 수정해야 합니다.

저는 새로운 접근방식을 바탕으로 이 문제에 대한 새로운 해결책을 개발했습니다.발견된 모든 접근 방식은 데이터베이스에 대한 연결을 여러 번 시도하거나 컨테이너와의 TCP 연결을 시도하는 스크립트에 의존합니다.자세한 내용은 waitdb 저장소에서 확인할 수 있지만, 컨테이너에서 가져온 로그를 사용하는 것이 해결책입니다.이 스크립트는 로그가 연결 준비가 된 메시지를 시작할 때까지 기다립니다.이 스크립트는 컨테이너가 처음 시작되는지 여부를 식별할 수 있습니다.이 경우 스크립트는 초기 데이터베이스 스크립트가 실행되고 데이터베이스가 재시작될 때까지 대기하며 새로운 연결 준비 메시지를 다시 기다립니다.MySQL 5.7 및 MySQL 8.0에서 이 솔루션을 테스트했습니다.

스크립트 자체(wait_db).sh) :

#!/bin/bash

STRING_CONNECT="mysqld: ready for connections"

findString() {
    ($1 logs -f $4 $5 $6 $7 $8 $9 2>&1 | grep -m $3 "$2" &) | grep -m $3 "$2" > /dev/null
}

echo "Waiting startup..."
findString $1 "$STRING_CONNECT" 1 $2 $3 $4 $5 $6 $7
$1 logs $2 $3 $4 $5 2>&1 | grep -q "Initializing database"
if [ $? -eq 0 ] ; then
    echo "Almost there..."
    findString $1 "$STRING_CONNECT" 2 $2 $3 $4 $5 $6 $7
fi
echo "Server is up!"

이 스크립트는 Docker Compose 또는 Docker 자체에서 사용할 수 있습니다.아래의 예에서 용도가 명확해졌으면 합니다.

예 01: 도커 컴포트와 함께 사용

SERVICE_NAME="mysql" && \
docker-compose up -d $SERVICE_NAME && \
./wait_db.sh docker-compose --no-color $SERVICE_NAME

예 02: 도커와 함께 사용

CONTAINER_NAME="wait-db-test" && \
ISO_NOW=$(date -uIs) && \
  docker run --rm --name $CONTAINER_NAME \
    -e MYSQL_ROOT_PASSWORD=$ROOT_PASSWORD \
    -d mysql:5.7 && \
./wait_db.sh docker --since "$ISO_NOW" $CONTAINER_NAME

예 3: 완전한 예(테스트 케이스)

전체 예는 저장소의 테스트 케이스에서 찾을 수 있습니다.이 테스트 케이스는 새로운 MySQL을 기동하여 더미 데이터베이스를 작성하고 모든 것이 시작될 때까지 기다린 후 모든 것이 정상인지 확인하기 위한 선택을 실행합니다.그런 다음 컨테이너를 다시 시작하고 시작할 때까지 기다린 다음 새 선택을 실행하여 연결 준비가 되었는지 확인합니다.

애덤스 솔루션을 도커 컴포지트 기반 프로젝트에 도입한 방법은 다음과 같습니다.

라는 제목의 bash 파일을 작성했습니다.db-ready.sh내 안에서server컨테이너 폴더(내 컨테이너에 내용이 복사됨 -)server):

#!bin/bash

until nc -z -v -w30 $MYSQL_HOST 3306
do
  echo "Waiting a second until the database is receiving connections..."
  # wait for a second before checking again
  sleep 1
done

그러면 나는 달릴 수 있다.docker-compose run server sh ./db-ready.sh && docker-compose run server yarn run migrate제가 이 프로그램을 실행할 때migrate내 안의 태스크server컨테이너, DB가 연결을 수락하는 것을 알고 있습니다.

bash 파일은 실행하려는 명령어와 별개이므로 이 방법이 좋습니다.쉽게 실행할 수 있습니다.db-ready.sh다른 DB보다 먼저 실행할 수 있습니다.

저는 당신에게 이 제품을 사용하는 것을 추천할 수 있습니다./usr/bin/mysql --user=root --password=root --execute "SHOW DATABASE;"대신 헬스 체크스크립트로mysqladmin ping실제 초기화를 기다리고 클라이언트 접속을 위한 서비스를 준비합니다.

예:

  docker run -d --name "test-mysql-client" -p 0.0.0.0:3306:3306 -e MYSQL_PASSWORD=password -e MYSQL_USER=user -e MYSQL_ROOT_PASSWORD=root --health-cmd="/usr/bin/mysql --user=root --password=root --execute \"SHOW DATABASE;\"" --health-interval=1s --health-retries=60 --health-timeout=10s -e MYSQL_DATABASE=db  mysql:latest```

플라미스트답변과 네이선 아서의 코멘트를 조합하면, 이 답변이 가장 편리하다고 생각합니다.

CONTAINER_MYSQL='' # name of the MySQL container
CONTAINER_DB_HOST='127.0.0.1'
CONTAINER_DB_PORT=3306
MYSQL_USER='' # user name if there is, normally 'root'
MYSQL_PWD='' # password you set

is_mysql_alive() {
  docker exec -it ${CONTAINER_MYSQL} \
    mysqladmin ping \
      --user=${MYSQL_USER} \
      --password=${MYSQL_PWD} \
      --host=${CONTAINER_DB_HOST} \
      --port=${CONTAINER_DB_PORT} \
    > /dev/null
  returned_value=$?
  echo ${returned_value}
}

until [ "$(is_mysql_alive)" -eq 0 ]
do
  sleep 2
  echo "Waiting for MySQL to be ready..."
done

anything_else_to_do

기본적으로, 이 체크는mysqladmin는 MySQL 컨테이너에 존재하며, 존재한다면 MySQL이 가동되어야 합니다.

위의 Mihai Craiăur 훌륭한 답변을 바탕으로 CURL 옵션에 0.9를 활성화하고(기본적으로 비활성화), 부팅 시 로그 "노이즈"를 줄이기 위해 출력을 숨깁니다.

server="MyServerName"
echo "Waiting for MySQL at ${server}"
while ! curl --http0.9 -o - "${server}:3306" &> /dev/null; do sleep 1; done

https://github.com/docker-library/mysql/blob/master/5.7/docker-entrypoint.sh 도커 엔트리 포인트sh는 아직 맞춤형 .sql 병합을 지원하지 않습니다.

도커 진입점을 변경할 수 있을 것 같습니다.sh: mysql 인스턴스가 준비되면 실행할 수 있도록 sql을 Marge합니다.

온 유저희쪽에서ENTRYPOINT스크립트는 MySQL 연결이 유효한지 확인해야 합니다.

이 솔루션에서는 컨테이너에 MySQL Client를 설치할 필요가 없습니다.또한 컨테이너를 실행하는 동안php:7.0-fpm입니다.nc설치도 필요했기 때문에 선택사항이 아니었습니다.또, 포토가 열려 있는지를 확인한다고 해서, 반드시 서비스가 정상적으로 동작해, 공개되고 있는 것은 아닙니다.[더 많이]

이 솔루션에서는 MySQL Container가 접속할 수 있는지 확인하기 위해 PHP 스크립트를 실행하는 방법을 보여 줍니다.이것이 왜 더 나은 방법인지 알고 싶다면, 제 의견을 확인해 보세요.

★★entrypoint.sh

#!/bin/bash
cat << EOF > /tmp/wait_for_mysql.php
<?php
\$connected = false;
while(!\$connected) {
    try{
        \$dbh = new pdo( 
            'mysql:host=mysql:3306;dbname=db_name', 'db_user', 'db_pass',
            array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
        );
        \$connected = true;
    }
    catch(PDOException \$ex){
        error_log("Could not connect to MySQL");
        error_log(\$ex->getMessage());
        error_log("Waiting for MySQL Connection.");
        sleep(5);
    }
}
EOF
php /tmp/wait_for_mysql.php
# Rest of entry point bootstrapping

이를 실행하면 유효한 MySQL Connection이 설정될 때까지 컨테이너의 부트스트래핑 논리를 차단합니다.

다음 코드를 사용합니다.

COMPROJECT_NAME=web을 내보냅니다.

IS_DATA_CONTENER_EXIST=$(도커볼륨 ls | grep ${COMPOSE_PROJE_NAME}_sqldata)를 내보냅니다.

docker-compose up -d;
docker-compose ps;

export NETWORK_GATEWAY=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}' ${COMPOSE_PROJECT_NAME}_webserver1_con);

언급URL : https://stackoverflow.com/questions/25503412/how-do-i-know-when-my-docker-mysql-container-is-up-and-mysql-is-ready-for-taking

반응형