Docker FAQ

This is a Docker tutorial written in a Frequently Asked Questions (FAQ) style.

Posted on July 23, 2016 by Ernesto Garbarino

Introduction

This text explains the basics of Docker using a Frequently Asked Questions (FAQ) approach.

Assumptions:

  1. The Docker version is 1.11
  2. The OS is Linux Mint Rosa 17.3 (Ubuntu derivative)
  3. The docker ... commands must be executed as root and it is up to the user to use sudo or log in is as root.

Docker Installation

How do you install Docker?

Step 1: First update the repository and add the necessary key:

sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

Step 2: Add the Docker repository:

sudo vim /etc/apt/sources.list.d/docker.list
i
deb https://apt.dockerproject.org/repo ubuntu-xenial main

Step 3: Install Docker using apt-get:

sudo apt-get update
apt-cache policy docker-engine
sudo apt-get install docker-engine

Step 4: Startup Docker and verify that it is up and running:

sudo service docker start
sudo docker run hello-world

Step 5: Adjust the firewall so that it doesn’t drop packets.

Open /etc/default/ufw, locate DEFAULT_FORWARD_POLICY="DROP" and change to "ACCEPT".

sudo vim /etc/default/ufw 
sudo ufw reload

How do you enable Docker at boot time?

sudo systemctl enable docker

How do you disable Docker at boot time?

sudo systemctl disable docker 

How do you stop/start/restart the Docker daemon?

Start:

systemctl enable docker

Stop:

systemctl stop docker

Restart:

systemctl restart docker

How do you check whether Docker is running?

Use sudo systemctl status docker or sudo docker info.

How do I configure the daemon’s startup properties?

Edit the file /lib/systemd/system/docker.service and then be sure to issue a sudo systemctl daemon-reload command so that the new configuration is loaded.

How do I bind the Docker daemon to a different interface?

By default, docker binds to a local Unix socket:

docker daemon -H unix:///var/run/docker.sock

We can change this using the --host or -H flag:

docker daemon -H tcp://192.168.1.23:5555

Multiple instances of the -H flag will result in the Docker daemon binding to multiple interfaces.

On the client side, the -H can be used to specify the daemon’s interface. Optionally, the DOCKER_HOST environment variable may be used too.

Launching and Managing Containers

What does it mean to “launch” a container?

Launching a container means selecting a Docker image and running a command inside of it.

How do you run a one-off command?

Use the docker run <image> <command> command. For example:

docker run ubuntu printenv

In the above case, the container will be stopped after the command printenv has produced its results.

How do you interact with a command?

Use the -i (interactive) flag when using the docker run command. For example:

docker run -i ubuntu passwd
Enter new UNIX password: perro
Retype new UNIX password: perro
passwd: password updated successfully

This -i flag leaves the container’s STDIN stream open.

How do you run full terminal capabilities?

If the command provided to run docker is bash, we normally want full terminal capabilities so that we can run text editors such as vim and have autocompletion capabilities on the command line.

In the described case, we use the -t (allocate pseudo-TTY) flag which may be combined with -i as -it:

docker run -it ubuntu bash
root@abe7f8978e4c:/# ps xa
  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 bash
    9 ?        R+     0:00 ps xa

How do you name a container?

Use the --name <container> flag. For example:

docker run --name gato_lindo ubuntu ls

How do you run a container as a daemon?

Use the -d flag. For example:

docker run --name gato_feo -d ubuntu /bin/sh -c "while true ; do echo -n The time is... ; date +%H:%M:%S ; sleep 1 ; done"

Please note that if the intention is to launch a container that stays up, it is not sufficient to specify the -d flag. The container must run a non-daemon, and non-terminating command so that it remains running. If the command goes in the background or it terminates, the container will be stopped.

How do you automatically restart a container if it fails?

The --restart flag restarts the container automatically based on the container’s running process exit code:

Flag Description
--restart=no Never restart: default.
--restart=always Ignore the exit code: always restart.
--restart=unless-stopped Ignore if it has been stopped before.
--restart=on-failure Only if non-zero exit code.
--restart=on-failure:3 Same as above but max 3 attempts.

How do you override the image’s startup command?

If the image defines the startup command by using the CMD declaration in the Dockerfile, it is just a matter of specifying the required command as the last argument to docker run.

However, an image may define an automatic command to be executed when a container is run via the ENTRYPOINT declaration. (see Dockerfile Configuration). To override this command, use the --entrypoint="<command>" flag.

For example:

docker run -ti --entrypoint="bash" apache_image

How do you launch the container inside a default directory?

Use the -w flag. For instance:

