Docker compose getting mysql db fully started before flask app starts












0














I just started to dockerize my app. I've built my Dockerfile and docker-compose.yml and everything seems to work fine except one thing. There are times my flask app will start too quick and throw a connection refused error (because the MySQL db is not fully up). I am using healthcheck to check if the db is up but this seems to not be reliable (I'm even making sure I can see show databases, but mysql apparently initializes more things after the healthcheck passes? not sure what the healthcheck is for then). In my output, I see that the db does get created first but it is still initializing when the flask app starts up. Ideally, when I run docker-compose up I want to be able to see this line first,



db_1_eae741771281 | 2018-11-10T00:50:21.473098Z 0 [Note] mysqld: ready for connections.


and then start my flask app entry point. Currently, it doesn't do this.



Is there a more reliable way to ensure the MySQL is fully up before starting my start.sh?



Dockerfile:



FROM python:3.5-alpine

RUN apk update && apk upgrade

RUN apk add --no-cache curl python build-base openldap-dev python2-dev python3-dev pkgconfig python-dev libffi-dev musl-dev make gcc

RUN pip install --upgrade pip

RUN adduser -D user

WORKDIR /home/user

COPY requirements.txt requirements.txt
RUN python -m venv venv
RUN venv/bin/pip install -r requirements.txt

COPY app app
COPY start.sh ./
RUN chmod +x start.sh

RUN chown -R user:user ./
USER user

EXPOSE 5000
ENTRYPOINT ["./start.sh"]


docker-compose.yml:



version: "2.1"
services:
db:
image: mysql:5.7
ports:
- "32000:3306"
environment:
- MYSQL_DATABASE=mydb
- MYSQL_USER=user
- MYSQL_PASSWORD=user123
- MYSQL_ROOT_PASSWORD=user123
volumes:
- ./db:/docker-entrypoint-initdb.d/:ro
healthcheck:
test: "mysql --user=user --password=user123 --execute "SHOW DATABASES;""
timeout: 20s
retries: 20

app:
build: ./
ports:
- "5000:5000"
depends_on:
db:
condition: service_healthy


start.sh



#!/bin/sh

source venv/bin/activate
# Start Gunicorn processes
echo Starting Gunicorn.

exec gunicorn -b 0.0.0.0:5000 wsgi --chdir my_app --timeout 9999 --workers 3 --access-logfile - --error-logfile - --capture-output --log-level debug









share|improve this question
























  • Possible duplicate of Docker-compose check if mysql connection is ready
    – Yann39
    Nov 10 at 17:14










  • @Yann39 I already saw that post and tried all the solutions recommended in the post, however, none of those works. As you can see in my code I have the health_check in place, but still getting the issue.
    – honeybadger_execute
    Nov 11 at 3:23
















0














I just started to dockerize my app. I've built my Dockerfile and docker-compose.yml and everything seems to work fine except one thing. There are times my flask app will start too quick and throw a connection refused error (because the MySQL db is not fully up). I am using healthcheck to check if the db is up but this seems to not be reliable (I'm even making sure I can see show databases, but mysql apparently initializes more things after the healthcheck passes? not sure what the healthcheck is for then). In my output, I see that the db does get created first but it is still initializing when the flask app starts up. Ideally, when I run docker-compose up I want to be able to see this line first,



db_1_eae741771281 | 2018-11-10T00:50:21.473098Z 0 [Note] mysqld: ready for connections.


and then start my flask app entry point. Currently, it doesn't do this.



Is there a more reliable way to ensure the MySQL is fully up before starting my start.sh?



Dockerfile:



FROM python:3.5-alpine

RUN apk update && apk upgrade

RUN apk add --no-cache curl python build-base openldap-dev python2-dev python3-dev pkgconfig python-dev libffi-dev musl-dev make gcc

RUN pip install --upgrade pip

RUN adduser -D user

WORKDIR /home/user

COPY requirements.txt requirements.txt
RUN python -m venv venv
RUN venv/bin/pip install -r requirements.txt

COPY app app
COPY start.sh ./
RUN chmod +x start.sh

RUN chown -R user:user ./
USER user

EXPOSE 5000
ENTRYPOINT ["./start.sh"]


docker-compose.yml:



version: "2.1"
services:
db:
image: mysql:5.7
ports:
- "32000:3306"
environment:
- MYSQL_DATABASE=mydb
- MYSQL_USER=user
- MYSQL_PASSWORD=user123
- MYSQL_ROOT_PASSWORD=user123
volumes:
- ./db:/docker-entrypoint-initdb.d/:ro
healthcheck:
test: "mysql --user=user --password=user123 --execute "SHOW DATABASES;""
timeout: 20s
retries: 20

app:
build: ./
ports:
- "5000:5000"
depends_on:
db:
condition: service_healthy


start.sh



#!/bin/sh

source venv/bin/activate
# Start Gunicorn processes
echo Starting Gunicorn.

exec gunicorn -b 0.0.0.0:5000 wsgi --chdir my_app --timeout 9999 --workers 3 --access-logfile - --error-logfile - --capture-output --log-level debug









share|improve this question
























  • Possible duplicate of Docker-compose check if mysql connection is ready
    – Yann39
    Nov 10 at 17:14










  • @Yann39 I already saw that post and tried all the solutions recommended in the post, however, none of those works. As you can see in my code I have the health_check in place, but still getting the issue.
    – honeybadger_execute
    Nov 11 at 3:23














0












0








0







I just started to dockerize my app. I've built my Dockerfile and docker-compose.yml and everything seems to work fine except one thing. There are times my flask app will start too quick and throw a connection refused error (because the MySQL db is not fully up). I am using healthcheck to check if the db is up but this seems to not be reliable (I'm even making sure I can see show databases, but mysql apparently initializes more things after the healthcheck passes? not sure what the healthcheck is for then). In my output, I see that the db does get created first but it is still initializing when the flask app starts up. Ideally, when I run docker-compose up I want to be able to see this line first,



db_1_eae741771281 | 2018-11-10T00:50:21.473098Z 0 [Note] mysqld: ready for connections.


and then start my flask app entry point. Currently, it doesn't do this.



Is there a more reliable way to ensure the MySQL is fully up before starting my start.sh?



Dockerfile:



FROM python:3.5-alpine

RUN apk update && apk upgrade

RUN apk add --no-cache curl python build-base openldap-dev python2-dev python3-dev pkgconfig python-dev libffi-dev musl-dev make gcc

RUN pip install --upgrade pip

RUN adduser -D user

WORKDIR /home/user

COPY requirements.txt requirements.txt
RUN python -m venv venv
RUN venv/bin/pip install -r requirements.txt

COPY app app
COPY start.sh ./
RUN chmod +x start.sh

RUN chown -R user:user ./
USER user

EXPOSE 5000
ENTRYPOINT ["./start.sh"]


docker-compose.yml:



version: "2.1"
services:
db:
image: mysql:5.7
ports:
- "32000:3306"
environment:
- MYSQL_DATABASE=mydb
- MYSQL_USER=user
- MYSQL_PASSWORD=user123
- MYSQL_ROOT_PASSWORD=user123
volumes:
- ./db:/docker-entrypoint-initdb.d/:ro
healthcheck:
test: "mysql --user=user --password=user123 --execute "SHOW DATABASES;""
timeout: 20s
retries: 20

app:
build: ./
ports:
- "5000:5000"
depends_on:
db:
condition: service_healthy


start.sh



#!/bin/sh

source venv/bin/activate
# Start Gunicorn processes
echo Starting Gunicorn.

exec gunicorn -b 0.0.0.0:5000 wsgi --chdir my_app --timeout 9999 --workers 3 --access-logfile - --error-logfile - --capture-output --log-level debug









share|improve this question















I just started to dockerize my app. I've built my Dockerfile and docker-compose.yml and everything seems to work fine except one thing. There are times my flask app will start too quick and throw a connection refused error (because the MySQL db is not fully up). I am using healthcheck to check if the db is up but this seems to not be reliable (I'm even making sure I can see show databases, but mysql apparently initializes more things after the healthcheck passes? not sure what the healthcheck is for then). In my output, I see that the db does get created first but it is still initializing when the flask app starts up. Ideally, when I run docker-compose up I want to be able to see this line first,



db_1_eae741771281 | 2018-11-10T00:50:21.473098Z 0 [Note] mysqld: ready for connections.


and then start my flask app entry point. Currently, it doesn't do this.



Is there a more reliable way to ensure the MySQL is fully up before starting my start.sh?



Dockerfile:



FROM python:3.5-alpine

RUN apk update && apk upgrade

RUN apk add --no-cache curl python build-base openldap-dev python2-dev python3-dev pkgconfig python-dev libffi-dev musl-dev make gcc

