How do I know when my docker mysql container is up and mysql is ready for taking queries?

后端 未结 14 911
猫巷女王i
猫巷女王i 2020-11-30 22:33

I am deploying a few different docker containers, mysql being the first one. I want to run scripts as soon as database is up and proceed to building other containers. The sc

相关标签:
14条回答
  • 2020-11-30 23:14

    I developed a new solution for this issue based on a new approach. All approaches I found rely on a script that tries over and over to connect to the database, or try to establish a TCP connection with the container. The full details can be found on the waitdb repository, but, my solution is to rely on the retrieved log from the container. The script waits until the log fires the message ready for connections. The script can identify if the container is starting for the first time. In this case the script waits until the initial database script is executed and the database is restarted, waiting again for a new ready for connections message. I tested this solution on MySQL 5.7 and MySQL 8.0.

    The script itself (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!"
    

    The script can be used in Docker Compose or in Docker itself. I hope the examples bellow make the the usage clear:

    Example 01: Using with Docker Compose

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

    Example 02: Using with Docker

    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
    

    Example 3: A full example (the test-case)

    A full example can be found on the test case of the repository. This test-case will startup a new MySQL, create a dummy database, wait until everything is started and then fires a select to check if everything goes fine. After that it'll going restart the container and wait it to be started and then fires a new select to check if it's ready for connection.

    0 讨论(0)
  • 2020-11-30 23:16

    I use the following code ;

    export COMPOSE_PROJECT_NAME=web;

    export IS_DATA_CONTAINER_EXISTS=$(docker volume ls | grep ${COMPOSE_PROJECT_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);
    
    0 讨论(0)
  • 2020-11-30 23:19

    This was more or less mentioned in comments to other answers, but I think it deserves its own entry.

    First of all you can run your container in the following manner:

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

    There is also an equivalent in the Dockerfile.

    With that command your docker ps and docker inspect will show you health status of your container. For mysql in particular this method has the advantage of mysqladmin being available inside the container, so you do not need to install it on the docker host.

    Then you can simply loop in a bash script to wait on the status to become healthy. The following bash script is created by 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"
    }
    

    Now you can do this in your script:

    waitContainer mysql
    

    and your script will wait until the container is up and running. The script will exit if the container becomes unhealthy, which is possible, if for example docker host is out of memory, so that the mysql cannot allocate enough of it for itself.

    0 讨论(0)
  • 2020-11-30 23:22

    The following health-check works for all my mysql containers:

    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
    
    0 讨论(0)
  • 2020-11-30 23:22

    https://github.com/docker-library/mysql/blob/master/5.7/docker-entrypoint.sh docker-entrypoint.sh doesn't support merging customized .sql yet.

    I think you can modify docker-entrypoint.sh to merge your sql so it can be executed once mysql instance is ready.

    0 讨论(0)
  • 2020-11-30 23:25

    Some times the problem with the port is that the port could be open, but the database is not ready yet.

    Other solutions require that you have installed the mysql o a mysql client in your host machine, but really you already have it inside the Docker container, so I prefer to use something like this:

    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
    
    0 讨论(0)
提交回复
热议问题