docker run -ti -w /etc/init.d ubuntu ls
README                  hwclock.sh             mountnfs.sh  sendsigs
bootmisc.sh             killprocs              ondemand     single
checkfs.sh              mountall-bootclean.sh  procps       skeleton
checkroot-bootclean.sh  mountall.sh            rc           umountfs
checkroot.sh            mountdevsubfs.sh       rc.local     umountnfs.sh
halt                    mountkernfs.sh         rcS          umountroot
hostname.sh             mountnfs-bootclean.sh  reboot       urandom

How do you specify a runtime environmental variable?

Use the -e flag. For instance:

docker run -ti -e "TERM=linux" ubuntu bash
root@dc6cf98ed6a6:/# echo $TERM
linux

How do you run a command inside a running container?

Use the docker exec <container> command which accepts similar flags as the docker run command.

For example, let’s suppose gato_feo is a running container.

To run a command and see its results, just specify the container name as opposed to the image name:

docker exec gato_feo ps -xa

If you are not interested in the results, you can run a command in the background, use the -d flag:

docker exec -d gato_feo rm /tmp/old.log

As in the case of run, you can also run full terminal capabilities using the -it flag:

docker exec -i -t gato_feo bash

How do I attach to a daemonised container?

A daemonised container will be normally be sending its STDOUT stream to the Docker logger. However, it is possible to attach directly to it using the docker attach command.

For example:

docker attach gato_lindo

Please note that docker attach is not the same as docker exec It simply connects the container’s parent (PID = 1) running process STDIN/STDOUT streams to the current terminal.

To detach without stopping the container, press CTRL+p, followed by CTRL+q.

How do you list the containers you have launched?

Use the docker ps command with different flags subject to how you want to filter the results.

Show running containers only: no flag.

docker ps

Show all containers regardless of whether they are running or not:

docker ps -a

Show the last container that was launched:

docker ps -l

Show the last n containers that were last launched:

docker ps -n 10

How do you remove a container?

You can remove a container by name or by id using the docker rm command. The flag -f (force) will kill the container before removing it.

Examples:

docker rm gato_lindo
docker rm 68685c007cf7
docker rm -f gato_feo

Monitoring and Controlling a Container

How to inspect the processes running inside a container?

You can use the docker top command to get a one-off word:

docker top gato_feo

But also, you can get real-time statistics using docker stats <container1> <container_n> ...:

docker stats gato_feo gato_lindo

How do you obtain all settings that apply to a container?

The docker inspect command provides a JSON document with in-depth details about a container regardless of whether it is stopped or running. It may inspect various containers at the same time.

docker inspect gato_feo
[
    {
        "Id": "22368529243bf94c9846c1ab4478fc2ae011d998c7bc5a30b74dbd492c99c759",
        "Created": "2016-07-01T15:51:09.578123484Z",
        "Path": "/bin/sh",
        "Args": [
            "-c",
            "while true ; do echo -n The time is... ; date +%H:%M:%S ; sleep 1 ; done"
        ],
        "State": {
            "Status": "exited",
            "Running": false,
            "Paused": false,
            "Restarting": false,
            "Dead": false,
            "Pid": 0,
            "ExitCode": 137,
            "Error": "",
            "StartedAt": "2016-07-01T16:40:48.534348845Z",
            "FinishedAt": "2016-07-01T16:49:07.678227024Z"
        },
        "Name": "/gato_feo",
        ...
     }
]        

How do you retrieve a container’s individual setting?

Individual fields can be selected using the --format flag. For example:

docker inspect --format='{{.State.Running}}' perro_feo
false
docker inspect --format='{{.Config.Image}}' perro_feo
ubuntu

Multiple fields may also be combined:

docker inspect --format='{{.Name}} {{.State.Running}}' perro_feo locuras
/perro_feo false
/locuras false

The shorter -f flag may be used as well:

docker inspect -f {{.State.Running}} perro_feo

How do you check a containers’ logs?

Checking a container’s log means checking its STDOUT and STDERR streams. Let’s assume a container named gato_feo.

See all log output:

docker logs gato_feo

See all log output and than follow changes:

docker logs -f gato_feo

See only the last 10 lines:

docker logs --tail 10 gato_feo

See only the last 10 lines and then follow changes:

docker logs -f --tail 10 gato_feo

Same as above but with a timestamp:

docker logs -ft --tail 10 gato_feo

How to change the log driver?

As of version 1.11, supported log drivers are:

Usage:

docker run --log-driver="syslog" ...

How do you start a stopped or newly created container?

docker start gato_feo

How do you stop a running container?

The docker stop command sends the SIGTERM signal to the container’s running process:

docker stop gato_feo

How do you kill a container by brute force?

The docker kill command, unlike docker stop, sends the SIGKILL signal to the container’s running process:

docker kill gato_feo

Images

How do you list locally available images?

Use the docker images command

How do you download an image from Docker Hub?

Use the docker pull <image>[:tag] command:

docker pull centos

How do you search for images?

