3

I have a dockerized app that uses mysql, express & react.

I need to first initialize mysql with a docker-entrypoint-initdb.d before starting the express app. However, when mysql server starts it doesn't execute the starting .sql script right away and my_database_name starts initially empty.

In that timegap, my express app starts and tries to query en empty database. Later the initialization script works as intended and fills my_database_name which is already too late by then since my express app has already started.

I've tried depends_on/condition as shown below but Version 3 no longer supports the condition form of depends_on as stated in the docs.

version: '3.8'

services:
  api-server:
    build:
      context: ./server
      dockerfile: ./Dockerfile
    image: myapp_server
    env_file: ./server/.env
    stdin_open: true
    tty: true
    depends_on:
      mysqldb:
        condition: service_healthy
    ports:
      - 9000:9000
    networks:
      - mysern-app
    container_name: my_express_app

  mysqldb:
    image: mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: my_database_name
    volumes:
      - mysql-data:/data/db
      - ./db/backup/:/mysql/backup
      - ./db/init:/docker-entrypoint-initdb.d
    healthcheck:
      test: 'not sure what to write in here as well'
      interval: 1s
      retries: 120
    networks:
      - mysern-app
    ports:
      - 3306:3306
    container_name: my_mysql_app
networks:
  mysern-app:
    driver: bridge
volumes:
  mysql-data:
    driver: local

I ultimately want to do this sequence:

Start mysqldb > fill the table from the script > start the express app

usersina
  • 1,063
  • 11
  • 28

2 Answers2

2

There are several things you can do:

  1. Add restart: always to your api-server. If it crushes because MySQL is not yet available - it will restart until MySQL will be available. I'm assuming that your api-server will crush if MySQL is not available.
  2. In case it won't crush, implement health-check for your service, so it won't be available if Mysql isn't available.

docker-compose is your orchestrator and it can help you and take care of failures. In real-world, your MySQL might be not available for a second too, and you must know how to handle that.

ItayB
  • 10,377
  • 9
  • 50
  • 77
1

This worked for me:

version: "3.7"
services:
  acme-db:
    image: mysql:5.7
    command: mysqld --sql_mode="" --max_connections=1100 --general-log=1 --general-log-file=/tmp/mysql-general-log.log
    container_name: eventhos-db
    ports:
      - "3306:3306"
    volumes:
      - ./database:/docker-entrypoint-initdb.d
    environment:
      MYSQL_ROOT_PASSWORD: changeme
      MYSQL_PASSWORD: changeme
      MYSQL_USER: "usr_acme"
      MYSQL_DATABASE: "acme"
      TZ: America/Lima
    deploy:
      resources:
        limits:
          memory: 512M
    healthcheck:
      test: 'cat /tmp/mysql-general-log.log | grep "root@localhost on  using Socket"'
      interval: 10s
      retries: 120

Explanation

There is not a native way to ask the mysql if dump has been fully imported.

Researching I found an internal mysql log file called mysql general_log and reviewing its content in dockerized mysql I detected a pattern:

If everything is ok, at the end this line appear: "root@localhost on using Socket" just once

enter image description here

So if we enabled this log using command: in docker-compose:

command: mysqld --sql_mode="" --max_connections=1100 --general-log=1 --general-log-file=/tmp/mysql-general-log.log

The health check is just a search of these line

cat /tmp/mysql-general-log.log | grep "root@localhost on  using Socket"

Note: Health check interval less than 10 seconds, don't work!

JRichardsz
  • 14,356
  • 6
  • 59
  • 94