Docker-compose check if mysql connection is ready
I am trying to make sure that my app container does not run migrations / start until the db container is started and READY TO accept connections.
So I decided to use the healthcheck and depends on option in docker compose file v2.
In the app, I have the following
app:
...
depends_on:
db:
condition: service_healthy
The db on the other hand has the following healthcheck
db:
...
healthcheck:
test: TEST_GOES_HERE
timeout: 20s
retries: 10
I have tried a couple of approaches like :
- making sure the db DIR is created
test: ["CMD", "test -f var/lib/mysql/db"]
- Getting the mysql version:
test: ["CMD", "echo 'SELECT version();'| mysql"]
- Ping the admin (marks the db container as healthy but does not seem to be a valid test)
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
Does anyone have a solution to this?
Solution 1:
version: "2.1"
services:
api:
build: .
container_name: api
ports:
- "8080:8080"
depends_on:
db:
condition: service_healthy
db:
container_name: db
image: mysql
ports:
- "3306"
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
MYSQL_USER: "user"
MYSQL_PASSWORD: "password"
MYSQL_DATABASE: "database"
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 20s
retries: 10
The api container will not start until the db container is healthy (basically until mysqladmin is up and accepting connections.)
Solution 2:
If you are using docker-compose v3+, condition
as an option of depends_on
has been removed.
The recommended path is to use rather wait-for-it
, dockerize
, or wait-for
. In your docker-compose.yml
file, change your command to be:
command: sh -c 'bin/wait-for db:3306 -- bundle exec rails s'
I personally prefer wait-for
since it can run in an Alpine container (sh
compatible, no dependance on bash
). Drawback is that it depends on netcat
, so if you decide to use it, make sure you have netcat
installed in the container, or install it in your Dockerfile, for example with:
# for Alpine image:
RUN apk update && apk add netcat-openbsd
# otherwise:
RUN apt-get -q update && apt-get -qy install netcat
Compose published a good doc about Startup Order.
I also forked the wait-for
project so it can check for healthy HTTP status (it uses wget
). Then you can do something like that:
command: sh -c 'bin/wait-for http://api/ping -- jest test'
PS: A PR is also ready to be merged to add that capacity to wait-for
project.
Solution 3:
This should be enough
version: '2.1'
services:
mysql:
image: mysql
ports: ['3306:3306']
environment:
MYSQL_USER: myuser
MYSQL_PASSWORD: mypassword
healthcheck:
test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
Solution 4:
Hi for a simple healthcheck using docker-compose v2.1, I used:
/usr/bin/mysql --user=root --password=rootpasswd --execute \"SHOW DATABASES;\"
Basically it runs a simple mysql
command SHOW DATABASES;
using as an example the user root
with the password rootpasswd
in the database.
If the command succeed the db is up and ready so the healthcheck path. You can use interval
so it tests at interval.
Removing the other field for visibility, here is what it would look like in your docker-compose.yaml
.
version: '2.1'
services:
db:
... # Other db configuration (image, port, volumes, ...)
healthcheck:
test: "/usr/bin/mysql --user=root --password=rootpasswd --execute \"SHOW DATABASES;\""
interval: 2s
timeout: 20s
retries: 10
app:
... # Other app configuration
depends_on:
db:
condition: service_healthy