RUN pip install --upgrade pip

RUN adduser -D user

WORKDIR /home/user

COPY requirements.txt requirements.txt
RUN python -m venv venv
RUN venv/bin/pip install -r requirements.txt

COPY app app
COPY start.sh ./
RUN chmod +x start.sh

RUN chown -R user:user ./
USER user

EXPOSE 5000
ENTRYPOINT ["./start.sh"]


docker-compose.yml:



version: "2.1"
services:
db:
image: mysql:5.7
ports:
- "32000:3306"
environment:
- MYSQL_DATABASE=mydb
- MYSQL_USER=user
- MYSQL_PASSWORD=user123
- MYSQL_ROOT_PASSWORD=user123
volumes:
- ./db:/docker-entrypoint-initdb.d/:ro
healthcheck:
test: "mysql --user=user --password=user123 --execute "SHOW DATABASES;""
timeout: 20s
retries: 20

app:
build: ./
ports:
- "5000:5000"
depends_on:
db:
condition: service_healthy


start.sh



#!/bin/sh

source venv/bin/activate
# Start Gunicorn processes
echo Starting Gunicorn.

exec gunicorn -b 0.0.0.0:5000 wsgi --chdir my_app --timeout 9999 --workers 3 --access-logfile - --error-logfile - --capture-output --log-level debug






docker docker-compose






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 10 at 11:27

























asked Nov 10 at 1:41









honeybadger_execute

1078




1078












  • Possible duplicate of Docker-compose check if mysql connection is ready
    – Yann39
    Nov 10 at 17:14










  • @Yann39 I already saw that post and tried all the solutions recommended in the post, however, none of those works. As you can see in my code I have the health_check in place, but still getting the issue.
    – honeybadger_execute
    Nov 11 at 3:23


















  • Possible duplicate of Docker-compose check if mysql connection is ready
    – Yann39
    Nov 10 at 17:14










  • @Yann39 I already saw that post and tried all the solutions recommended in the post, however, none of those works. As you can see in my code I have the health_check in place, but still getting the issue.
    – honeybadger_execute
    Nov 11 at 3:23
















Possible duplicate of Docker-compose check if mysql connection is ready
– Yann39
Nov 10 at 17:14




Possible duplicate of Docker-compose check if mysql connection is ready
– Yann39
Nov 10 at 17:14












@Yann39 I already saw that post and tried all the solutions recommended in the post, however, none of those works. As you can see in my code I have the health_check in place, but still getting the issue.
– honeybadger_execute
Nov 11 at 3:23




@Yann39 I already saw that post and tried all the solutions recommended in the post, however, none of those works. As you can see in my code I have the health_check in place, but still getting the issue.
– honeybadger_execute
Nov 11 at 3:23












3 Answers
3






active

oldest

votes


















1














OK I also had problems with health_check...



Maybe not the most optimal, but the most reliable solution is to use a MySQL client (mysqladmin) to ping your MySQL server before starting your application.



1 - Create a wait.sh script (db is your MySQL service name here) :



#!/bin/sh

# Wait until MySQL is ready
while ! mysqladmin ping -h"db" -P"3306" --silent; do
echo "Waiting for MySQL to be up..."
sleep 1
done


2 - Get a MySQL client from your app Dockerfile :



# install mysql client, will be used to ping mysql
apt-get -y install mysql-client


3 - In your docker-compose.yml file, just add scripts to your container (I used volumes but you can keep using COPY) and run wait.sh before start.sh :



app:
build: ./
ports:
- "5000:5000"
depends_on:
db:
command: bash -c "/usr/local/bin/wait.sh && /usr/local/bin/start.sh"
volumes:
- ./start.sh:/usr/local/bin/start.sh
- ./wait.sh:/usr/local/bin/wait.sh


This should work.



If you really don't want having to download a MySQL client, try this (again db is your MySQL service name here). It has worked in most of my project but not in all (may depend of the distribution?) :



#!/bin/sh

# Wait until MySQL is ready
while ! exec 6<>/dev/tcp/db/3306; do
echo "Trying to connect to MySQL at 3306..."
sleep 5
done


PS : avoid naming your services "app" or "db", you may have problems later if you have other containers with those same service names (even in different networks).






