Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

docker with ansible wait for database

I try to deploy docker with ansible. I have one docker database container, and in other container is my web app, and I try to link this two container. The problem is that database container didn't have a time to configure itself and a web container is already started. My ansible playbook look something like:

...
- name: run mysql in docker container
  docker:
    image: "mysql:5.5"
    name: database
    env: "MYSQL_ROOT_PASSWORD=password"
    state: running

- name: run application containers
  docker:
    name: "application"
    image: "myapp"
    ports:
      - "8080:8080"
    links:
      - "database:db"
    state: running

How to determine if database is start? I try with wait_for module, but that didn't work. I don't want to set timeout, it's not good option for me.

like image 242
Vladimir Fejsov Avatar asked Apr 15 '15 14:04

Vladimir Fejsov


4 Answers

To avoid the sh and I don't normally have telnet installed...

- name: Wait for database to be available
  shell: docker run --rm --link mysql:mysql mysql sh -c 'mysql -h"$MYSQL_PORT_3306_TCP_ADDR" -P"$MYSQL_PORT_3306_TCP_PORT" -uroot -p{{mysql_password}} || true'
  register: result
  until: result.stderr.find("Can't connect to MySQL") == -1
  retries: 10
  delay: 3
like image 99
FreshPow Avatar answered Oct 15 '22 04:10

FreshPow


As etrubenok said:

wait_for does not work for the MySQL docker container because it only checks that the port is connectable (which is true straight away for the Docker container). However, wait_for does not check that the service inside the container listens the port and sends responses to the client.

Using Andy Shinn's suggestion of FreshPow's answer, you can wait without needing a shell script or telnet:

- name: Wait for mariadb
  command: >
    docker exec {{ container|quote }}
    mysqladmin ping -u{{ superuser|quote }} -p{{ superuser_password|quote }}
  register: result
  until: not result.rc  # or result.rc == 0 if you prefer
  retries: 20
  delay: 3

This runs mysqladmin ping ... until it succeeds (return code 0). Usually superuser is root. I tested using podman instead of docker but I believe the command is the same regardless. |quote does shell escaping, which according to the Ansible docs should also be done when using command:

like image 45
Tim Diels Avatar answered Oct 15 '22 03:10

Tim Diels


This works for me just fine:

  - name: get mariadb IP address
    command: "docker inspect --format '{''{ .NetworkSettings.IPAddress }''}' mariadb-container"
    register: mariadb_ip_address
  - name: wait for mariadb to become ready
    wait_for:
      host: "{{ mariadb_ip_address.stdout }}"
      port: 3306
      state: started
      delay: 5
      connect_timeout: 15
      timeout: 30
like image 3
Tomas Tomecek Avatar answered Oct 15 '22 03:10

Tomas Tomecek


wait_for does not work for the MySQL docker container because it only checks that the port is connectable (which is true straight away for the Docker container). However, wait_for does not check that the service inside the container listens the port and sends responses to the client.

This is how I am waiting in the ansible playbook for the MySQL service becoming fully operational inside the Docker container:

- name: Start MySQL container
  docker:
    name: some-name
    image: mysql:latest
    state: started
    ports:
    - "8306:3306" # it's important to expose the port for waiting requests
    env:
        MYSQL_ROOT_PASSWORD: "{{ mysql_root_password }}"

- template: mode="a+rx,o=rwx" src=telnet.sh.j2 dest=/home/ubuntu/telnet.sh

# wait while MySQL is starting
- action: shell /home/ubuntu/telnet.sh
  register: result
  until: result.stdout.find("mysql_native_password") != -1
  retries: 10
  delay: 3

And the telnet.sh.j2 is

#!/bin/bash -e

telnet localhost 8306 || true
like image 15
etrubenok Avatar answered Oct 15 '22 02:10

etrubenok