Practical Docker For Beginners

    In this tutorial, we will get our feet wet with Docker. Before defining what Docker is, let's get started with a basic use case to understand why do we need Docker in the first place.

    I want to run some Linux terminal commands

    Let's say, we wanted to have access to a Linux terminal on our computer.

    The first thing comes to mind is utilizing a virtual machine, using for example VirtualBox. However, virtual machines require a lot of space, and we don't need a fancy GUI at all, since what we only need is a Linux terminal.

    We decided to use Docker for this goal. We want to have a docker container, which Ubuntu is running inside of it.

    Images, and Containers

    The bread and butter of Docker are images and containers. There is no way to use Docker properly, without understanding images and containers. So, it is crucial to grasp the differences between them.

    Now, I know the following might be abstract if you haven't used images and containers before. But, just focus to understand the relationship between image and containers. Once we understand this relationship, we will go practical.

    One analogy is from object-oriented programming. We can think of images as classes and containers as objects. We create a class, give methods, and properties to it, and finally spawn objects from that class. And then, we can use the object. So, in the same way, containers are derived from images. We can have multiple containers, derived from only one image.

    Another analogy is from building a house. No one starts to build a house, without a plan. More specifically, a blueprint. How many rooms, doors and windows we need, where to place them, etc.. which in this case refers to an image. With that blueprint(image) in hand, we can build a house(container), or houses as many as we wish. A house refers to a container.

    Installing Docker

    Now, after knowing the relationship between images and containers, we can install Docker Desktop. For Windows 10 Pro, Enterprise, and Education check this link. For Windows 10 Home, click this link. For MacOS, click here.

    After Docker Desktop is installed, let's run it. You will see a docker logo as a tray icon for windows, and on the top bar for Mac.  Now we should be able to run commands on a command line with docker. So, open a cmd or a terminal, and type your first Docker command:

    docker version

    You should see something similar to this:

    Client: Docker Engine - Community
     Azure integration  0.1.15
     Version:           19.03.12
     API version:       1.40
     Go version:        go1.13.10
     Git commit:        48a66213fe
     Built:             Mon Jun 22 15:41:33 2020
     OS/Arch:           darwin/amd64
     Experimental:      false
    
    Server: Docker Engine - Community
     Engine:
      Version:          19.03.12
      API version:      1.40 (minimum version 1.12)
      Go version:       go1.13.10
      Git commit:       48a66213fe
      Built:            Mon Jun 22 15:49:27 2020
      OS/Arch:          linux/amd64
      Experimental:     false
     containerd:
      Version:          v1.2.13
      GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
     runc:
      Version:          1.0.0-rc10
      GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
     docker-init:
      Version:          0.18.0
      GitCommit:        fec3683

    Pulling an image from DockerHub

    Now that we have our docker on the command line, we can go ahead and pull the Ubuntu image to our computer:

    docker pull ubuntu

    The expected result is like:

    Using default tag: latest
    latest: Pulling from library/ubuntu
    e6ca3592b144: Pull complete 
    534a5505201d: Pull complete 
    990916bd23bb: Pull complete 
    Digest: sha256:cbcf86d7781dbb3a6aa2bcea25403f6b0b443e20b9959165cf52d2cc9608e4b9
    Status: Downloaded newer image for ubuntu:latest
    docker.io/library/ubuntu:latest

    In case you are curious where the Ubuntu image was stored:

    We pulled it from DockerHub, which is a repository for images. Think of it as GitHub for docker images. You can go to DockerHub, search for Ubuntu in the search box, and the first one in the list is what we are looking for. Click that one, and you will see a bunch of information about that image, like versions of Ubuntu,  etc.

    For instance, you could pull an older version of Ubuntu like:

    docker pull ubuntu:trusty
    You can provide tags like "trusty" after a semicolon for more specific options.

    The options you specify after a semicolon are called tags.

    In the case of not providing any tags, it defaults to a tag called latest. So under the hood, we ran: docker pull ubuntu:latest

    Listing images on our computer

    After pulling the Ubuntu image, we should be able to see one image when we list our images on our computer:

    docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    ubuntu              latest              bb0eaf4eee00        6 days ago          72.9MB
    repository=ubuntu, size=72.9MB

    Creating a container from an image

    Alright. We have the blueprint(image), let's build a house(container). But before that, let's list our containers with ps:

    docker ps -a
    -a flag stands for "all", meaning running and not running containers. if omitted, will show only running containers.

    Yes, as expected we don't have any containers yet:

    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

    Let's create one!

    docker run ubuntu
    Mr. docker, create a container from this image please

    The container has been created, but there will be no output on the command line. We can verify our container by running docker ps -a . In the status column, we see the word, exited. So, our container has been created and exited immediately, since we didn't give any instructions to it.

    So this time, let's run it by giving instructions to it:

    docker run 
    docker run -it ubuntu /bin/bash

    What we told is:

    Mr. Docker, create a container from ubuntu image, and then run /bin/bash(which starts a new shell) command in this container.

    Also, keep stdin open (so I can enter commands), because I gave you -i flag.

    And lastly, allocate me a pseudo-tty(treat it like a terminal), because I gave you -t flag.

    Expected outcome:

    root@217e2fbc8254:/# 

    There you have it. We have achieved our goal. We have an Ubuntu running container. We have access to its terminal.

    Let's exit this shell and list our containers, docker ps -a

    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
    217e2fbc8254        ubuntu              "/bin/bash"         14 minutes ago      Exited (127) 49 seconds ago                       suspicious_shannon

    You can remove the container by running docker rm container_id(217e2fbc8254) or container_name(suspicious_shannon)

    docker rm suspicious_shannon

    Conclusion

    Docker is more than playing around in a shell. We can do more complex and useful things with docker.

    With docker, we have a full environment(operating system) for our specific needs. And it's fast to spin it up. We could run our application in a container. Containers also allow us to deploy our application easily since the environment doesn't change between local and remote. One other advantage would be to join a project easily.  We wouldn't need to configure our computer for the project.

    Alican Donmez

    Alican Donmez

    Read more posts by this author.

    Practical Docker For Beginners