Marc Wäckerlin
Für eine libertäre Gesellschaft

Docker Overview

April 14, 2015

Visits: 3580

This article is for all those who are confused by the Docker concepts and who would like to have a short summary of the important things, instead of a widely distributed documentation.

Most Important Commands

Optional parts in [brackets]. For more commands, see docker help or docker help command.

Search Image with keyword on Registry
docker search [host[:port]/]keyword
Download Image from Registry
docker pull [host[:port]/][user-name/]image-name[:tag]
List all Local Images
docker images
List all Running Container
docker ps
List all Container
docker ps -a
Remove a Local Image
docker rmi image-name
Remove a Container
docker rm container-name
Stop a Running Container
docker stop container-name
docker pause container-name
Start a Stopped Container
docker start container-name
Open a Shell in a Running Container
docker exec -it container-name /bin/bash
Create a New (or Update) Image From Container
docker commit container-name [host[:port]/][user-name/]image-name[:tag]
Store New or Updated Image on Registry
docker push [host[:port]/][user-name/]image-name[:tag]
Remove an image from the own registry
curl -u 'username:password' -XDELETE
Create a New Image from an Existing Directory (e.g. created with bootstrap)
tar c . | docker import - [host[:port]/][user-name/]image-name[:tag]

Registry vs. Image vs. Container

Docker is based on an image registry, which is a virtual machine template image repository. It behaves similar to a git repository. You can have your own local registry on your own host (i.e. if your images contain secrets). An image is a template for a virtual machine instance. A container is a virtual machine and can be running or stopped. Starting an image with docker run always creates a new container, so don’t run twice, run once, then start and stop the container. A container can be seen as a persistent process.

Install Docker

On Ubuntu 16.04, package docker.io installs docker version 1.12, which is the first that supports docker swam, but still misses new features, such as docker config and docker secret. That’s why you better install from docker.com:

wget -qO- https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install docker-ce lxc-docker- docker-engine- docker.io-

To be able to run docker as non root user, add your username to group docker, then logout and login again, or simply run su - $(whoami) or ssh localhost, to get the new group (e.g. on Ubuntu):

sudo adduser $(whoami) docker

or (e.g. on OpenSUSE):

sudo usermod -aG docker $(whoami)

Search an Image on a Registry

Use docker search searchtext to find an image for «searchtext» in the public docker repository, or to search an apache image on your repository, e.g. on localhost port  5000, use docker search localhost:5000/apache.

Since I have an apache image in my repository on server dev0004, I receive:

> docker search dev0004:5000/apache
NAME                    DESCRIPTION   STARS     OFFICIAL   AUTOMATED
library/ubuntu-apache                 0

Pull an Image from a Registry

Before you can instanciate a container from an image, you need to pull it from the repository. E.g. pull the apache image from above:

docker pull dev0004:5000/library/ubuntu-apache

Run a Container from an Image

A docker image is an image template. To really instantiate a virtual machine from an image, use docker run. For all the parameters and settings, you need the image builders documentation. You should at least specify a name with --name, so that you can access the container by a well knoen name. Otherwise a name is generated. To make sure, the container keeps running and is restarted when it cashes, add the option --restart=always the program to start depends on the image. I created a file /

Start a Docker Container on Boot

To start a container service in Ubuntu 14.04, just create an upstart config file in /etc/init. When you run the container, you should give it a name with option --name and you shoud add option  --restart=always. E.g. for starting a docker container with a given name of «container-name», create a file /etc/init/container-name.conf that contains:

description "container name"
author "my name"
start on filesystem and started docker
stop on runlevel [!2345]
respawn
script
  /usr/bin/docker start -a container-name
end script

Run Your Own Registry

The simplest way to run your own registry is to run it in a docker instance, in this example, images should be stored in path /var/registry:

sudo mkdir /var/registry
sudo chown docker.docker /var/registry
sudo chmod g+w /var/registry
docker pull registry
docker run --name="docker_registry" --restart=always -e SETTINGS_FLAVOR=local -e STORAGE_PATH=/var/registry -e SEARCH_BACKEND=sqlalchemy -p 5000:5000 -v /var/registry:/var/registry registry

You can then access the repository on port 5000 of your host, e.g. localhost, so list all images:

wget -q -O- http://localhost:5000/v1/search; echo

Don’t forget to backup your Images in /var/registry.

Create Ubuntu and Apache Images from Scratch

Bootstrap an Ubuntu Utopic Unicorn

Go to a working directory, e.g. cd /tmp, then create a full installation of Ubuntu 14.10 Utopic Unicorn (which is the latest Ubuntu release at the time of writing) in subdirectory utopic:

mkdir utopic
sudo debootstrap utopic utopic

Create Docker Image from Directory

Now create a Docker image from the Ubuntu 14.10 Utopic Unicorn installation in subdirectory utopic, in my case, I’ll store the image on my own registry on host dev0004, port 5000 and give it the name library/ubuntu-utopic:

cd utopic
sudo tar c . | docker import - dev0004:5000/library/ubuntu-utopic

The image is now ready to be used locally, but not yet stored in my registry, so last step is to push it to my registry:

docker push dev0004:5000/library/ubuntu-utopic

Create New Image With Service Apache

Run a shell in a new container named apache-setup that runs the just created Ubuntu image:

docker run -it --name apache-setup dev0004:5000/library/ubuntu-utopic /bin/bash

Within this container, do all necessary configurations for a running Apache, in the easiest case, install apache2 and create a file /run.sh in the root, that starts Apache, then waits forever:

