Docker Tutorial

Arteco - Information Technologies
  • :)
  • :0
  • :D
  • ;)
  • :]
foto Ramón Arnau

Ramón Arnau

Gerente de Arteco Consulting SL

Docker is a Virtualization Software that allows running Applications encapsulated within Containers, allocating Resources to them

Docker is a virtualization system that allows starting virtual machines locally or on an Internet server, each with a specialized application or service, such as running a MySQL database. Learn to build and deploy your distributed applications easily in the cloud with Docker.

What is Docker?

Docker is a virtualization service that can be deployed locally or in the cloud, which allows for managing virtual containers. Containers are similar to virtual machines but share some common layers to alleviate the workload on the host or server that needs to run all of them.

Each container typically contains a pre-installed application within what is called an image. Programmers and system administrators build this image by including the application, configuration files, and other resources, enabling the container to run the application.

Advantages of Using Docker

Docker greatly simplifies starting pre-configured applications, thanks to the community providing thousands of well-packaged services in images that can easily be started on a regular PC, such as a MySQL database or a Java application with Spring Boot. With minimal knowledge, an advanced user can package their own applications to distribute to other users.

These images can be distributed locally or publicly on the Internet on web platforms called registries, similar to Maven artifact repositories. To give flexibility to applications, they usually accept parameters in the form of environment variables, which allow adapting the application according to the environment. For example, some images can be parameterized with the address where the database is located.

Another great advantage of using Docker is that these containers can be assigned quotas for CPU, memory, and disk to keep them isolated from the rest of the processes and containers running on the host. Typically, network traffic is redirected with TCP/IP rules so that incoming communications to the host are propagated to the appropriate container, either through the use of different ports or through a reverse proxy like Traefik that uses different domain names or HTTP routes to redirect traffic.

What are Containers?

The industry standard today is to use virtual machines (VMs) to run software applications. Virtual machines run applications within a guest operating system, which runs on virtual hardware powered by the server's host operating system.

Virtual machines are excellent for providing complete process isolation for applications: there are very few ways in which an issue in the host operating system can affect the software running in the guest operating system, and vice versa. However, this isolation comes at a high cost: the computational overhead spent on virtualizing the hardware for a guest operating system to use is substantial.

Containers take a different approach: by leveraging the low-level mechanics of the host operating system, containers provide most of the isolation of virtual machines at a fraction of the required computing power.

Why Use Containers?

Containers offer a logical packaging mechanism in which applications can be abstracted from the environment in which they actually run. This decoupling allows container-based applications to be deployed easily and consistently, regardless of whether the target environment is a private data center, a public cloud, or even a developer's personal laptop. This gives developers the ability to create predictable environments that are isolated from the rest of the applications and can run anywhere.

From an operations perspective, in addition to container portability, they also give you more granular control over resources, providing greater efficiency to your infrastructure, which can result in better utilization of your computing resources.

Container Illustration

Due to these benefits, containers (and Docker) have seen widespread adoption. Companies like Google, Facebook, Netflix, and Salesforce leverage containers to make large engineering teams more productive and improve the utilization of computing resources.

What Will This Tutorial Teach Me?

This tutorial aims to be the one-stop shop for getting hands-on with Docker. Besides demystifying the Docker landscape, it will give you practical experience in building and deploying your own web applications in the cloud.

This document contains a series of sections, each explaining a particular aspect of Docker. In each section, we will be writing commands (or writing code). All the code used in the tutorial is available in the GitHub repository.

Note: This tutorial uses Docker version 19.03.8-ce. If you find any part of the tutorial incompatible with a future version, please let us know. Thank you!

Docker Requirements

