Home > Blockchain >  Does docker-compose support init container?
Does docker-compose support init container?

Time:12-14

init container is a great feature in Kubernete and I wonder whether docker-compose supports it? it allows me to run some command before launch the main application.

I come cross this PR https://github.com/docker/compose-cli/issues/1499 which mentions to support init container. But I can't find related doc in their reference.

CodePudding user response:

This was a discovery for me but yes, it is now possible to use init containers with docker-compose since version 1.29 as can be seen in the PR you linked in your question.

Meanwhile, while I write those lines, it seems that this feature has not yet found its way to the documentation

You can define a dependency on an other container with a condition being basically "when that other container has successfully finished its job". This leaves the room to define containers running any kind of script and exit when they are done before an other dependent container is launched.

To illustrate, I crafted an example with a pretty common scenario: spin up a db container, make sure the db is up and initialize its data prior to launching the application container.

Note: initializing the db (at least as far as the official mysql image is concerned) does not require an init container so this example is more an illustration than a rock solid typical workflow.

The complete example is available in a public github repo so I will only show the key points in this answer.

Let's start with the compose file

---
x-common-env: &cenv
    MYSQL_ROOT_PASSWORD: totopipobingo

services:
    db:
        image: mysql:8.0
        command: --default-authentication-plugin=mysql_native_password
        environment:
            <<: *cenv
    init-db:
        image: mysql:8.0
        command: /initproject.sh
        environment:
            <<: *cenv
        volumes:
            - ./initproject.sh:/initproject.sh
        depends_on:
            db:
                condition: service_started
    my_app:
        build:
            context: ./php
        environment:
            <<: *cenv
        volumes:
            - ./index.php:/var/www/html/index.php
        ports:
            - 9999:80
        depends_on:
            init-db:
                condition: service_completed_successfully

You can see I define 3 services:

  • The database which is the first to start
  • The init container which starts only once db is started. This one only runs a script (see below) that will exit once everything is initialized
  • The application container which will only start once the init container has successfuly done its job.

The initproject.sh script run by the db-init container is very basic for this demo and simply retries to connect to the db every 2 seconds until it succeeds or reaches a limit of 50 tries, then creates a db/table and insert some data:

#! /usr/bin/env bash

# Test we can access the db container allowing for start
for i in {1..50}; do mysql -u root -p${MYSQL_ROOT_PASSWORD} -h db -e "show databases" && s=0 && break || s=$? && sleep 2; done
if [ ! $s -eq 0 ]; then exit $s; fi

# Init some stuff in db before leaving the floor to the application
mysql -u root -p${MYSQL_ROOT_PASSWORD} -h db -e "create database my_app"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -h db -e "create table my_app.test (id int unsigned not null auto_increment primary key, myval varchar(255) not null)"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -h db -e "insert into my_app.test (myval) values ('toto'), ('pipo'), ('bingo')"

The Dockerfile for the app container is trivial (adding a mysqli driver for php) and can be found in the example repo as well as the php script to test the init was succesful by calling http://localhost:9999 in your browser.

The interesting part is to observe what's going on when launching the service with docker-compose up -d.

The only limit to what can be done with such a feature is probably your imagination ;) Thanks for making me discovering this.

  • Related