Getting Started with Docker

In this chapter, we are going to learn about docker shell, the command line utility and how to use it to launch containers. We will also learn what it means to run a container, its lifecycle and perform basic operations such as creating, starting, stopping, removing, pausing containers and checking the status etc.

Using docker cli

We can use docker cli to interact with docker daemon. Various functions of docker command is given below. Try this yourself by runnig $sudo docker command

docker

[Output]

Usage: docker [OPTIONS] COMMAND [arg...]
       docker [ --help | -v | --version ]

A self-sufficient runtime for containers.

Options:

  --config=~/.docker              Location of client config files
  -D, --debug                     Enable debug mode
  -H, --host=[]                   Daemon socket(s) to connect to
  -h, --help                      Print usage
  -l, --log-level=info            Set the logging level
  --tls                           Use TLS; implied by --tlsverify
  --tlscacert=~/.docker/ca.pem    Trust certs signed only by this CA
  --tlscert=~/.docker/cert.pem    Path to TLS certificate file
  --tlskey=~/.docker/key.pem      Path to TLS key file
  --tlsverify                     Use TLS and verify the remote
  -v, --version                   Print version information and quit

Commands:
    attach    Attach to a running container
    build     Build an image from a Dockerfile
    commit    Create a new image from a container's changes
    cp        Copy files/folders between a container and the local filesystem
    create    Create a new container
    diff      Inspect changes on a container's filesystem
    events    Get real time events from the server
    exec      Run a command in a running container
    export    Export a container's filesystem as a tar archive
    history   Show the history of an image
    images    List images
    import    Import the contents from a tarball to create a filesystem image
    info      Display system-wide information
    inspect   Return low-level information on a container, image or task
    kill      Kill one or more running containers
    load      Load an image from a tar archive or STDIN
    login     Log in to a Docker registry.
    logout    Log out from a Docker registry.
    logs      Fetch the logs of a container
    network   Manage Docker networks
    node      Manage Docker Swarm nodes
    pause     Pause all processes within one or more containers
    port      List port mappings or a specific mapping for the container
    ps        List containers
    pull      Pull an image or a repository from a registry
    push      Push an image or a repository to a registry
    rename    Rename a container
    restart   Restart a container
    rm        Remove one or more containers
    rmi       Remove one or more images
    run       Run a command in a new container
    save      Save one or more images to a tar archive (streamed to STDOUT by default)
    search    Search the Docker Hub for images
    service   Manage Docker services
    start     Start one or more stopped containers
    stats     Display a live stream of container(s) resource usage statistics
    stop      Stop one or more running containers
    swarm     Manage Docker Swarm
    tag       Tag an image into a repository
    top       Display the running processes of a container
    unpause   Unpause all processes within one or more containers
    update    Update configuration of one or more containers
    version   Show the Docker version information
    volume    Manage Docker volumes
    wait      Block until a container stops, then print its exit code

Getting Information about Docker Setup

We can get the information about our Docker setup in several ways. Namely,

docker -v  

docker version  

docker system info

[Output of docker -v]

Docker version 18.03.1-ce, build 9ee9f40

[Output of docker version]

Client:
 Version:      18.03.1-ce
 API version:  1.37
 Go version:   go1.9.5
 Git commit:   9ee9f40
 Built:        Thu Apr 26 07:18:46 2018
 OS/Arch:      linux/amd64
 Experimental: false
 Orchestrator: swarm

Server:
 Engine:
  Version:      18.03.1-ce
  API version:  1.37 (minimum version 1.12)
  Go version:   go1.9.5
  Git commit:   9ee9f40
  Built:        Thu Apr 26 07:16:59 2018
  OS/Arch:      linux/amd64
  Experimental: false

The docker system info command gives a lot of useful information like total number of containers and images along with information about host resource utilization etc.

Launching our first container

Now we have a basic understanding of docker command and sub commands, let us dive straight into launching our very first container

docker run alpine:3.4 uptime

Where, * we are using docker client to * run a application/command uptime using
* an image by name alpine:3.4

[Output]

Unable to find image 'alpine:3.4' locally
3.4: Pulling from library/alpine
81033e7c1d6a: Pull complete
Digest: sha256:2532609239f3a96fbc30670716d87c8861b8a1974564211325633ca093b11c0b
Status: Downloaded newer image for alpine:3.4

 15:24:34 up  7:36,  load average: 0.00, 0.03, 0.04

What happened?
This command will
* Pull the alpine image file from docker hub, a cloud registry * Create a runtime environment/ container with the above image
* Launch a program (called uptime) inside that container
* Stream that output to the terminal
* Stop the container once the program is exited

Where did my container go?

docker container  ps

docker container  ps -l

The point here to remember is that, when that executable stops running inside the container, the container itself will stop
This process will further be explained under the lifecycle of a container topic.

