In this tutorial we will use Docker to create separate Python and database containers and place them in their own network such that they are able to communicate with each other. In Docker this can be done manually using normal docker
commands or we can use a tool called Docker Compose.
The final code from this tutorial is on GitHub here.
Firstly, let's view what Docker networks we have currently:
docker network ls
Create a new network which we will call appnet
:
docker network create appnet
Now onto the containers. We will use MariaDB for our database container:
docker run --rm -d --name=db --network=appnet -e MYSQL_ROOT_PASSWORD=password mariadb
Start a temporary Python container within the same network (specified by the --network
flag) and open up a shell prompt:
docker run --rm -it --name=app --network=appnet python:alpine sh
Install PyMySQL with pip install PyMySQL
.
Now within a python
prompt try:
import pymysql.cursors
connection = pymysql.connect(host='db', user='root', password='password')
The database host is the name of the MariaDB container that we gave it. If this runs without errors, then we have managed to get our Python container to talk to our database container.
Let's now create a more permanent container. Exit out of the Python container. Insert the Python code above into a file called app.py
. Create another file called Dockerfile
and insert into it the following:
FROM python:alpine
COPY . .
RUN pip install pymysql
CMD ["python", "app.py"]
Build the image:
docker build -t pythonapp .
Create a container (make sure the database container from above is still running):
docker run --rm --name=app --network=appnet pythonapp
If this returns nothing, then it should have worked. Add a print('It worked!')
to the end of app.py
to check (remember to rebuild the image first).
Whilst it's only really a few Docker commands to create this very simple network of containers, it can get unwieldy if we had many more containers and multiple networks. Instead we can use Docker Compose which uses a YAML file to define all our containers and network configuration.
We will need to create a file called docker-compose.yaml
in the root directory of our project.
Let's insert the following into this file:
version: "3"
services:
db:
image: mariadb:latest
restart: always
environment:
MYSQL_ROOT_PASSWORD: password
python:
build: .
You can see that we have two "services" - these are our containers i.e. the database and the Python script. You can also see that the file conveys pretty much the same information as our Docker commands from before. More information about the Compose file format can be found here. Note that we do not need to specify anything about a network since Docker Compose will automatically assign one for all the services.
We will also need to tweak the Python script to account for the MariaDB instance taking a bit of time to start up. You can control the order in which services start up, but the docs state that:
Compose does not wait until a container is “ready” ... - only until it’s running.
In our case this means that the MariaDB instance might be pingable at the start, but it doesn't mean we can run queries on it yet.
Let's put this in app.py
instead:
import pymysql.cursors
import time
while True:
try:
connection = pymysql.connect(host='db', user='root', password='password')
print('WE ARE IN!', flush=True)
break
except:
print('NOT YET IN.', flush=True)
time.sleep(1)
The container will now try to connect to the database every one second until it works.
Finally, we can start up our network of containers with simply:
docker-compose up
This will build the images and start each container. You should see a load of log messages mostly coming from the database container but also a few NOT YET IT.
logs from the Python container. At the end you should see the final WE ARE IN!
log message confirming that it worked.
docker-compose ps
will show a list of containers that have been created through Compose. docker-compose down
will stop and remove all the containers.
We have now laid the groundwork to create a proper Python application that utilises a database and also make sure that it's all within it's own network.