Towards building, shipping, and deploying your apps with a peace of mind
Docker is a great tool to easily develop your applications, ship them into containers and deploy them everywhere.
In my job as a data scientist, I frequently use Docker whenever I need to package an application that has multiple services underneath (such as a back-end, a database, a front-end, etc) into an image that I can run, update, stop, share, and definitely deploy it to any cloud: the IT world has never seen such flexibility before.
In this post, I share a collection of Docker commands I frequently use to manipulate Docker containers. While this isn’t a thorough introduction to Docker, it should at least give you the basics at hand to do great things.
👉 If you’re a data scientist who plans to move to production and give his apps a second life outside of local notebooks, learning Docker is the way to go.
I hope you’re all set. Let’s dive in 🏊
This post assumes a tiny familiarity with Docker’s basic concepts such as Docker client and daemon, images, containers, hosts, Dockerfile, etc. If you’re new to these terms, I highly encourage you to check the overview section of the official docs: it’s a two-minute read, tops.
1 — Build a Docker image
“An image is a read-only template with instructions for creating a Docker container. Often, an image is based on another image, with some additional customization. For example, you may build an image which is based on the
ubuntuimage, but installs the Apache web server and your application, as well as the configuration details needed to make your application run.”
— Source: Docker docs.
For the sake of learning, we’re going to build and play with a custom Docker image instead of pulling one from the registry (think of a registry as a central location where Docker images are stored, something like Github but for images)
This image encapsulates a Python 3.7 environment and it has everything it needs to run a Flask API on port 80.
To build this Docker image, we need to define a series of instructions in a Dockerfile: this post won’t cover the specifics of Dockerfile commands. To learn more about them, I suggest you check this link.
The Dockerfile we’ll be using is the following: It’s basically a set of sequential instructions that contains all the commands a user would call on the command line to assemble an image.
Let’s go line by line to understand what this Dockerfile does:
- It starts by pulling a base image that encapsulates a lightweight python 3.7 environment
- It sets the working directory from which the Flask app will run on the container
- It copies the requirements.txt file from the host to the container (i.e. in the working directory)
- It runs
pipto install the Python requirements
- It copies the content of the current directory (especially the
app.pyfile to the container)
- It indicates that the container is listening on the network port 80 at runtime
- It executes the Python code when the image is run
The Python code we’ll be running is a simple hello-world Flask API, nothing fancy.
To build the image and tag it with a specific name (I chose
flask_image ), run the following command:
docker build -t flask_image
Once the build starts executing, it goes over each step in the Dockerfile.
There’s definitely a lot going on here, so I’m just going to skip the details so that you won’t get overwhelmed. But if you’re interested, I recommend you check this section.
2 — Run a Docker container
“A container is a runnable instance of an image. You can create, start, stop, move, or delete a container using the Docker API or CLI. You can connect a container to one or more networks, attach storage to it, or even create a new image based on its current state.” — Source: Docker docs.
Once a Docker image is built, you can first check its existence on your filesystem.
Then, you can run it: this will create a container. If you run the image again, this will create another container, and so on. In fact, a container, as the official docs indicate, is nothing but a running instance of the image.
Let’s run a container by running our image:
As expected, this container fires a Flask server listening to the TCP port 80.
Great! but it seems that we cannot exit the console without killing the container. It would be really nice if we could run the container in the background.
3 — Run a container in the background
Most of the time, your containers need to be run in the background as services. This could be an API like the one we’re playing with or a database, proxy server, a React app, etc.
Here’s how you’d do it: you just add the
-d (for detached) option:
docker run -d flask_image
To check that the container is indeed running in the background, you can use the
ps Docker command that lists running containers.
Now that the container is running and serving an awesome API (we can see the port number is printed to the console), can we access it from the outside, i.e. from the host, and start sending queries to it?
4 — Map ports between the container and the host
To make our Flask API accessible from the host, we need to map the current container’s port (80) to an available port on the host. Let’s pick, say … 1234
The syntax is the following:
docker run -p 1234:80 flask_image
If we hit http://localhost:1234, Chrome indicates that the API is indeed accessible from the host.
If we hit the refresh button multiple times, we can see HTTP logs on the container.
You can also run this command in the background by adding
docker run -d -p 1234:80 flask_image
Now you’ve got yourself a running API that’s accessible from outside the container.
5 — Stop a container from running
Assume you run a container in the background and now you want to stop it.
First, look up its
And use it in the following command:
docker stop 11bca8ee1f8c
ps again, the container is no longer visible.
However, you can still view it as a stopped container (along with the other previously stopped containers):
docker ps -a
6 — Start a stopped container
Given its id, you can start a stopped container with the
You just have to provide its id:
docker start 11bca8ee1f8c
7 — Remove a stopped container
Once a container is stopped and you need to remove it, you first need to grab its id using
docker ps -a then launch a
docker rm command.
docker rm 11bca8ee1f8c
8— Remove all stopped containers
Now if you need to remove all stopped containers and don’t want to do it manually, you can use the
docker container prune
9 — Run a container and remove it after it stops
If you want to automatically remove a container after it stops, you can use the
—rm option when running it.
This is a nice option that provides cleanup.
docker run --rm -d -p 1234:80 flask_image
10 — Rename a container
If for whatever reason, you need to rename your container, you can do it with the
docker rename command.
We’ve just scratched the surface of what containers are, what they do, and how you can play with them with simple (and useful) commands.
However, since containers have a single responsibility in general, they’re usually composed with other containers to form a complete stack: this is achieved by docker-compose, something we might investigate in a future post.