Let's see what happens when we run that command again,

[Output]

docker run alpine uptime
 07:48:06 up  3:15,  load average: 0.00, 0.00, 0.00

Now docker no longer pulls the image again from registry, because it has stored the image locally from the previous run
So once an image is pulled, we can make use of that image to create and run as many container as we want without the need of downloading the image again. However it has created a new instance of the iamge/container.

Checking Status of the containers

We have understood how docker run commands works. But what if you want to see list of running containers and history of containers that had run and exited? This can be done by executing the following commands

docker ps

[Output]

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

This command doesn't give us any information. Because, docker ps command will only show list of container(s) which are running

docker ps -l

[Output]

CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
988f4d90d604        alpine              "uptime"            About a minute ago   Exited (0) About a minute ago                       fervent_hypatia

the -l flag shows the last run container along with other details like image it used, command it executed, return code of that command, etc.,

docker ps -n 2

[Output]

NAMES
988f4d90d604        alpine              "uptime"            About a minute ago   Exited (0) About a minute ago                       fervent_hypatia
acea3023dca4        alpine              "uptime"            3 minutes ago        Exited (0) 3 minutes ago                            mad_darwin

Docker gives us the flexibility to show the desirable number of last run containers. This can be achieved by using -n #no_of_results flag

docker ps -a

[Output]

CONTAINER ID        IMAGE                        COMMAND                  CREATED              STATUS                          PORTS                  NAMES
988f4d90d604        alpine                       "uptime"                 About a minute ago   Exited (0) About a minute ago                          fervent_hypatia
acea3023dca4        alpine                       "uptime"                 4 minutes ago        Exited (0) 4 minutes ago                               mad_darwin
60ffa94e69ec        ubuntu:14.04.3               "bash"                   27 hours ago         Exited (0) 26 hours ago                                infallible_meninsky
dd75c04e7d2b        schoolofdevops/ghost:0.3.1   "/entrypoint.sh npm s"   4 days ago           Exited (0) 3 days ago                                  kickass_bardeen
c082972f66d6        schoolofdevops/ghost:0.3.1   "/entrypoint.sh npm s"   4 days ago           Exited (0) 3 days ago           0.0.0.0:80->2368/tcp   sodcblog

This command will show all the container we have run so far.

Running Containers in Interactive Mode

We can interact with docker containers by giving -it flags at the run time. These flags stand for
* i - Interactive
* t - tty

docker run -it alpine sh

[Output]

Unable to find image 'alpine:latest' locally
latest: Pulling from library/alpine
ff3a5c916c92: Already exists
Digest: sha256:7df6db5aa61ae9480f52f0b3a06a140ab98d427f86d8d5de0bedab9b8df6b1c0
Status: Downloaded newer image for alpine:latest
/ #

As you see, we have landed straight into sh shell of that container. This is the result of using -it flags and mentioning that container to run the sh shell. Don't try to exit that container yet. We have to execute some other commands in it to understand the next topic

Namespaced:

Like a full fledged OS, Docker container has its own namespaces
This enables Docker container to isolate itself from the host as well as other containers

Run the following commands and see that alpine container has its own namespaces and not inheriting much from host OS

[Command]

cat /etc/issue

[Output]

Welcome to Alpine Linux 3.4
Kernel \r on an \m (\l)

[Command]

ps aux

[Output]

PID   USER     TIME   COMMAND
    1 root       0:00 sh
    6 root       0:00 ps aux

[Command]

ifconfig

[Output]

eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2%32640/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1%32640/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

[Command]

hostname

[Output]

ae84d253ecb5

Shared:
We have understood that containers have their own namespaces. But will they share something to some extent? the answer is YES. Let's run the following commands on both the container and the host machine

[Command]

uname -a

[Output - container]

Linux ae84d253ecb5 3.10.0-327.28.3.el7.x86_64 #1 SMP Thu Aug 18 19:05:49 UTC 2016 x86_64 Linux

[Output - hostmachine]

Linux dockerserver 3.10.0-327.28.3.el7.x86_64 #1 SMP Thu Aug 18 19:05:49 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

As you can see, the container uses the same Linux Kernel from the host machine. Just like uname command, the following commands share the same information as well. In order to avoid repetition, we will see the output of container alone.

[Command]

date  

[Output]

Wed Sep 14 18:21:25 UTC 2016

[Command]

cat /proc/cpuinfo

[Output]

processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 94
model name      : Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
stepping        : 3
cpu MHz         : 2592.002
cache size      : 6144 KB
physical id     : 0
siblings        : 1
core id         : 0
cpu cores       : 1
apicid          : 0
initial apicid  : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 22
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc pni pclmulqdq monitor ssse3 cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx rdrand hypervisor lahf_lm abm 3dnowprefetch rdseed clflushopt
bogomips        : 5184.00
clflush size    : 64
cache_alignment : 64
address sizes   : 39 bits physical, 48 bits virtual
power management:

[Command]

free

[Output]

total       used       free     shared    buffers     cached
Mem:       1884176     650660    1233516          0       1860     473248
-/+ buffers/cache:     175552    1708624
Swap:      1048572          0    1048572

Now exit out of that container by running exit or by pressing ctrl+d

Making Containers Persist

Running Containers in Detached Mode

So far, we have run the containers interactively. But this is not always the case. Sometimes you may want to start a container without interacting with it. This can be achieved by using "detached mode" (-d) flag. Hence the container will launch the deafault application inside and run in the background. This saves a lot of time, we don't have to wait till the applications launches successfully. It will happen behind the screen. Let us run the following command to see this in action

[Command]

docker run -idt schoolofdevops/loop program

-d , --detach : detached mode

[Output]

2533adf280ac4838b446e4ee1151f52793e6ac499d2e631b2c752459bb18ad5f

This will run the container in detached mode. We are only given with full container id as the output

Let us check whether this container is running or not
[Command]

docker ps

[Output]

CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS              PORTS               NAMES
2533adf280ac        schoolofdevops/loop   "program"           37 seconds ago      Up 36 seconds                           prickly_bose

As we can see in the output, the container is running in the background

Checking Logs

To check the logs, find out the container id/name and run the following commands, replacing 08f0242aa61c with your container id

[Commands]

docker container ps

docker container logs 08f0242aa61c

docker container logs -f  08f0242aa61c

Connecting to running container to execute commands

We can connect to the containers which are running in detached mode by using these following commands
[Command]

docker exec -it 2533adf280ac sh

[Output]

/ #

You could try running any commands on the shell e.g.

apk update
apk add vim
ps aux

Now exit the container.

Pausing Running Container

Just like in a video, it is easy to pause and unpause the running container
[Command]

docker pause 2533adf280ac

After running pause command, run docker ps again to check the container status

[Output]

CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS                  PORTS               NAMES
2533adf280ac        schoolofdevops/loop   "program"           2 minutes ago       Up 2 minutes (Paused)                       prickly_bose

Unpausing the paused container

This can be achieved by executing following command

[Command]

docker unpause

Run docker ps to verify the changes

[Output]

CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS              PORTS               NAMES
2533adf280ac        schoolofdevops/loop   "program"           6 minutes ago       Up 6 minutes                            prickly_bose

Creating and Starting a Container instead of Running

docker run command will create a container and start that container simultaneously. However docker gives you the granularity to create a container and not to run it at the time of creation. However, This container can be started by using start command

[Command]

docker create alpine:3.4 sh

Run docker ps -l to see the status of the container

[Output]

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
22146d15eb71        alpine:3.4          "sh"                31 seconds ago      Created                                 grave_leavitt

If you do docker ps -l, you will find that container status to be Created. Now lets start this container by executing,

[Command]

docker start 22146d15eb71

Run docker ps -l again to see the status change

[Output]

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
22146d15eb71        alpine:3.4          "sh"                3 minutes ago       Exited (0) 2 minutes ago                      grave_leavitt

This command will start the container and exit right away we have not specified interactive mode in the command

Creating Pretty Reports with Formatters

docker ps --format "{{.ID}}: {{.Status}}"

[Output]

2533adf280ac: Up 12 minutes

Checking disk utilisation by


docker system df

[output]

docker system df
TYPE                TOTAL               ACTIVE              SIZE                RECLAIMABLE
Images              7                   5                   1.031GB             914.5MB (88%)
Containers          8                   4                   27.97MB             27.73MB (99%)
Local Volumes       3                   2                   0B                  0B
Build Cache                                                 0B                  0B

To prune, you could possibly use

docker container prune

docker system prune

e.g.

docker system prune
WARNING! This will remove:
        - all stopped containers
        - all networks not used by at least one container
        - all dangling images
        - all build cache
Are you sure you want to continue? [y/N]

Make sure you understand what all will be removed before using this command.

Stopping and Removing Containers

We have learnt about interacting with a container, running a container, pausing and unpausing a container, creating and starting a container. But what if you want to stop the container or remove the container itself

Stop a container

A container can be stopped using stop command. This command will stop the application inside that container hence the container itself will be stopped. This command basically sends a SIGTERM signal to the container (graceful shutdown)

[Command]

docker stop 2533adf280ac

[Output]

2533adf280ac

Kill a container

This command will send SIGKILL signal and kills the container ungracefully

[Command]

docker kill 590e7060743a

[Output]

590e7060743a

If you want to remove a container, then execute the following command. Before running this command, run docker ps -a to see the list of pre run containers. Choose a container of your wish and then execute docker rm command. Then run docker ps -a again to check the removed container list or not

[Command]

docker rm 590e7060743a

[Output]

590e7060743a