Dockerfiles
- Write Dockerfiles to create new images
- Containerise applications using Docker
- Test and deploy containerised applications on AWS
Pre work
Research
- Read through this article to understand the basics of Dockerfiles
- Read this cheatsheet to get a sense of the syntax
- Find an open-source project on Github with a Dockerfile and try to understand it
Code
Write a Flask server with one route, /draw. This route should return a text-based representation of a single card (e.g. `"3H").
The server should run be default on port 8080, but accept an environment variable to change this.
Workshop
Introduction
Ask trainees what they remember about Docker. What is it? Why is it useful?
Remind trainees that they've already used Docker to run different services (e.g. Kafka).
Explain that this was only possible because those services had been dockerised: configured to run as a container.
Note that, had they not been dockerised, we'd have had to do much more config to get them running on our machines.
Introduce the key elements of this process:
- A Dockerfile describes how to build an image from your code
- An image is a compressed, portable version of your code, including all required resources and instructions
- A container is an isolated instance of your code, built from an image and actually running
- Dockerisation is the process of converting your code into an image using a Dockerfile
Use, if helpful, the analogy of a frozen meal here; the Dockerfile is the recipe, the image is the frozen meal, and the container is the edible, thawed version.
State that we can dockerise our own code/apps/services, gaining the same flexibility of which we have already taken advantage.
The code
Create a script that has at least one dependency.
Copy, if you wish, the below example:
- main.py
- names.txt
- requirements.txt
"""Generates random pairings."""
from random import shuffle
import pandas as pd
def load_names(filename:str="names.txt") -> list[str]:
"""Returns a list of names from a file."""
with open(filename, "r", encoding="utf-8") as f:
data = [l.strip().title() for l in f.readlines()]
return data
def generate_pairs(names:list[str]) -> pd.DataFrame:
"""Returns a dataframe of random pairings."""
return pd.DataFrame(
data = [(names[i], names[i + 1]) for i in range(0, len(names), 2)]
)
if __name__ == "__main__":
names = load_names("names.txt")
shuffle(names)
pairings = generate_pairs(names)
print(pairings)
Rich
Chris
Louise
Vanessa
Joni
Sodrul
Emily
Sophie
Matthew
Daniela
Xiao
Dave
pandas
Demonstrate that this script runs locally.
Discuss all the things it requires to do so:
- Python
- All libraries installed
- A
names.txtfile in the right directory - Knowledge of the command to run the script
Point out that having to ensure all of the above manually on every new computer quickly gets tedious/unmanageable.
State your intention to dockerise the app, so that it is portable and easy to run on the cloud.
The Dockerfile
Introduce the concept of a Dockerfile and share the documentation.
Create a basic Dockerfile:
# Describes what you do to the local code to build an image
FROM python:latest
COPY requirements.txt .
COPY names.txt .
COPY main.py .
RUN pip3 install -r requirements.txt
# The actual instruction when defrosted
CMD python3 main.py
Talk through the file, noting the key aspects:
FROM, which defines a starting imageCOPYcommands, to copy files from the local machine into the imageRUNcommand, to execute particular shell commands in the image (install libraries, set up folders, etc.)CMDcommand, stating what command to execute when a container is created
Dockerising
Run the dockerisation command: docker buildx build -t [name]:[label] ..
Narrate the process as it runs.
Show the created image with docker image ls.
Run a container based on the image with docker run [name]:[label] and show the output.
Layers
Make a small change to the script and re-build the image.
Note that it takes a while.
Explain the idea of cached layers in an image: as the installation step is after the script being copied, a small change to the script leads to a whole new install.
Swap the COPY and RUN instructions, and show that it builds faster after small changes, only installing libraries once.
Warn trainees that having out-of-order instructions can really slow down development time; they should be thinking about efficiency at every stage.
Challenge
Divide trainees into pairs.
Challenge pairs to
Create a dockerised app that does the following when run:
- Runs the server written during the pre-work
- Makes it accessible in the browser when the docker container is run
- Above & Beyond: Add a Healthcheck to the docker container
Encourage trainees to explore the documentation and find more advanced behaviour.
Allow them the remaining time to experiment/explore this technology.
Answer any questions that arise.
Conclusion
Assert that any app can be dockerised, and that doing so provides a clean, organised way to move it onto the cloud.
State that dockerising apps will be a common step in this week and future ones.