Container

Docker
The Basics

Now that we have covered the basic history and technology of containers, we want leverage some of those concepts in this lab. First we need to understand the concept of Docker Hub.

Docker Hub

Docker Hub is the repository in which Docker users can create, test, store and distribute container images amongst each other. Docker Hub can be leveraged in the cloud, but many companies host their own local Docker Hub repository.

Click Docker Hub in a browser window. In the top portion of the window is the search bar. Enter ubuntu. In the search results you will find a result like this:

When you click on details you will get a description page that covers various information points and examples of the Docker container. On the top right you will see a window with the docker pull command (We will explain this soon).

One of the key concepts to understand is the concept of tags. For example, in the case of ubuntu it can be called in various ways. In the top of the page there is a tab called Tags.

If you click on this you will see a list. These tag names can be invoked individually to request a more specific version of the container. These are used in many ways. In the description section it stipulates that for ubuntu:

  • The ubuntu:latest tag points to the "latest LTS", since that's the version recommended for general use.
  • The ubuntu:rolling tag points to the latest release (regardless of LTS status).

As best practice it isn't recommended to just pull a container without a tag. As in this case you are gambling as to what release exactly your application will be using as a base operating system. And that in itself could lead to failures if changes happen in the cloud. To avoid this condition it is recommended to always be specific. Let's look at the ubuntu 16.04 as an example. The release name is xenial.

  • 16.04
  • xenial
  • xenial-20180228
  • xenial-20180123
  • xenial-20180112.1
  • xenial-20171201

As you can see, there are various releases. Users always want to make sure they select the right build for their project. The idea behind this verification is to make sure the user has the correct version of the container. This comes into play because a user may need a specific version of the container.

Let's now pull a specific version of ubuntu to play with. We just want to pull the latest 16.04 release container.

Step 1 - Download Ubuntu container image


docker pull ubuntu:16.04

You should see an output as follows:

16.04: Pulling from library/ubuntu
22dc81ace0ea: Pull complete
1a8b3c87dba3: Pull complete
91390a1c435a: Pull complete
07844b14977e: Pull complete
b78396653dae: Pull complete
Digest: sha256:e348fbbea0e0a0e73ab0370de151e7800684445c509d46195aef73e090a49bd6
Status: Downloaded newer image for ubuntu:16.04

To see the downloaded container in your local file store, issue the following command:


docker images

[root@pod09-master ~]# docker images
REPOSITORY  TAG     IMAGE ID        CREATED     SIZE
ubuntu      16.04   f975c5035748    10 days ago 124MB

For every Docker image you download, the Docker client will tag it with an image id. This is what you will have to use to manipulate that image.

As we discussed containers can be hosted in either cloud or private locations. Many people simply use a container from one of the public container registries like Docker Hub. The error many people make is to start with containers that are based on known distributions. These can lead to fat containers that are a drag on your plans for a streamlined private cloud.

There are a variety of stripped down linux distribution containers that have a bare minimum install. One of these distributions is Alpine Linux. The smallest available Alpine Linux distribution starts at a couple of megabytes in size.

Understanding Container Layered Filesystem

When you downloaded the Ubuntu image before, it had output similar to the following:

16.04: Pulling from library/ubuntu
0a01a72a686c: Pull complete 
cc899a5544da: Pull complete 
19197c550755: Pull complete 
716d454e56b6: Pull complete 
Digest: sha256:3f3ee50cb89bc12028bab7d1e187ae57f12b957135b91648702e835c37c6c971
Status: Downloaded newer image for ubuntu:16.04
docker.io/library/ubuntu:16.04

Each of the lines that end with Pull Complete are layers of the container that you downloaded.

The docker history command provides the details of what each of these various layers consist of. To get this first issue the command docker images.


docker images

The output contains the images that have been downloaded, one that you pulled and one that was downloaded when you issued the docker run command.

[root@pod09-master ~]# docker images
REPOSITORY      TAG     IMAGE ID        CREATED     SIZE
ubuntu          latest  96da9143fb18    10 days ago 124MB

Copy the docker image ID from the downloaded ubuntu image and then use this ID for the docker history command. Below is the sample to follow:

[root@pod09-master ~]# docker history 96da9143fb18


IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
96da9143fb18        10 days ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
<missing>           10 days ago         /bin/sh -c mkdir -p /run/systemd && echo 'do…   7B                  
<missing>           10 days ago         /bin/sh -c set -xe   && echo '#!/bin/sh' > /…   745B                
<missing>           10 days ago         /bin/sh -c rm -rf /var/lib/apt/lists/*          0B                  
<missing>           10 days ago         /bin/sh -c #(nop) ADD file:4b2eb5cd0b37ca015…   124MB               

The important reason to understand this step is because it gives you an idea on the efficiency of the container in a host. If your application needs hundreds of containers that are based on the same image, then only the difference of that R/W layer created when the container was built counts towards the incremental storage on the compute resource.

In this example, the base image is 112MB in size. The three combined containers that are depicted in the diagram would mean that the three containers in this host are consuming a total of 220MB (112 + 87 + 9 + 12 ).

If these were micro-services utilizing virtual machines then at best you would start with 112MB * 3 plus (87 + 9 + 12 ) or 444MB. If you consider a hefty compute resource that could run hundreds of containers, you can start to understand the advantage of containerized micro-services.

Step 2 - Start Ubuntu container

The first exercise you will do is to start a very small alpine container from docker hub.


docker run -d -t -i --rm -h=ubuntu-ciscolive --name ubuntu-ciscolive ubuntu:16.04

To explain we have provided these parameters:

  1. -d

    Detached mode

  2. -i

    Interactive mode

  3. -t

    Allocate a pseudo tty. If you don't allocate a pseudo tty then when the container principal process starts ( bash ) it would not have a way to get input and fails causing the container to stop.

  4. -h

    This provides the hostname for the container

  5. --rm

    Upon termination of process or stopping of container, delete the container.

  6. --name

    Provide a name to be able to manage container without having to use the identifier.

After running this command you will be returned to your prompt. Now you can see the container that is running.


docker ps -a

The output should be similar to the following with different container ID.

[root@pod09-master ~]# docker ps -a
CONTAINER ID    IMAGE           COMMAND         CREATED         STATUS          PORTS   NAMES
62ef904844b6    ubuntu:16.04    "/bin/bash"     7 seconds ago   Up 6 seconds            ubuntu-ciscolive

Step 3 - Attach to container

Now that you have a working container you can attach to the container itself.


docker attach ubuntu-ciscolive

Once inside the container execute the command ps -ef. You should only see two processes. The ps process and the actual bash shell.


ps -ef 

root@ubuntu-ciscolive:/# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 13:50 pts/0 00:00:00 /bin/bash
root 9 1 0 14:00 pts/0 00:00:00 ps -ef

Now exit the container.


exit

At this point the container will be exited and removed ( deleted ) from the system because of the --rm parameter. As a reference, you can exit an active detached container easily without stopping the container with the sequence CTRL + p and CTRL + q. In the previous set using the exit command kills the bash shell causing the container to terminate.

You can verify that the container has been deleted, by executing the docker ps -a command as previously shown.