share|improve this answer





















  • Is that different than this solution here?stackoverflow.com/a/42757250/10067412
    – honeybadger_execute
    Nov 11 at 11:17










  • Yes it does not use healthcheck but command instead which override the default command. Although both solutions use mysqladmin to ping server every interval seconds.
    – Yann39
    Nov 11 at 19:07










  • Okay, and why do we need to install mysql-client? Will mysqladmin ping not work without it?
    – honeybadger_execute
    Nov 12 at 9:30






  • 1




    Yes just chain your commands in the docker-compose command instruction : command: bash -c "chmod +x /usr/local/bin/wait.sh /usr/local/bin/start.sh && /usr/local/bin/wait.sh && /usr/local/bin/start.sh". You can also mix wait.sh and start.sh in a single script if you prefer.
    – Yann39
    Nov 12 at 20:56






  • 1




    Indeed python3.5-alpine is based on alpine:3.8 Linux image which use sh (bash is not included). So you can just use sh if you don't want to install bash, then the docker-compose command would be : command: sh -c "...". Also use the #!/bin/sh shebang instead of #!/bin/bash in your scripts. For the differences see this answer.
    – Yann39
    Nov 13 at 7:34



















1














While using a health check is easier, it totally depends on how reliable the check is.



Another approach would be to rely on projects like wait-for-it or wait-for, in your app container.

Since you are getting a connection refused, these scripts could return only once the connection is possible and your app can start only after.



Also, in case that doesn't work too, you could have a separate script (python in your case) to check until the DB is ready and you can call this script in your start.sh before starting the flask app.






share|improve this answer





















  • yeah, the wait-for-it script didn't work either. I ended up having to put a sleep 30 in my start.sh before starting the app and that seems to solve the problem.
    – honeybadger_execute
    Nov 11 at 3:21












  • The best practice would be to have a simple script (python would be ideal for you since the container already has everything you need) which tries to connect and validate the DB on a loop until successful. Sort of like the health check but in your app container instead.
    – Pramodh Valavala
    Nov 11 at 5:28



















0














This is a common problem with multi containers. It is difficult to control the speed at which different containers start. Container orchestration solution like Kubernetes might be able to help you in such cases.
Kubernetes has the concept of init containers which run to completion before your dependent container can start. You can find sample of init container here



https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html



This youtube vide might be helpful for you as well
https://www.youtube.com/watch?v=n2FPsunhuFc






