Image for post
Image for post

Docker the Pythonic Way — Part 2

Orchestrating containers with Docker SDK for Python Solution

In a previous article I stated the problem requirements for orchestrating Docker containers with WordPress and MySQL containers.

Previous Article

The Solution with Explanations

Basic Operations

The scope of the code will consist of essential four operations to create the volume resource, network resource, and then run MySQL container, and WordPress container:

import docker
d = docker.from_env()
d.volumes.create(...)
d.networks.create(...)
d.containers.run('mysql:5.7',...)
d.containers.run('wordpress:latest',...)

User Specified Host Port

We need to allow the user to specify a host port through the WORDPRESS_PORT environment variable, and default the port to 8080 if it is not set. We can arrange this by doing the following:

import oswordpress_port = os.environ.get('WORDPRESS_PORT') or '8080'

Volume Resource

The volume resource is pretty straight forward:

mysql_volume = 'db_data'd.volumes.create(mysql_volume, driver='local')

Network Resource

For the network resource, we need to not create it if it already exists. With the Python docker library, we can actually create multiple ones of the same name. That is a state we do not want.

network_name = 'wordpress_net'if not d.networks.list(network_name):
d.networks.create(network_name, driver='bridge')

MySQL Container

This is straight forward: we specify the image as the first parameter, set it run detached (or else the script blocks until the container is finished running), set the restart policy to always, use our network we created earlier, and a container name of db.

d.containers.run(
'mysql:5.7',
detach=True,
network=network_name,
restart_policy={'Name': 'always'},
volumes={
mysql_volume: {'bind': '/var/lib/mysql', 'mode': 'rw'}
},
environment=[
'MYSQL_ROOT_PASSWORD=wordpress',
'MYSQL_PASSWORD=wordpress',
'MYSQL_USER=wordpress',
'MYSQL_DATABASE=wordpress'
],
name='db')

WordPress Container

This is similar to the container we launched previously, except we have a different image, and container name of wordpress. We pass in environment variables that will trigger built-in automation from the WordPress container.

d.containers.run(
'wordpress:latest',
detach=True,
network=network_name,
restart_policy={'Name': 'always'},
ports={'80/tcp': wordpress_port},
environment=[
'WORDPRESS_DB_HOST=db:3306',
'WORDPRESS_DB_PASSWORD=wordpress',
'MYSQL_USER=wordpress',
'MYSQL_DATABASE=wordpress'
],
name='wordpress')

Check for Existing Containers

This script is functional, but will only work once. Should the containers be already running, or one of them has stopped, the script will fail.

containers = [
c for c in d.containers.list()
if c.name in ['db', 'wordpress']
]
if containers:
for container in containers:
container.stop()
containers = [
c for c in d.containers.list(all=True)
if c.name in ['db', 'wordpress']
]
if containers:
for container in containers:
container.remove()

The Complete Solution Source

Below is the final solution when all put together.

python sdk_run.py
export WORDPRESS_PORT=8888
python sdk_run.py

Conclusion

This is pretty straightforward, no quirky gotchas or tricks get basic to advance features to work. I was quite surprised how easy this was to put together.

Written by

Linux NinjaPants Automation Engineering Mutant — exploring DevOps, Kubernetes, CNI, IAC

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store