Run Script After MySQL Docker Initialization

May 31, 2022

01021-container–extremely-detailed-cyberpunk-(-steampunk-)–day-light–realistic-shaded

The Problem

I wanted to setup automated tests for OpenSupports.

I made them run after each commit with Github Actions, but they failed. Sometimes.

Inside the Ubuntu given by Github Actions, I ran all steps inside Docker containers.

The steps looked like this:

    steps:
      - uses: actions/checkout@v3
      - run: make build
      - run: make run
      - run: make install
      - run: make test

And all those make commands interact with Docker containers.

  • make build: builds the images from Dockerfile files, or pulls them from repos with official images
  • make run: does a docker run under the hood, which starts the containers
  • make install: does initialization steps, like installing dependencies, and setting up a base database (this last step was causing problems)
  • make test: finally runs all tests

When done this way, one step after another, I sometimes saw this error in the logs from Docker:

2022-05-31T14:45:34.922935Z 0 [ERROR] InnoDB: Unable to lock ./ibdata1 error: 11
2022-05-31T14:45:34.922969Z 0 [Note] InnoDB: Check that you do not already have another mysqld process using the same InnoDB data or log files.

But sadly none of the resources for these errors helped me.

The Solution

The MySQL Docker official image will run all .sh scripts in the folder /docker-entrypoint-initdb.d from the docker container.

First I placed my initialization script in a folder, like ./scripts-db/init-db.sh, with content:

mysql -u root -e "CREATE DATABASE IF NOT EXISTS development;"

Then I mounted that folder to the special location inside the docker container: I added -v $(pwd)/.scripts-db:/docker-entrypoint-initdb.d to my docker run command.

Then I just removed the extra step that tried to create the database in make install, since it now gets done from the make run command alone.

The Explanation

The problem was caused by a race condition. While the machine was initializing the MySQL instance, I was attempting to create a database. This sometimes worked, and sometimes didn’t (depending on if the initialization steps were already completed or not).

In order not to block your terminal, you usually initialize Docker instances with docker run -d. This -d means “detached”, and effectively runs your container as a background process.

As a result, first running make run started the MySQL image, but that requires some initialization steps, and at the same time those initialization steps were being done, the script under make install runs, which tries to create a database. As a consequence, I received the error mentioned above.

The solution was creating the database directly after all those initialization steps ran. The MySQL Docker official image has a way to do this (explained in The Solution section).


Do you have any feedback/comments? Hit me up at maxiredigonda@gmail.com