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

后端 未结 14 909
猫巷女王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:07

    I had the same issue when my Django container tried to connect the mysql container just after it started. I solved it using the vishnubob's wait-for.it.sh script. Its a shell script which waits for an IP and a host to be ready before continuing. Here is the example I use for my applicaction.

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

    In that script I'm asking to the mysql container to wait maximum 90 seconds (it will run normally when ready) in the port 3306 (default mysql port) and the host asigned by docker for my MYSQL_CONTAINER_NAME. The script have more variables but for mw worked with these three.

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

    On your ENTRYPOINT script, you have to check if you have a valid MySQL connection or not.

    This solution does not require you to install a MySQL Client on the container and while running the container with php:7.0-fpm running nc was not an option, because it had to be installed as well. Also, checking if the port is open does not necessarily mean that the service is running and exposed correctly. [more of this]

    So in this solution, I will show you how to run a PHP script to check if a MySQL Container is able to take connection. If you want to know why I think this is a better approach check my comment here.

    File 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
    

    By running this, you are essentially blocking any bootstrapping logic of your container UNTIL you have a valid MySQL Connection.

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

    This little bash loop waits for mysql to be open, shouldn't require any extra packages to be installed:

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

    Here's how I incorporated Adams solution into my docker-compose based project:

    Created a bash file titled db-ready.sh in my server container folder (the contents of which are copied in to my container - 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
    

    I can then run docker-compose run server sh ./db-ready.sh && docker-compose run server yarn run migrate to ensure that when I run my migrate task within my server container, I know the DB will be accepting connections.

    I like this approach as the bash file is separate to any command I want to run. I could easily run the db-ready.sh before any other DB using task I run.

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

    So I am not sure if any one has posted this. It doesn't look like any one has, so... there is a command in mysqladmin that features a wait, it handles testing of the connection, then retries internally and returns a success upon completion.

    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
    

    The important piece is mysqladmin ping -h 127.0.0.1 -u root --password=MY_ROOT_PASS --wait=30 -v with the --wait being the flag to wait until the connection is successful and the number being the amount of attempts to retry.

    Ideally you would run that command from inside the docker container, but I didn't want to modify the original posters command too much.

    When used in my make file for initialization

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

    If the docker container waiting for a mysql container is based on a python image (for instance for a Django application), you can use the code below.

    Advantages are:

    • It's not based on wait-for-it.sh, which does wait for the IP and port of mysql to be ready, but this doesn't automatically mean also that the mysql initialization has finished.
    • It's not a shell script based on a mysql or mysqladmin executable that must be present in your container: since your container is based on a python image, this would require installing mysql on top of that image. With the below solution, you use the technology that is already present in the container: pure python.

    Code:

    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()
    

    Usage:

    1. Add this code into a python file (wait-for-mysql-db.py for instance) inside your application's source code.
    2. Write another python script (startup.py for instance) that first executes the above code, and afterwards starts up your application.
    3. Make sure your application container's Dockerfile packs these two python scripts together with the application's source code into a Docker image.
    4. In your docker-compose file, configure your application container with: command: ["python3", "startup.py"].

    Note that this solution is made for a MySQL database. You'll need to adapt it slightly for another database.

    0 讨论(0)
提交回复
热议问题