Docker the Pythonic Way
Orchestrating containers with Docker SDK for Python
Earlier I demonstrated on how use Python use some shell interactivity in order to automate container orchestration through the Docker CLI command docker
.
I’m not going to lie, Python, is well, perhaps not a pretty sight with regards to using subshell with popen()
. Best advice, unless absolutely need to interact with the shell, just don’t do it.
However with Python, you can just talk to the Docker service directly through the Docker SDK or Python, otherwise known as docker-py.
This Python library is what is used for both Ansible docker modules and Docker Compose tool. So let’s go directly to the source, and use the library instead of higher level tools.
Problem
The goal of this exercise bring up fully functional WordPress environment that you can use for your development delights. This means using Python to orchestrate two containers. Below are featured organized into basic and advanced.
When completed, name the script docker_sdk.py
or other suitable name, and run it to verify it features manually or with Inspec script listed in Verification section.
Basic Feature Requirements
We want to bring up the containers and verify they work.
For this we want to do the following:
- Launch MySQL (
mysql:5.7
) with restart policy of always, intuitive name of db, and to triggering internal container configuration by passing environment variables to setup root password, and a wordpress database, user, and password. - Launch WordPress (
wordpress:latest
) with restart policy ofalways
, intuitive name ofwordpress
, map the container port of80
to host port of8080
, and to triggering internal container configuration by passing environment variables to setup
Advanced Feature Requirements
For this, we want to support put our containers on a private network, use a persistent volume for the MySQL database, and allow the user to specify the host port with WORDPRESS_PORT
environment variable.
We will do this to implement the features:
- Create a volume resource and mount it as
/var/lib/mysql
for thedb
container. - Create a network resource and configure both containers to use the private network.
- Set the host port to the environment variable
WORDPRESS_PORT
, and if this is not set, then default it to port8080
Verification
You can manually verify the solution or use the automated InSpec script to verify the results.
Manually Verification of Basic Features
With docker inspec
, jq
, and grep
, you features as depicted by the graphic below:
Manual Verification of Advanced Features
With docker inspec
, jq
, and grep
, you features as depicted by the graphic below:
Automated Verification
With InSpec (gem install inspec && gem install inspec-bin
), you can verify both basic and advance features:
Download the script as container_test.rb
, and run it:
inspec exec container_test.rb
If you set an alternative port with WORDPRESS_PORT
, you can verify using the following commands:
echo "port: $WORDPRESS_PORT" > attributes.yml
inspec exec container_test.rb --attrs=attributes.yml
Underrepresented Testing
Back in the day, testers were challenged to break the application, but these days, it seems that testing is regulated to developers verifying features are completed. For this reason, I call these underrepresented testing instead of negative, destructive, or edge testing.
At minimum, in any change system, you want verify that the automation idempotent, where running it more than once produces the same results. It definitely should not give you a traceback, or create new resources with the same name, such as multiple networks with the wordpress_net
name.
Here are some additional tests that you may want (or not want) to try with the final solution:
Clean Up Script
You can use this to erase your environment and start over again should you need it.
Removing Containers
docker ps -f name=wordpress -q | xargs docker stop && \
docker ps -f name=wordpress -aq | xargs docker rmdocker ps -f name=db -q | xargs docker stop && \
docker ps -f name=db -aq | xargs docker rm
Removing Volume and Network Resources
docker volume rm db_data
docker network ls -f name=wordpress_net -q | xargs docker network rm
Validation
For validation, you would point your web browser to the host port, and interact with the WordPress application.
For the database persistence, create stuff, maybe like a blog post. Then stop and remove the MySQL db
container, and recreate it, making sure not to remove the volume db_data
. The data should still exist after this process.
Resources
References
- Docker SDK Networks API: https://docker-py.readthedocs.io/en/stable/networks.html
- Docker SDK Volumes API: https://docker-py.readthedocs.io/en/stable/volumes.html
- Docker SDK Containers API: https://docker-py.readthedocs.io/en/stable/containers.html
- Docker SDK Examples: https://docs.docker.com/develop/sdk/examples/
- Docker Client Examples: https://www.programcreek.com/python/example/107511/docker.DockerClient
Formal Requirements Document
Related Articles
Problem for Docker CLI
Solution for Docker CLI in Shell Programming
Solution for Docker CLI in Python, Ruby, and Perl
Last Thoughts
For this article, I presented the problem and how to test and validate it. I hope you can try out Inspec script to test your solution to get a sample of TDD for systems programming.
In a follow-up article, I will present the solution.