No specific skills are needed for this tutorial beyond basic comfort with the command line and using a text editor. Previous experience in web application development will be useful but is not necessary. As we progress through the tutorial, we will make use of some cloud services. If you are interested in following along, create an account on the indicated site (it's free):

We will use this account to publicly host the images you build. Don't worry, when it comes to an enterprise application, you can host the image in a private registry.

How to Install Docker

Whether you have Windows, Linux, or Mac, the best way to install Docker is via the official packages prepared by the project, which provide very easy-to-run installers. All of them require administrator permissions on the machine, as the software needs to actively interact with network services for redirecting traffic that originates from or is destined for any of the containers it manages.

The only limitations on installing Docker are that your PC or laptop must have a certain capacity and power. On the other hand, if you are a Windows user, you will need the Professional version to install Docker. If not, check out the Ubuntu installation tutorial, the best operating system for programming, completely free and open source.

Below are the links to proceed with the installation according to the operating system used:

How to Use Docker / Compose

Once Docker is installed on your machine, it will be running as a background service orchestrating the different containers you start. Obviously, right after installing Docker, there won't be any containers running. You can try to start a test container with the following command in the command line:

docker run hello-world

The output of the command should display a message similar to the following:

Hello from Docker. This message shows that your installation appears to be working correctly. ...

Docker BusyBox

Now that we have everything set up, it's time to get our hands dirty. In this section, we will run a BusyBox container on our system and test the [docker run].

To start, let's run the following in our terminal:

docker pull busybox

Depending on how Docker is installed on your system, you might see a permission denied error after running the above command. If you are on a Mac, ensure that the Docker engine is running. If you are on Linux, then prefix your Docker commands with sudo. Alternatively, you can create a user group to get rid of this problem.

The pull command fetches the BusyBox image from the Docker registry and saves it on our system. You can use the docker images command to see a list of all images on your system.

docker images

This gives output similar to:

busybox    latest  c51f86c28340  4 weeks ago  1.109 MB

Docker Run

Now, let's run a Docker container based on this image. To do that, we will use the all-powerful docker run command.

docker run busybox

Nothing happened? Yes, behind the scenes, a lot happened. When you call run, the Docker client finds the image (BusyBox in this case), loads the container, and then runs a command in that container. When we ran dockerrunbusyboxdocker run busyboxdockerrunbusybox, we didn’t provide a command, so the container started, ran an empty command, and then exited. Let's vary the test a bit:

docker run busybox echo "hello from busybox"
hello from busybox

Great, we finally see some output. In this case, the Docker client dutifully ran the echo command in our BusyBox container and then shut it down. If you noticed, all that happened quite fast. Imagine booting up a virtual machine, running a command, and then killing it. Now you know why they say containers are fast! Okay, now it’s time to check out the docker ps command. The dockerpsdocker psdockerps command shows all containers that are currently running.

docker ps

Since no containers are running, we see a blank line. Let’s try a more useful variant:

docker ps -a
CONTAINER    ID IMAGE     COMMAND   CREATED         STATUS                     PORTS   NAMES
305297d7a235 busybox      "uptime"  11 minutes ago  Exited (0) 11 minutes ago          distracted_goldstine
ff0a5c3750b9 busybox      "sh"      12 minutes ago  Exited (0) 12 minutes ago          elated_ramanujan
14e5bd11d164 hello-world  "/hello"   2 minutes ago  Exited (0) 2 minutes ago           thirsty_euclid

So, what we see above is a list of all the containers we have run. Note that the STATUS column shows that these containers exited a few minutes ago.

You might be wondering if there's a way to run more than one command in a container. Let's try that now:

docker run -it busybox sh
# Dentro del contenedor
# ls
bin dev etc home proc root sys tmp usr var
# uptime
05:45:21 up 5:58, 0 users, load average: 0.00, 0.01, 0.04

Running the run command with the -it flags joins us to the interactive terminal within the container. Now we can execute as many commands in the container as we want. Take some time to run your favorite commands.

If you're feeling particularly adventurous, you can try rm−rf/binrm -rf /binrm−rf/bin in the container. Make sure to run this command within the container and not on your laptop/desktop. Doing so will render other commands like ls, uptime unusable. Once everything stops working, you can exit the container (type exit and press Enter) and then start it again with the command dockerrun−itbusyboxshdocker run -it busybox shdockerrun−itbusyboxsh. Since Docker creates a new container each time, everything should start working again, hence containers are volatile.

The dockerrundocker rundockerrun command, which you'll likely use most frequently, makes sense to spend some time getting comfortable with. For more information about run, use docker run –help to see a list of all the flags it supports. As we progress, we'll look at a few more variants of docker run.

However, before moving forward, let's quickly talk about removing containers. We saw above that we can still see the remnants of the container even after exiting by running dockerps−adocker ps -adockerps−a. Throughout this tutorial, you'll run dockerrundocker rundockerrun several times, and leaving stray containers lying around will consume disk space. Therefore, as a general rule, clean up containers once you're done with them. To do that, you can run the docker rm command. Simply copy the container IDs from above and paste them along with the command.

docker rm 305297d7a235 ff0a5c3750b9 305297d7a235 ff0a5c3750b9

When deleting, you should see repeated IDs. If you have to delete a bunch of containers at once, copying and pasting IDs can be tedious. In that case, you can simply run:

docker rm $(docker ps -a -q -f status=exited)

This command removes all containers that have a status of exited. In case you're wondering, the -q flag only returns the numeric IDs, and the output of the -f filters according to the provided conditions. One last thing that will be useful is the –rm flag that can be passed to dockerrundocker rundockerrun which automatically removes the container once you exit it.

In later versions of Docker, the docker container prune command can be used to achieve the same effect.

docker container prune
WARNING! This will remove all stopped containers. Are you sure you want to continue ? \[y/N\]
# y Deleted Containers:
Total reclaimed space: 212 B

Finally, you can also delete images you no longer need by running docker rmi.

Terminology in Docker

In the last section, we used a lot of Docker-specific jargon that might be confusing for some. So, before we continue, let me clarify some terminology that is frequently used in the Docker ecosystem.

  • Images: Snapshots of our application ready to run that form the basis of containers. In the previous demonstration, we used the dockerpulldocker pulldockerpull command to download the busybox image.
  • Containers: Created from Docker images and run the actual application. We create a container with dockerrundocker rundockerrun, which we did with the busybox image we downloaded. You can see a list of running containers with the dockerpsdocker psdockerps command.
  • Docker Daemon: The background service running on the host that manages the building, running, and distribution of Docker containers. The daemon is the process that runs on the operating system that clients talk to.
  • Docker Client: The command-line tool that allows the user to interact with the daemon. In broader terms, there can also be other client forms, like Kitematic, which provide a GUI to users.
  • Docker Hub: A registry of Docker images. You can think of the registry as a directory of all available Docker images. If needed, one can host their own Docker registries and can use them to pull images.

Webapps with Docker

Great! So now we've seen dockerrundocker rundockerrun, played with a Docker container, and also learned some terminology. Armed with all this knowledge, we're now ready to get to the real deal, i.e., deploying web applications with Docker.

Static Sites

Let's start by taking baby steps. The first thing we'll look at is how we can run a very simple static website. We'll pull a Docker image from Docker Hub, run the container, and see how easy it is to run a web server.

Let's get started. The image we're going to use is a single-page website that we've already created for the purpose of this demonstration and hosted on the registry: arteco/static-app. We can download and run the image directly in one go using docker run. As noted earlier, the --rm flag automatically removes the container when it exits.

docker run --rm arteco/static-app

Since the image doesn't exist locally, the client will first look for the image in the registry and then run it. If all goes well, you should see the "Nginx is running…" message in your terminal. Alright, now that the server is running, how do we view the website? What port is it running on? And more importantly, how do we access the container directly from our host machine? Press Ctrl + C to stop the container.

Well, in this case, the client isn't exposing any ports, so we need to re-run the docker run command to publish ports. While we're at it, we should also find a way to detach our terminal from the running container. That way, you can happily close your terminal and keep the container running. This is called detached mode.

docker run -d -P --name static-app arteco/static-app

In the previous command, -d will detach our terminal, -P will publish all exposed ports to random ports, and finally --name corresponds to the name we want to give. Now we can view the ports by running the command docker port [CONTAINER]

docker port static-app
80/tcp ->

You can open http://localhost:32768 in your browser.

Note: If you are using docker-toolbox, then you may need to use docker-machine ip default to get the IP.

You can also specify a custom port to which the client will forward connections to the container.

docker run -p 8888:80 arteco/static-app
Nginx is running...

To stop a detached container, run docker stop followed by the container ID. In this case, we can use the name static-app that we used to start the container.

docker stop static-app

I'm sure you'll agree that it was super simple. To deploy this on a real server, you'll only need to install Docker and run the above Docker command. Now that you've seen how to run a web server inside a Docker image, you might be wondering: how do I create my own Docker image? This is the question we'll explore in the next section.

Docker Images

We've seen images before, but in this section, we'll delve deeper into what Docker images are and create our own image. Finally, we'll also use that image to run our application locally and then deploy it to Docker Hub to share it with our friends. Excited? Great! Let's get started.

Docker images are the building blocks of containers. In the previous example, we pulled the Busybox image from the registry and instructed the Docker client to run a container based on that image. To see the list of images that are available locally, use the command docker images.

docker images
arteco/static-app       latest  b270625a1631  21 hours ago  133.9 MB
busybox                 latest  c51f86c28340   9 weeks ago  1.109 MB
hello-world             latest  0a6ba66e537a  11 weeks ago  960 B

The above provides a list of images pulled from the registry, along with ones we've created (we'll see how shortly). The TAG refers to a particular snapshot of the image, and the IMAGE ID is the corresponding unique identifier for that image.