Use the docker search <TERM> command:

docker search jenkins

Building Images

How do you build your own image?

Follow these steps:

  1. Create a directory to store our image’s configuration. E.g. mkdir myImage
  2. Create a myImage/Dockerfile file that describes the images’ properties
  3. Use the docker build -t="<image_name>" . to build the image

For example:

mkdir myImage
cd myImage
vim Dockerfile

Contents of Dockerfile:

FROM ubuntu:latest
RUN apt-get update
RUN apt-get -y install perl

Then run:

docker run perl_image perl -e '@scalar = "Hello" ; print @scalar'
docker run perl -e '$scalar = "Hello World\n" ; print $scalar'

How do you debug an image that fails to build?

Use the image’s name from the last successful step and run bash inside of it to check what went wrong.

For example:

...
Step 2: RUN apt-get update
  --> Running in 6f7d8a6fd7a5
  --> d7a8d6a7d8a7
Step 3: RUN apt-get install -y apachee
...
E: Unable to locate package apachee
2016/07/01 12:30 The command [/bin/sh -c apt-get install -ya apachee] 
returned a non-zero code: 100

The healthy image built before the error is d7a8d6a7d8a7:

docker run -t -i d7a8d6a7d8a7 bash

Once inside the image, you can type the problematic RUN command and check what went wrong.

How do you check what changes have been applied to an image?

Use the docker history command. For example:

