[mysql] Docker 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

도커 컨테이너 내부에서 끝나는 진입 점 mysql 설정 스크립트의 신호를 기다리는 방법이 있습니까? 배쉬 수면은 차선책처럼 보입니다.

편집 : 이와 같은 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 할 수 있습니다. 여러 Docker 컨테이너로 작업 할 때 유용합니다. 수면과 결합하여 간단한 대기 루프를 만듭니다.

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


답변

이 작은 bash 루프는 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

Dockerfile 에도 동등한 것이 있습니다 .

이 명령을 사용하면 docker psdocker inspect컨테이너의 상태가 표시됩니다. 특히 mysql의 경우이 방법은 container 내부에서mysqladmin 사용할 수 있다는 장점이 있으므로 docker 호스트에 설치할 필요가 없습니다.

그런 다음 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이 자체적으로 충분히 할당 할 수없는 경우 가능합니다.


답변

포트의 문제는 포트가 열려 있을 수 있지만 데이터베이스가 아직 준비되지 않은 경우가 있습니다.

다른 솔루션을 사용하려면 호스트 컴퓨터에 mysql oa mysql 클라이언트 를 설치해야 하지만 실제로는 이미 Docker 컨테이너에 포함되어 있으므로 다음과 같은 것을 사용하는 것이 좋습니다.

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


답변

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

지금까지이 방법에 문제가 발생하지 않았습니다. VinGarcia가 mysqladmin ping답변 중 하나에 대한 의견에서 비슷한 것을 제안했습니다 .


답변

다음 상태 확인은 모든 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에는 대기 기능을 제공하는 명령이 있으며 연결 테스트를 처리 한 다음 내부적으로 재 시도하고 완료되면 성공을 반환합니다.

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