apt-get install apache2
cat > /run.sh <<EOF
#!/bin/bash
systemctl start apache2
sleep infinity
EOF
chmod +x /run.sh
exit

If you forgot a configuration step and need to go back to the stopped container, call:

docker start -i apache-setup

Create a new image from this container, again, it will be stored on my own registry on host dev0004, port 5000 and give it the name library/ubuntu-utopic-apache, then push the new image to the registry:

docker commit apache-setup dev0004:5000/library/ubuntu-utopic-apache
docker push dev0004:5000/library/ubuntu-utopic-apache

Now you can create a container from your Apache image. Just run the command /run.sh created above. Here I map port 80 (Apache) in the Docker container to port 9876 on the Host:

docker run -d --name test-apache -p 9876:80 dev0004:5000/library/ubuntu-utopic-apache /run.sh

If everything works, open your browser, head to http://localhost:9876 and you see the default apache page.
Image of Apache Default Page

Working with Dockerfile

Create Apache Image using Dockerfile

Alternatively to the above, it is possible to derive a new image from an existing image plus applying a docker file. For Dockerfile syntax details try man dockerfile. This way, you can do even more configurations, i.e. you can specify the program to run as ENTRYPOINT and you don’t need the /run.sh-script any more.

To generate an Ubuntu Utopic Unicorn Apache image, change to an empty directory and create a file Dockerfile in it:

FROM dev0004:5000/library/ubuntu-utopic
MAINTAINER "Marc Wäckerlin"
RUN apt-get install -y apache2
EXPOSE 80 443
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

Now cd to that directory, that contains only the docker file and build the an image dev0004:5000/library/ubuntu-utopic-apache from the docker file and push it to your registry:

docker build --rm --force-rm --pull -t dev0004:5000/library/ubuntu-utopic-apache .
dev0004:5000/library/ubuntu-utopic-apache

Now, running it is simpler, because there is no need to specify  a  command, the ENTRYPOINT is enough as default:

docker run -d --name test-apache -p 9876:80 dev0004:5000/library/ubuntu-utopic-apache

ADD vs. COPY

COPY copies files from the host, i.e. from the Dockerfile directory into the docker container, it is a subset of ADD. ADD can also handle URLs as source and ADD untars tarred sources.

Completely Delete an Image on Private Registry

If you are experimenting, then sometimes it might be necessary to cleanup by completely removing images from your own repository. You can do this through a REST API call. Here an example, where I delete image library/ubuntu-unicorn from a registry that runs on port 5000 of host dev0004:

curl -X DELETE http://dev0004:5000/v1/repositories/library/ubuntu-unicorn/

Docker Volumes

If you specify a volume in a container, it means, that there are data that are not part of the container image. So if you commit a container, the volumes won’t be changed in the image. On the other hand, you can mount a local file or filesystem of the host to a volume inside a container. This way, you can easily backup your data or even remove or replace the container (e.g. by a newer version) and keep the data.

Link container file /var/www to host’s /home/me/data/www-test:

docker run [...] -v /home/me/data/www-test:/var/www [...]

Several container can share the same data in a data container. Link the volumes of one docker data container to the volumes of another docker container, where container1 contains only data and container2 and container3 contain the application that accesses the data:

docker create --name container1 -v /path/to/data [...]
docker run --name container2 --volumes-from container1 [...]
docker run --name container2 --volumes-from container1 [...]

Backup the data, e.g. attach a busybox container that tars the data:

docker run --volumes-from container1 -v $(pwd):/backup busybox tar xjf /backup/backup.tar.bz2 /path/to/data

Linking Docker Container

Linking two docker instances together using option docker run --link other-container-name:alias results in local environment variables named ALIAS_... in the docker instance, there you find connect information, such as URL or ports. Also, the hostname alias is added to /etc/hosts, so you can address the link partner using its host name.

Changing Bridge Subnetwork

In my company, they use the 172.16.0.0/16 and 172.17.0.0/16 range for internal purpose, so when I start docker on my laptop, it takes one out of those addresses, and when I then try to use our intranet, it fails. Therefore I need to specify a different range in /etc/default/docker:

DOCKER_OPTS="--bip=172.21.42.1/16"

Unfortunately, due to a bug in docker, it’s not enough to restart docker, but bridge and iptables need to be reset:

sudo systemctl stop docker
sudo iptables -t nat -F
sudo ifconfig docker0 down
sudo brctl delbr docker0
sudo systemctl start docker

That’s it, unless you use docker swarm. In that case, swarm creates docker_gwbridge on 172.17.0.1. To get rid of it and set it, e.g. to 172.28.0.1:

docker swarm leave
docker network rm docker_gwbridge
docker network create \
       --subnet 172.28.0.0/20 \
       --gateway 172.28.0.1 \
       -o com.docker.network.bridge.enable_icc=false \
       -o com.docker.network.bridge.name=docker_gwbridge \
       docker_gwbridge

Then init or join the swarm again.

comments title

[…] support a maintained docker image that contains an Ubuntu based build environment and build scripts for several libraries and […]

[…] Evaluation, I recommend using docker swarm instead of kubernetes. Docker swarm is now integrated in docker, so it fits perfectly the need when using docker, and moreover it is extremely simple to use and […]

[…] yourself to the group docker to be able to use docker without sudo. A normal person would read the best blog entry on docker to get the exact command. But not me, I thought it’s a good idea to write the command from my […]