D   A   T   A   W   O   K





Creation: December 07 2017
Modified: April 10 2022

Docker Tutorial

Linux containers

Are virtualization machanism acting at the operating system level.

They can execute multiple and isolated Linux systems on the same machine (host) but they use the kernel of the host.

Containers are different from virtual machines that virtualize the full OS (the kernel) and, usually, even the hardware.

Allows the developers to have an environment that is reproducible and the same as the production environment.

Docker Concepts

Build: tools for creating containarized applications. The application is packaged together with dependencies and infrastructure. The result is a docker image.

Ship: an image shared on a docker registry (e.g. https://hub.docker.com)

Run: A docker container is a runtime running a representation of a docker image.

Architecture

Docker host: a machine running the "docker engine"

Docker client: program configured to talk with the engine.

The host checks whether the requested image is already chached on the machine, if not, it downloads from the central repository.

When a client runs a container, a new container is created running the specified image. Several containers can run the same image (analogy container/image ~ program/process).

Containers are executed on the docker host and the standard output is (eventually) redirected to the client.

A "docker image" is a read-only template. Containers are read-write.

An image consists of several layer (using union filesystem) combined into a single image file.

When an image is changed a new layer is built on top of the previous one. Only the new layer is eventually distributed.

Common layers are reused by several images

Modifications in a running container are not saved.

Golden rule

A container should run a single command/service.


Commands

The following are the core commands for the docker client.

Show cached images

$ docker images

Show installed images in the system with few informations

Image search

$ docker search <name>

Search on Docker Hub images with the specifed name. The search result shows:

Automated build

As soon as a commit is pushed on the corresponding git repository, the image is automatically rebuilt on Docker Hub

Image history

$ docker history <image>

Prints an image layers hystory.

Remove image

$ docker rmi <name>

Removes a downloaded image from the computer

Pull image

$ docker pull <name>:<tag>

Downloads (if not already pulled) the image with given name and tag. If no tag is specified then it assumest the "latest".

Comman layers already downloaded are not downloaded again.

Image run

$ docker run <name>

Runs the specified image in a container.

Option Purpose
-i Keep stdin open even if not attached
-t Allocate a pseudo-tty
-d Run container in background and print container ID
--name Assign a name to the container
--rm Automatically remove the container when it exits
-e Set environment variable
-P Publish all exposed ports to random ports on the host
-p Publish a container's port(s) to the specified host port
-m Limit the memory

The first time the images is downloaded (i.e. all its layers).

$ docker run hello-world

List containers

View running containers

$ docker ps [-a]

The -a option shows also terminated containers.

Stop, Restart and Attach a container

An exited container that keeps stdin active (e.g. ubuntu) can be restarted by specifying its container name. Once restarted you have to reattach to the container.

Get container name from the NAMES column: docker ps -a

$ docker stop <name>
$ docker restart <name>
$ docker attach <name>

Remove a container

Remove a stopped container from the containers list (ps -a)

$ docker rm <name>

Data Volumes

A special directory used by one or several containers.

Volumes are initialized when a container is created and they survive when containers are deleted.

$ docker run --name myvol -v /dir ubuntu

Creates a container with name "myvol" with a volume in the directory dir.

$ docker run -it --rm --volumes-from myvol ubuntu /bin/bash

Executes the ununtu bash in a container using the volumes of the container "myvol". What's written in the directory "/adirectory" will be persisted in the volume of the container "myvolume".

Executing several containers with the above commands to share files. The files are persistent as long as the container "myvol" is not removed.

Locate a volume

$ docker inspect myvolume

Returns a JSON description of the volume. The interesting part is "Source", telling the absolute path in our computer where the contents of the volume is stored. The source is under the "Mounts subtree.

Mount a local directory

-v <host-dir>:<container-dir>

If the local directory does not exist it will be created with root privileges.

Restart on crash

To restart a docker container when it crashes itself, use the restart policies provided by Docker itself.

$ docker run --restart always <image-name>

Networking

Port forwarding

-p <local-port>:<container-port>

If the container exposes "container-port", this will be visible from the host at port "local-port".


Dockerfile

Text file with instructions to create and build images according to the Dockerfile syntax.

For example what the used would run from the command line in a container, such as apt commands to install packages, creation of config files.

The build command uses thi sfile and executes the instructions to create an image.

At build time you pass a "context" that is used for creating the image:

In the Dockerfile you can access only the directories of the context (at build time). The context directory is processed recursively.

All its contents are sent to the Docker host for the build. Use a .dockerignore to exclude paths and thus increment build performance.

The paths in the Dockerfile are meant relative to the context ("/" is the root of the context).

Never specify "/" as the context you pass to the build! All your harddisk contents would be sent to the Docker host.

Core Dockerfile commands

FROM

First noncomment instruction in the Dockerfile. Specifies the Docker image to start from. All the following instructions are executed on the base image.

Example

FROM ubuntu

The command creates a "chain" of images with installed software (docker history <image>).

COPY

Copy moultiple source files from the context to the filesys of the container a the specified path

COPY .vimrc /home

ENV

Sets the environment variable

ENV HOSTNAME=test

RUN

Executes a command

RUN apt-get update

CMD

Commnad that is executed by default in a container from the image. If specified multiple times only the last CMD will be considered

CMD ["/bin/echo","hello world"]

Can be overridden from the command line if you specify a command after the image name in the docker run command (e.g. ubuntu /bin/bash).

EXPOSE

Informs the network ports that the container will listen on

EXPOSE 8093

Build

Given the following Dockerfile

FROM python
CMD ["python","--version"]

Enter the folder where the Dockerfile is stored.

$ docker build -t hello-python .

The name of the image to create is specified with -t option. The directory for the context is . (current directory).


Docker Hub

Social network to share docker images.

Login

$ docker login

To push an image

$ docker push <user-id>/<image-name>

Docker Compose

Compose is a tool for defining and running multi-container Docker applications. A YAML file is used to configure the application's services.

A single command is then used to create and start all the services defined in the configuration file.

Start services set on the background:

$ docker-compose up -d

Stop services set:

$ docker-compose down

Inspect and follow the started services log:

$ docker-compose logs -f

Inspect the services volumes:

$ docker-compose volumes

For more informations about compose refer to the official documentation here.


Tips'n Tricks

Image dependencies

To find dependent child images of a given image:

$ docker inspect \
    --format='{{.Id}} {{.Parent}}' \
    $(docker images --filter since=<PARENT-ID> --quiet) \
  | grep <PARENT-ID>

Reclaim unused space

Remove unused volumes:

$ docker system prune --volumes

Remove all unused images and volumes:

$ docker system prune --all

Docker root directory

To change the default (/var/lib/docker) docker root directory the beste way is to create/edit the config.json file in /etc/docker/config.json.

In particular it should contain the following entry:

{
    data-root: <FOLDER-PATH>
}

Proudly self-hosted on a cheap Raspberry Pi