Random Technology thoughts from an Irish Virtualization Geek (who enjoys saving the world in his spare time).

Last time we did the base build of a Raspberry Pi with Docker hosting a bunch of different services and we left Docker looking like this (as seen via Portainer)

We also walked through setting up an external Kodi client to reference the MySQL server.

That was pretty neat in that we did a bunch of consolidation, but each of the services on the docker host were more or less standalone in that there were no dependencies between them, and therefore the startup order was more or less irrelevant. All of the containers had a restart policy of always (meaning they would restart when crashed or when the docker host booted). So what would happen if we were to add a dependent container (e.g a Kodi client) to our Docker configuration?

And our Kodi client, available on http://[pi-static-ip]:8080 is showing the data we scraped in using our external Kodi client

But now we have two problems

Problem One: We have a dependency between the kodi-client container and the mysql-server container, in that Kodi needs MySQL to be running when it launches. But if you look at the configuration of the Kodi client, you will see the following startup command, which isn’t going to wait on anything.

Problem Two: We have a really complex docker run command to remember if we need to rebuild the Kodi container with a newer image

So I’m going to use Docker Compose to solve both of our problems. Docker Compose allows you to coordinate a related set of Docker containers, either from existing images or from ones that you want to build on the fly. We will do both in this case.

Installing Docker Compose

SSH into Pi

sudo apt-get update

sudo apt-get install -y python python-pip

sudo pip install docker-compose

Obtain wait-for-it.sh

We are going to use this utility to have our Kodi container wait on the MySQL server to be ready before launching Kodi itself

Stop and Remove Containers

To build our dependent containers we need to remove the original ones. All of our data is saved externally, so we wont lose anything by rebuilding the containers. In fact, this is one of the selling points of Docker to begin with

You can stop and remove the containers through Portainer or you can do it via command line as follows

docker stop kodi-client

docker stop mysql-server

docker container rm kodi-client

docker container rm mysql-server

Create Dockerfile

We need to modify the standard Kodi image as we want to inject our our wait-for-it.sh script into it. We will use a Dockerfile as follows:

SSH into Pi

cd /compose/media-center

sudo vi Dockerfile

Enter the following contents:

FROM codafog/kodi-rpi
COPY wait-for-it.sh .

This will pull down the codafog/kodi-rpi image and inject the wait-for-it.sh into it creating a new custom image.

We are recreating the mysql-server and the kodi-client containers with more or less all the same inputs as before but in a much nicer format

mysql-server is grabbing a standard image using the image flag

kodi-client is building a custom image using the build flag to combine a base image and our custom injected script

The ‘build .‘ under the kodi service is using the contents of the Dockerfile in the current working directory to pull down the image, inject our script, create a new image and spin out a container called kodi-client from it

We are using the depends_on flag to make starting the kodi-client container dependent on the mysql-server container being started

This does nothing more than start the mysql-server container before the kodi-client container. It doesn’t actually wait for mysql-server itself to be available.

Because of this we are overriding the default startup command for the kodi-client container and replacing it with one that uses our wait-for-it.sh script to successfully test the availability of MySQL before starting Kodi as normal

Starting Up the configuration

SSH into Pi

cd /compose/media-center

docker-compose up -d

See how much easier that is vs remembering those docker run commands? If you want to force a rebuild of the images (maybe you have newer base images for the docker containers) then just do this instead

docker-compose up -d –build

If you look at the configuration of the kodi-client container now it looks like this. Note the new startup command.

And the overall containers list looks like this. See how we have media-center in the stacks column. This isn’t a true stack as that’s intended for docker swarm, but thats how Portainer views it. The media-center name comes from the folder name docker-compose was run from.

If you check the logs on the kodi-container itself, you will see this

You can also see the same from the command line by

SSH into Pi

cd /compose/media-center

docker-compose logs

Summary

Now we have a system with dependencies, but have controlled the start order. Even if the docker host reboots suddenly, the startup configuration of the kodi-client container will ensure that it will wait for MySQL to be running before it attempts to a launch Kodi.

Technically this could all be done without Docker Compose, but I think you’ll agree it’s an elegant way to handle the setup. Docker Compose can bring many other advantages which we haven’t used here, and you can also setup the docker-compose.yml to run as a service, but thats a topic for another time!