share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53235312%2fdocker-compose-getting-mysql-db-fully-started-before-flask-app-starts%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    OK I also had problems with health_check...



    Maybe not the most optimal, but the most reliable solution is to use a MySQL client (mysqladmin) to ping your MySQL server before starting your application.



    1 - Create a wait.sh script (db is your MySQL service name here) :



    #!/bin/sh

    # Wait until MySQL is ready
    while ! mysqladmin ping -h"db" -P"3306" --silent; do
    echo "Waiting for MySQL to be up..."
    sleep 1
    done


    2 - Get a MySQL client from your app Dockerfile :



    # install mysql client, will be used to ping mysql
    apt-get -y install mysql-client


    3 - In your docker-compose.yml file, just add scripts to your container (I used volumes but you can keep using COPY) and run wait.sh before start.sh :



    app:
    build: ./
    ports:
    - "5000:5000"
    depends_on:
    db:
    command: bash -c "/usr/local/bin/wait.sh && /usr/local/bin/start.sh"
    volumes:
    - ./start.sh:/usr/local/bin/start.sh
    - ./wait.sh:/usr/local/bin/wait.sh


    This should work.



    If you really don't want having to download a MySQL client, try this (again db is your MySQL service name here). It has worked in most of my project but not in all (may depend of the distribution?) :



    #!/bin/sh

    # Wait until MySQL is ready
    while ! exec 6<>/dev/tcp/db/3306; do
    echo "Trying to connect to MySQL at 3306..."
    sleep 5
    done


    PS : avoid naming your services "app" or "db", you may have problems later if you have other containers with those same service names (even in different networks).






    share|improve this answer





















    • Is that different than this solution here?stackoverflow.com/a/42757250/10067412
      – honeybadger_execute
      Nov 11 at 11:17










    • Yes it does not use healthcheck but command instead which override the default command. Although both solutions use mysqladmin to ping server every interval seconds.
      – Yann39
      Nov 11 at 19:07










    • Okay, and why do we need to install mysql-client? Will mysqladmin ping not work without it?
      – honeybadger_execute
      Nov 12 at 9:30






    • 1




      Yes just chain your commands in the docker-compose command instruction : command: bash -c "chmod +x /usr/local/bin/wait.sh /usr/local/bin/start.sh && /usr/local/bin/wait.sh && /usr/local/bin/start.sh". You can also mix wait.sh and start.sh in a single script if you prefer.
      – Yann39
      Nov 12 at 20:56






    • 1




      Indeed python3.5-alpine is based on alpine:3.8 Linux image which use sh (bash is not included). So you can just use sh if you don't want to install bash, then the docker-compose command would be : command: sh -c "...". Also use the #!/bin/sh shebang instead of #!/bin/bash in your scripts. For the differences see this answer.
      – Yann39
      Nov 13 at 7:34
















    1














    OK I also had problems with health_check...



    Maybe not the most optimal, but the most reliable solution is to use a MySQL client (mysqladmin) to ping your MySQL server before starting your application.



    1 - Create a wait.sh script (db is your MySQL service name here) :



    #!/bin/sh

    # Wait until MySQL is ready
    while ! mysqladmin ping -h"db" -P"3306" --silent; do
    echo "Waiting for MySQL to be up..."
    sleep 1
    done


    2 - Get a MySQL client from your app Dockerfile :



    # install mysql client, will be used to ping mysql
    apt-get -y install mysql-client


    3 - In your docker-compose.yml file, just add scripts to your container (I used volumes but you can keep using COPY) and run wait.sh before start.sh :



    app:
    build: ./
    ports:
    - "5000:5000"
    depends_on:
    db:
    command: bash -c "/usr/local/bin/wait.sh && /usr/local/bin/start.sh"
    volumes:
    - ./start.sh:/usr/local/bin/start.sh
    - ./wait.sh:/usr/local/bin/wait.sh


    This should work.



    If you really don't want having to download a MySQL client, try this (again db is your MySQL service name here). It has worked in most of my project but not in all (may depend of the distribution?) :



    #!/bin/sh

    # Wait until MySQL is ready
    while ! exec 6<>/dev/tcp/db/3306; do
    echo "Trying to connect to MySQL at 3306..."
    sleep 5
    done


    PS : avoid naming your services "app" or "db", you may have problems later if you have other containers with those same service names (even in different networks).






    share|improve this answer





















    • Is that different than this solution here?stackoverflow.com/a/42757250/10067412
      – honeybadger_execute
      Nov 11 at 11:17










    • Yes it does not use healthcheck but command instead which override the default command. Although both solutions use mysqladmin to ping server every interval seconds.
      – Yann39
      Nov 11 at 19:07










    • Okay, and why do we need to install mysql-client? Will mysqladmin ping not work without it?
      – honeybadger_execute
      Nov 12 at 9:30






    • 1




      Yes just chain your commands in the docker-compose command instruction : command: bash -c "chmod +x /usr/local/bin/wait.sh /usr/local/bin/start.sh && /usr/local/bin/wait.sh && /usr/local/bin/start.sh". You can also mix wait.sh and start.sh in a single script if you prefer.
      – Yann39
      Nov 12 at 20:56






    • 1




      Indeed python3.5-alpine is based on alpine:3.8 Linux image which use sh (bash is not included). So you can just use sh if you don't want to install bash, then the docker-compose command would be : command: sh -c "...". Also use the #!/bin/sh shebang instead of #!/bin/bash in your scripts. For the differences see this answer.
      – Yann39
      Nov 13 at 7:34














    1












    1








    1






    OK I also had problems with health_check...



    Maybe not the most optimal, but the most reliable solution is to use a MySQL client (mysqladmin) to ping your MySQL server before starting your application.



    1 - Create a wait.sh script (db is your MySQL service name here) :



    #!/bin/sh

    # Wait until MySQL is ready
    while ! mysqladmin ping -h"db" -P"3306" --silent; do
    echo "Waiting for MySQL to be up..."
    sleep 1
    done


    2 - Get a MySQL client from your app Dockerfile :



    # install mysql client, will be used to ping mysql
    apt-get -y install mysql-client


    3 - In your docker-compose.yml file, just add scripts to your container (I used volumes but you can keep using COPY) and run wait.sh before start.sh :



    app:
    build: ./
    ports:
    - "5000:5000"
    depends_on:
    db:
    command: bash -c "/usr/local/bin/wait.sh && /usr/local/bin/start.sh"
    volumes:
    - ./start.sh:/usr/local/bin/start.sh
    - ./wait.sh:/usr/local/bin/wait.sh


    This should work.



    If you really don't want having to download a MySQL client, try this (again db is your MySQL service name here). It has worked in most of my project but not in all (may depend of the distribution?) :



    #!/bin/sh

    # Wait until MySQL is ready
    while ! exec 6<>/dev/tcp/db/3306; do
    echo "Trying to connect to MySQL at 3306..."
    sleep 5
    done


    PS : avoid naming your services "app" or "db", you may have problems later if you have other containers with those same service names (even in different networks).






    share|improve this answer












    OK I also had problems with health_check...



    Maybe not the most optimal, but the most reliable solution is to use a MySQL client (mysqladmin) to ping your MySQL server before starting your application.



    1 - Create a wait.sh script (db is your MySQL service name here) :



    #!/bin/sh

    # Wait until MySQL is ready
    while ! mysqladmin ping -h"db" -P"3306" --silent; do
    echo "Waiting for MySQL to be up..."
    sleep 1
    done


    2 - Get a MySQL client from your app Dockerfile :



    # install mysql client, will be used to ping mysql
    apt-get -y install mysql-client


    3 - In your docker-compose.yml file, just add scripts to your container (I used volumes but you can keep using COPY) and run wait.sh before start.sh :



    app:
    build: ./
    ports:
    - "5000:5000"
    depends_on:
    db:
    command: bash -c "/usr/local/bin/wait.sh && /usr/local/bin/start.sh"
    volumes:
    - ./start.sh:/usr/local/bin/start.sh
    - ./wait.sh:/usr/local/bin/wait.sh


    This should work.



    If you really don't want having to download a MySQL client, try this (again db is your MySQL service name here). It has worked in most of my project but not in all (may depend of the distribution?) :



    #!/bin/sh

    # Wait until MySQL is ready
    while ! exec 6<>/dev/tcp/db/3306; do
    echo "Trying to connect to MySQL at 3306..."
    sleep 5
    done


    PS : avoid naming your services "app" or "db", you may have problems later if you have other containers with those same service names (even in different networks).







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 11 at 10:33









    Yann39

    2,08632232




    2,08632232












    • Is that different than this solution here?stackoverflow.com/a/42757250/10067412
      – honeybadger_execute
      Nov 11 at 11:17










    • Yes it does not use healthcheck but command instead which override the default command. Although both solutions use mysqladmin to ping server every interval seconds.
      – Yann39
      Nov 11 at 19:07










    • Okay, and why do we need to install mysql-client? Will mysqladmin ping not work without it?
      – honeybadger_execute
      Nov 12 at 9:30






    • 1




      Yes just chain your commands in the docker-compose command instruction : command: bash -c "chmod +x /usr/local/bin/wait.sh /usr/local/bin/start.sh && /usr/local/bin/wait.sh && /usr/local/bin/start.sh". You can also mix wait.sh and start.sh in a single script if you prefer.
      – Yann39
      Nov 12 at 20:56






    • 1




      Indeed python3.5-alpine is based on alpine:3.8 Linux image which use sh (bash is not included). So you can just use sh if you don't want to install bash, then the docker-compose command would be : command: sh -c "...". Also use the #!/bin/sh shebang instead of #!/bin/bash in your scripts. For the differences see this answer.
      – Yann39
      Nov 13 at 7:34


















    • Is that different than this solution here?stackoverflow.com/a/42757250/10067412
      – honeybadger_execute
      Nov 11 at 11:17










    • Yes it does not use healthcheck but command instead which override the default command. Although both solutions use mysqladmin to ping server every interval seconds.
      – Yann39
      Nov 11 at 19:07










    • Okay, and why do we need to install mysql-client? Will mysqladmin ping not work without it?
      – honeybadger_execute
      Nov 12 at 9:30






    • 1




      Yes just chain your commands in the docker-compose command instruction : command: bash -c "chmod +x /usr/local/bin/wait.sh /usr/local/bin/start.sh && /usr/local/bin/wait.sh && /usr/local/bin/start.sh". You can also mix wait.sh and start.sh in a single script if you prefer.
      – Yann39
      Nov 12 at 20:56






    • 1




      Indeed python3.5-alpine is based on alpine:3.8 Linux image which use sh (bash is not included). So you can just use sh if you don't want to install bash, then the docker-compose command would be : command: sh -c "...". Also use the #!/bin/sh shebang instead of #!/bin/bash in your scripts. For the differences see this answer.
      – Yann39
      Nov 13 at 7:34
















    Is that different than this solution here?stackoverflow.com/a/42757250/10067412
    – honeybadger_execute
    Nov 11 at 11:17




    Is that different than this solution here?stackoverflow.com/a/42757250/10067412
    – honeybadger_execute
    Nov 11 at 11:17












    Yes it does not use healthcheck but command instead which override the default command. Although both solutions use mysqladmin to ping server every interval seconds.
    – Yann39
    Nov 11 at 19:07




    Yes it does not use healthcheck but command instead which override the default command. Although both solutions use mysqladmin to ping server every interval seconds.
    – Yann39
    Nov 11 at 19:07












    Okay, and why do we need to install mysql-client? Will mysqladmin ping not work without it?
    – honeybadger_execute
    Nov 12 at 9:30




    Okay, and why do we need to install mysql-client? Will mysqladmin ping not work without it?
    – honeybadger_execute
    Nov 12 at 9:30




    1




    1




    Yes just chain your commands in the docker-compose command instruction : command: bash -c "chmod +x /usr/local/bin/wait.sh /usr/local/bin/start.sh && /usr/local/bin/wait.sh && /usr/local/bin/start.sh". You can also mix wait.sh and start.sh in a single script if you prefer.
    – Yann39
    Nov 12 at 20:56




    Yes just chain your commands in the docker-compose command instruction : command: bash -c "chmod +x /usr/local/bin/wait.sh /usr/local/bin/start.sh && /usr/local/bin/wait.sh && /usr/local/bin/start.sh". You can also mix wait.sh and start.sh in a single script if you prefer.
    – Yann39
    Nov 12 at 20:56




    1




    1




    Indeed python3.5-alpine is based on alpine:3.8 Linux image which use sh (bash is not included). So you can just use sh if you don't want to install bash, then the docker-compose command would be : command: sh -c "...". Also use the #!/bin/sh shebang instead of #!/bin/bash in your scripts. For the differences see this answer.
    – Yann39
    Nov 13 at 7:34




    Indeed python3.5-alpine is based on alpine:3.8 Linux image which use sh (bash is not included). So you can just use sh if you don't want to install bash, then the docker-compose command would be : command: sh -c "...". Also use the #!/bin/sh shebang instead of #!/bin/bash in your scripts. For the differences see this answer.
    – Yann39
    Nov 13 at 7:34













    1














    While using a health check is easier, it totally depends on how reliable the check is.



    Another approach would be to rely on projects like wait-for-it or wait-for, in your app container.

    Since you are getting a connection refused, these scripts could return only once the connection is possible and your app can start only after.



    Also, in case that doesn't work too, you could have a separate script (python in your case) to check until the DB is ready and you can call this script in your start.sh before starting the flask app.






    share|improve this answer





















    • yeah, the wait-for-it script didn't work either. I ended up having to put a sleep 30 in my start.sh before starting the app and that seems to solve the problem.
      – honeybadger_execute
      Nov 11 at 3:21












    • The best practice would be to have a simple script (python would be ideal for you since the container already has everything you need) which tries to connect and validate the DB on a loop until successful. Sort of like the health check but in your app container instead.
      – Pramodh Valavala
      Nov 11 at 5:28
















    1














    While using a health check is easier, it totally depends on how reliable the check is.



    Another approach would be to rely on projects like wait-for-it or wait-for, in your app container.

    Since you are getting a connection refused, these scripts could return only once the connection is possible and your app can start only after.



    Also, in case that doesn't work too, you could have a separate script (python in your case) to check until the DB is ready and you can call this script in your start.sh before starting the flask app.






    share|improve this answer





















    • yeah, the wait-for-it script didn't work either. I ended up having to put a sleep 30 in my start.sh before starting the app and that seems to solve the problem.
      – honeybadger_execute
      Nov 11 at 3:21












    • The best practice would be to have a simple script (python would be ideal for you since the container already has everything you need) which tries to connect and validate the DB on a loop until successful. Sort of like the health check but in your app container instead.
      – Pramodh Valavala
      Nov 11 at 5:28














    1












    1








    1






    While using a health check is easier, it totally depends on how reliable the check is.



    Another approach would be to rely on projects like wait-for-it or wait-for, in your app container.

    Since you are getting a connection refused, these scripts could return only once the connection is possible and your app can start only after.



    Also, in case that doesn't work too, you could have a separate script (python in your case) to check until the DB is ready and you can call this script in your start.sh before starting the flask app.






    share|improve this answer












    While using a health check is easier, it totally depends on how reliable the check is.



    Another approach would be to rely on projects like wait-for-it or wait-for, in your app container.

    Since you are getting a connection refused, these scripts could return only once the connection is possible and your app can start only after.



    Also, in case that doesn't work too, you could have a separate script (python in your case) to check until the DB is ready and you can call this script in your start.sh before starting the flask app.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 10 at 16:49









    Pramodh Valavala

    47127




    47127












    • yeah, the wait-for-it script didn't work either. I ended up having to put a sleep 30 in my start.sh before starting the app and that seems to solve the problem.
      – honeybadger_execute
      Nov 11 at 3:21












    • The best practice would be to have a simple script (python would be ideal for you since the container already has everything you need) which tries to connect and validate the DB on a loop until successful. Sort of like the health check but in your app container instead.
      – Pramodh Valavala
      Nov 11 at 5:28


















    • yeah, the wait-for-it script didn't work either. I ended up having to put a sleep 30 in my start.sh before starting the app and that seems to solve the problem.
      – honeybadger_execute
      Nov 11 at 3:21












    • The best practice would be to have a simple script (python would be ideal for you since the container already has everything you need) which tries to connect and validate the DB on a loop until successful. Sort of like the health check but in your app container instead.
      – Pramodh Valavala
      Nov 11 at 5:28
















    yeah, the wait-for-it script didn't work either. I ended up having to put a sleep 30 in my start.sh before starting the app and that seems to solve the problem.
    – honeybadger_execute
    Nov 11 at 3:21






    yeah, the wait-for-it script didn't work either. I ended up having to put a sleep 30 in my start.sh before starting the app and that seems to solve the problem.
    – honeybadger_execute
    Nov 11 at 3:21














    The best practice would be to have a simple script (python would be ideal for you since the container already has everything you need) which tries to connect and validate the DB on a loop until successful. Sort of like the health check but in your app container instead.
    – Pramodh Valavala
    Nov 11 at 5:28




    The best practice would be to have a simple script (python would be ideal for you since the container already has everything you need) which tries to connect and validate the DB on a loop until successful. Sort of like the health check but in your app container instead.
    – Pramodh Valavala
    Nov 11 at 5:28











    0














    This is a common problem with multi containers. It is difficult to control the speed at which different containers start. Container orchestration solution like Kubernetes might be able to help you in such cases.
    Kubernetes has the concept of init containers which run to completion before your dependent container can start. You can find sample of init container here



    https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html



    This youtube vide might be helpful for you as well
    https://www.youtube.com/watch?v=n2FPsunhuFc






    share|improve this answer


























      0














      This is a common problem with multi containers. It is difficult to control the speed at which different containers start. Container orchestration solution like Kubernetes might be able to help you in such cases.
      Kubernetes has the concept of init containers which run to completion before your dependent container can start. You can find sample of init container here



      https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html



      This youtube vide might be helpful for you as well
      https://www.youtube.com/watch?v=n2FPsunhuFc






      share|improve this answer
























        0












        0








        0






        This is a common problem with multi containers. It is difficult to control the speed at which different containers start. Container orchestration solution like Kubernetes might be able to help you in such cases.
        Kubernetes has the concept of init containers which run to completion before your dependent container can start. You can find sample of init container here



        https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html



        This youtube vide might be helpful for you as well
        https://www.youtube.com/watch?v=n2FPsunhuFc






        share|improve this answer












        This is a common problem with multi containers. It is difficult to control the speed at which different containers start. Container orchestration solution like Kubernetes might be able to help you in such cases.
        Kubernetes has the concept of init containers which run to completion before your dependent container can start. You can find sample of init container here



        https://www.handsonarchitect.com/2018/08/understand-kubernetes-object-init.html



        This youtube vide might be helpful for you as well
        https://www.youtube.com/watch?v=n2FPsunhuFc







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 10 at 3:30









        Nilesh Gule

        1,224911




        1,224911






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53235312%2fdocker-compose-getting-mysql-db-fully-started-before-flask-app-starts%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Xamarin.form Move up view when keyboard appear

            Post-Redirect-Get with Spring WebFlux and Thymeleaf

            Anylogic : not able to use stopDelay()