To simplify, you can think of an image similar to a git repository: images can be committed with changes and have multiple versions. If you don't provide a specific version number, the client defaults to the latest. For example, you can pull a specific version of the Ubuntu image:

docker pull ubuntu:18.04

To get a new Docker image, you can fetch it from a registry (like Docker Hub) or create your own. There are tens of thousands of images available on Docker Hub. You can also search for images directly from the command line using docker search.

An important distinction to note when it comes to images is the difference between base images and child images.

  • Base images are images that have no parent image, typically images with an operating system like Ubuntu, Busybox, or Debian.
  • Child images are images built on top of base images and add additional functionality.

Then there are official and user images, which can be both base and child images.

  • Official images are images maintained and officially backed by Docker. These are typically a single word long. In the list of images above, the Python, Ubuntu, Busybox, and Hello-world images are official images.
  • User images are images created and shared by users like you and me. They are built on base images and add additional functionality. These are usually formatted as username/image-name.

How to Create an Image

Now that we have a better understanding of images, it's time to create our own. Our goal in this section will be to create an image that hosts a simple Flask application. For the purposes of this workshop, I have already created a small application with Python Flask that displays dynamically served HTML text. If you haven't already, go ahead and clone the repository locally like this:

git clone https://github.com/arteco/docker-tutorial.git
cd docker-tutorial

