Dockerize your Python app
Sep 14, 2023
Intro
What is a container?
A container is a sandboxed process running on a host machine that is isolated from all other processes running on that host machine. That isolation leverages kernel namespaces and cgroups, features that have been in Linux for a long time. Docker makes these capabilities approachable and easy to use.
- Is a runnable instance of an image. You can create, start, stop, move, or delete a container using the Docker API or CLI.
- Can be run on local machines, virtual machines, or deployed to the cloud.
- Is portable (and can be run on any OS).
- Is isolated from other containers and runs its own software, binaries, configurations, etc.
If you’re familiar with chroot, then think of a container as an extended version of chroot. The filesystem comes from the image. However, a container adds additional isolation not available when using chroot.
What is an image?
A running container uses an isolated filesystem. This isolated filesystem is provided by an image, and the image must contain everything needed to run an application - all dependencies, configurations, scripts, binaries, etc. The image also contains other configurations for the container, such as environment variables, a default command to run, and other metadata.
Installation
- kvm
Docker Desktop runs a VM that requires KVM support
modprobe kvm lsmod | grep kvm
Set up KVM device user permissions link
# To check ownership of /dev/kvm ls -al /dev/kvm # Add your user to the kvm group in order to access the kvm device sudo usermod -aG kvm $USER
Sign out and sign back in so that your group membership is re-evaluated.
- deb
wget
sudo apt remove docker-desktop
rm -r $HOME/.docker/desktop sudo rm /usr/local/bin/com.docker.cli sudo apt purge docker-desktopsudo apt-get update sudo apt-get install ./docker-desktop-<version>-<arch>.deb
To start Docker Desktop
systemctl --user start docker-desktop
Check the versions of the binaries
docker-credential-gcloud compose version # Docker Compose version v2.17.3 docker --version # Docker version 23.0.5, build bc4487a docker version # Client: Docker Engine - Community # Cloud integration: v1.0.31 # Version: 23.0.5 # API version: 1.42 # <...>
To enable Docker Desktop to start on login
systemctl --user enable docker-desktop
- ob-docker
(use-package docker :ensure t :bind ("C-c d" . docker))
Containerize an application
Get the app
Let’s say you have the following python repository
βββ my_app/ β βββ main.py β βββ README.md β βββ test/ β βββ src/ β βββ requirements.txt
Build an image
- Create a
Dockerfile
To build the image, you’ll need to use a Dockerfile. A Dockerfile is simply a text-based file with no file extension that contains a script of instructions. Docker uses this script to build a container image.
cd /path/to/my_apptouch Dockerfile
FROM python:3.8-alpine # Or any preferred Python version. ADD main.py . RUN pip install requests beautifulsoup4 python-dotenv CMD [βpythonβ, β./main.pyβ] # Or enter the name of your unique directory and parameter set.
This Dockerfileis fairly basic, which is perfect for this application. Your
Dockerfilewill change depending on your code and desired app functionality. There are also other arguments available, likeWORKDIR, ENV, COPY, EXPOSE, ENTRYPOINT and HEALTHCHECK. Each allows you to build more operative complexity into your Python applications, or control which resources are pulled in. - build
The
docker buildcommand uses the Dockerfile to build a new image.docker build -t my_app .
The docker build command uses the Dockerfile to build a new image. You might have noticed that Docker downloaded a lot of “layers”. This is because you instructed the builder that you wanted to start from the
python:3.8-alpineimage. But, since you didn’t have that on your machine, Docker needed to download the image.After Docker downloaded the image, the instructions from the Dockerfile copied in your application and used
pipto install your application’s dependencies. TheCMDdirective specifies the default command to run when starting a container from this image.Finally, the
-tflag tags your image. Think of this as a human-readable name for the final image. Since you named the image getting-started, you can refer to that image when you run a container.The
.at the end of thedocker buildcommand tells Docker that it should look for theDockerfilein the current directory.
run an image
Now that you have an image, you can run the application in a container using the docker run command.
docker run -dp 127.0.0.1:3000:3000 my_app
The -d flag (short for --detach) runs the container in the background. The -p flag (short for --publish) creates a port mapping between the host and the container. The -p flag takes a string value in the format of HOST:CONTAINER, where HOST is the address on the host, and CONTAINER is the port on the container. The command publishes the container’s port 3000 to 127.0.0.1:3000 (localhost:3000) on the host. Without the port mapping, you wouldn’t be able to access the application from the host.
After a few seconds, open your web browser to http://localhost:3000. You should see your app.
If you take a quick look at your containers, you should see at least one container running that’s using the my_app image and on port 3000. To see your containers, you can use the CLI or Docker Desktop’s graphical interface.
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES df784548666d my_app "docker-entrypoint.sβ¦" 2 minutes ago Up 2 minutes 127.0.0.1:3000->3000/tcp kiriclope