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 daemonimagescontainershostsDockerfile, 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 ubuntu image, 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 pip to install the Python requirements
  • It copies the content of the current directory (especially the app.py file 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.

Screenshot by the author

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.

Screenshot by the author

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:

Screenshot by the author

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
Screenshot by the author

To check that the container is indeed running in the background, you can use the ps Docker command that lists running containers.

Screenshot by the author

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.

Screenshot by the author

If we hit the refresh button multiple times, we can see HTTP logs on the container.

Screenshot by the author

You can also run this command in the background by adding -d option:

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 id using ps :

Screenshot by the author

And use it in the following command:

docker stop 11bca8ee1f8c
Screenshot by the author

By running ps again, the container is no longer visible.

Screenshot by the author

However, you can still view it as a stopped container (along with the other previously stopped containers):

docker ps -a
Screenshot by the author

6 — Start a stopped container

Given its id, you can start a stopped container with the docker start

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 prune command.

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.

Conclusion

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.

Original Source