This should be cloned on the machine where you are running Docker commands and not inside a Docker container.

The next step now is to create an image with this web application. As mentioned earlier, all user images are based on a base image. Since our application is written in Python, the base image we'll use will be Python 3.

What is a Dockerfile

A Dockerfile is a simple text file that contains a list of commands that the Docker client calls while creating an image. It's a straightforward way to automate the image creation process. The best part is that the commands you write in a Dockerfile are almost identical to their equivalent Linux commands. This means you really don't have to learn a new syntax to create your own Dockerfiles.

The application directory contains a Dockerfile, but since we're doing it for the first time, we'll create one from scratch. To begin, create a new blank file in your favorite text editor and save it in the same folder as the application with the name Dockerfile.

We start by specifying our base image. Use the FROM keyword to do that:

FROM python: 3

The next step is usually to write the commands to copy the files and install the dependencies. First, we set a working directory and then copy all the files from our application.

#set a directory for the app
WORKDIR  /usr/src/app
# copy all the files to the container
COPY  . .

Now that we have the files, we can install the dependencies.

RUN pip install --no-cache-dir -r requirements.txt

The next thing we need to specify is the port number that should be exposed. Since our Flask application runs on port 5000, that's what we'll indicate.


The last step is to write the command to run the application, which is simply: python ./app.py. We use the CMD command to do that:

CMD  [ "python", "./app.py" ]

The main purpose of CMD is to tell the container what command it should execute when it starts. With that, our Dockerfile is ready. Here's how it looks:

FROM python: 3
# set a directory for the app
WORKDIR  /usr/src/app
# copy all the files to the container
COPY  . .
# install dependencies RUN  pip install --no-cache-dir -r requirements.txt
# tell the port number the container should expose
# run the command
CMD  [ "python", "./app.py" ]

Now that we have our Dockerfile, we can build our image. The docker build command does the heavy lifting of creating a Docker image from a Dockerfile.

The next section shows the result of running the same. Before running the command yourself (don't forget the dot), make sure to replace my username with yours. This username should be the same as the one you created when signing up for Docker Hub. If you haven't done so already, go ahead and create an account. The docker build command is pretty straightforward: it takes an optional tag name with -t and a directory location containing the Dockerfile.

docker build -t yourusername/flask-app .
Sending build context to Docker daemon 8.704 kB
Step 1 : FROM python:3 # Executing 3 build triggers...
Step 1 : COPY requirements.txt /usr/src/app/ ---> Using cache
Step 1 : RUN pip install --no-cache-dir -r requirements.txt ---> Using cache
Step 1 : COPY . /usr/src/app ---> 1d61f639ef9e Removing intermediate container 4de6ddf5528c
Step 2 : EXPOSE 5000 ---> Running in 12cfcf6d67ee ---> f423c2f179d1 Removing intermediate container 12cfcf6d67ee
Step 3 : CMD python ./app.py ---> Running in f01401a5ace9 ---> 13e87ed1fbc2 Removing intermediate container f01401a5ace9
Successfully built 13e87ed1fbc2

If you don't have the python:3 image, the client will first pull the image and then build your image. Therefore, your output from running the command will look different from mine. If everything went well, your image should be ready! Run docker images and see if your image is listed.

The last step in this section is to run the image and see if it actually works (replacing my username with yours).

docker run -p 8888:5000 yourusername/flask-app
* Running on (Press CTRL+C to quit)

The command we just executed used port 5000 for the server inside the container and exposed it externally on port 8888. Go to the URL with port 8888, where your application should be live.

Congratulations! You have successfully created your first Docker image.

Publishing an Image

There are many different Docker registries you can use (you can even host your own). For now, let's use Docker Hub to publish the image. To publish, simply type:

docker push yourusername/flask-app

If this is the first time you're pushing an image, the client will prompt you to log in. Provide the same credentials you used to log in to Docker Hub.

docker login Username: yourusername
WARNING: login credentials saved in /Users/yourusername/.docker/config.json
Index Succeeded

Remember to replace the image tag name above with yours. It's important to have the format of username/image_name for the client to know where to publish.

Once this is done, you can see your image on Docker Hub. For example, here is the webpage for my image.

Note: One thing we'd like to clarify before moving forward is that it's not mandatory to host your image on a public registry (or any registry). In case you're coding for the next million-dollar unicorn startup, you might totally skip this step. The reason we're publicizing our images is that it makes deployment very simple by skipping some intermediate setup steps.

Now that your image is online, anyone with Docker installed can play with your application by typing just one command.

docker run -p 8888:5000 yourusername/flask-app

If you've ever struggled to set up local development environments / share application setup in the past, you know just how amazing this sounds. That's why Docker is so cool!

Discover how Docker can simplify deploying your applications to the cloud. At Arteco Consulting we help you learn and master this powerful tool. Check out our Docker tutorial and start building and deploying your distributed applications easily!

Stay Connected


Stay up to date with the latest in technology and business! Subscribe to our newsletter and receive exclusive updates directly to your inbox.

Online Meeting

Don't miss the opportunity to explore new possibilities. Schedule an online meeting with us today and let's start building the future of your business together!

  • :)
  • :0
  • :D
  • ;)
  • :]