docker history perl_image
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
da269a070c7e        About an hour ago   /bin/sh -c apt-get -y install perl              43.13 MB            
8ccd6d7bda0d        About an hour ago   /bin/sh -c apt-get update                       37.81 MB            
2fa927b5cdd3        5 weeks ago         /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B                 
<missing>           5 weeks ago         /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB            
<missing>           5 weeks ago         /bin/sh -c rm -rf /var/lib/apt/lists/*          0 B                 
<missing>           5 weeks ago         /bin/sh -c set -xe   && echo '#!/bin/sh' > /u   701 B               
<missing>           5 weeks ago         /bin/sh -c #(nop) ADD file:025ef672711f22be39   122 MB              

How do you pass arguments at build time?

Use the --build-arg flag. For instance:

docker build --build-arg=user="webuser" -t myImage .

Dockerfile Configuration

How do you get started?

You have to create a file named Dockerfile under a directory in which you will be building the image.

Inside Dockerfile, at least you normally have to specify the base image using the FROM image:tag declaration. For instance:

FROM ubuntu:16.04

How do you set up the base image?

Use the RUN command, which accepts two variations in syntax: a command wrapper and an array format:

  1. RUN <command> which is equivalent to /bin/sh -c <command>
  2. RUN [ "exe", " <arg1>", "<arg2>"] where arguments are optional

For example, to add vim to an ubuntu image:

FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y vim

How do you define an image’s environment variable?

Use the ENV <variable> <value> declaration.

Environmental variables can then be referred from within the Dockerfile by prefixing the variable with dollar. For example:

# Dockerfile
FROM ubuntu
ENV JAVA_HOME /opt/jdk
WORKDIR $JAVA_HOME

How do you expose a TCP port in an image?

Use the EXPOSE <port> declaration in the image’s Dockerfile. For example:

FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y apache2
EXPOSE 80

Note: The above example simply exposes port 80. It does not automatically map the port when it is deployed into a container.

How do you define the startup command?

The command supplied as the last argument of docker run may be defined using the CMD declaration. For example:

# Dockerfile
FROM ubuntu
CMD [ "/bin/bash", "--norc" ]

In this case, bash would be executed automatically when launching the container:

docker run -ti simple
bash-4.3#

However, the user may still specify a command as the last argument to docker run so that CMD gets ignored.

docker run -ti simple ls
bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
boot  etc  lib   media  opt  root  sbin  sys  usr

How do you define startup arguments?

If you want to execute a command when a container is launched but you want to have flexibility in terms of its arguments, you can use ENTRYPOINT [ "<command>" ] to define the command that should be executed when the container is run, and, optionally, the CMD [ "arg1","arg2",...] declaration to specify the command’s arguments.

For example:

ENTRYPOINT [ "/bin/bash" ]
CMD [ "--norc" ]

In the above case, docker run without a command argument will run /bin/bash --norc but the latter may be optionally overridden:

docker run -ti simple
bash-4.3# exit
exit
docker run -ti simple --version
GNU bash, version 4.3.42(1)-release (x86_64-pc-linux-gnu)
Check the **Running an Image** section to see how to
override these options when running a container	.

The ENTRYPOINT declaration may be overridden using the --entrypoint flag when using the docker run command. In the below example, both the ENTRYPOINT and the CMD declarations are being overridden:

docker run -ti --entrypoint="/bin/ls" simple -la
total 72
drwxr-xr-x  33 root root 4096 Jul  2 16:47 .
drwxr-xr-x  33 root root 4096 Jul  2 16:47 ..
-rwxr-xr-x   1 root root    0 Jul  2 16:47 .dockerenv
drwxr-xr-x   2 root root 4096 May 25 23:11 bin
drwxr-xr-x   2 root root 4096 Apr 12 20:14 boot
drwxr-xr-x   5 root root  380 Jul  2 16:47 dev
drwxr-xr-x  45 root root 4096 Jul  2 16:47 etc
...

How do you setup a working directory?

Rather than referring all commands using absolute paths, a default working directory may be defined using the WORKDIR declaration.

How do you copy files to the image?

Use the ADD <source> <destination> declaration, which supports various modes:

Copy file: In this case, <source> is a file within the build directory only. For example:

ADD config.xml /var/lib/app/config.xml

Fetch file from URL: In this case is a file that will be retrieved from an URL. For example:

ADD http://intranet/config.xml /var/lib/app/config.xml

Unpack archive file: In this case is an archive file such as .tar, .tar.gz, etc. For example:

ADD images.tar /var/www/images/

Alternatively, the COPY declaration may be used which will avoid any unpacking when dealing with archive files.

How do you add metadata?

Use the LABEL <variable>="<value>" declaration. For example:

LABEL release="1.2"

Multiple label may also appear in the same line. For example:

LABEL release="1.2" author="ernie" 

The labels can be extracted using the docker inspect command:

docker docker inspect -f {{.ContainerConfig.Labels}} gato_lindo
map[author:ernie release:1.2]
docker inspect -f {{.ContainerConfig.Labels.author}} gato_lindo 
ernie

How do you specify default build arguments?

Defaults for the --build-arg flag passed to the docker build command may be specified using the ARG <value> or ARG <name>=<value> declarations. For example:

ARG betaImage
ARG runAs=webuser

Volumes

What are volumes?

Volumes are Docker’s mechanism to writing and sharing persistent data (that survives stopping a container). All volumes have in common the fact that they appear as mount points inside the container. However, how (and to what object) the mount point is connected to the outside world may vary:

  1. A host’s directory: A regular UNIX path sitting within the host.

  2. A new volume: A new volume is created when the container is launched but it is not deleted when it is stopped unless special directives are provided.

  3. A volume registered by a container: When a new volume is created, in reality it is associated with the container’s name. Therefore, a second container may refer the volume created by a previous one. This way we stop creating brand new volumes every time which is not very useful anyway.

How do you mount a host’s directory?

Use the -v <host_path>:<mount_point> flag. For instance:

docker run -ti -v /tmp:/outsidetmp ubuntu bash
root@8883750fbf8b:/# ls -la | grep out
drwxrwxrwt  15 root root 4096 Jul  2 18:24 outsidetmp

Note: Hosts’ directories cannot be mounted using a Dockerfile declaration.

How do you create a new volume?

A new volume is creating using the -v <mount_point> flag when running the docker run command or by using the VOLUME <mount_point> declaration inside a Dockerfile.

For example:

docker run -ti -v /myvolume ubuntu bash
root@e9c53b0b5906:/# cd myvolume
root@e9c53b0b5906:/myvolume# echo "Hello My Volume" >> hello.txt
root@e9c53b0b5906:/myvolume# exit

Even though we have stopped the container by exiting it, we can still find the file:

find /var/lib/docker -name "hello.txt"
/var/lib/docker/volumes/a5620c14aae707/_data/hello.txt

Alternatively, you can also find out about the volume’s properties using the docker inspect command. For example:

docker inspect -f {{.Config.Volumes}} pipo

Please note that the volume id has been shortened for formatting

Networking

How do you find out which port a container is mapped to?

Use the docker port <container> command. For example:

docker port apache_container
80/tcp -> 0.0.0.0:32769

You may also specify a specific port number if there are many that are exposed:

# docker port apache_container 80
0.0.0.0:32769

How do you find out a container’s internal IP address?

docker inspect -f {{.NetworkSettings.Networks.bridge.IPAddress}} server
172.17.0.1

How do you connect two containers?

Containers that listen on a TCP port are, by default, available on the Docker’s bridge virtual network. For example, let’s suppose that we have a server that listens on port 8000 that is exposed and mapped to port 80 and a client that takes the server’s URL:

export SERVER_IP=`docker inspect -f {{.NetworkSettings.Networks.bridge.IPAddress}} server`
docker run --name client client_image $SERVER_IP:8000

As you can see, the exposed port (80) is irrelevant in the case of the client reaching the client via the Docker’s bridge.

However, what if we want the client container to talk to the regular host’s network interface? In this case we have to use the --net="host" flag when we invoke the client and use the mapped port instead. For example:

docker run --name client --net="host" client_image http://localhost:80