In short, Docker works like a virtual machine with considerably less overhead. It is used to run applications in an environment isolated from the rest of the system. Each Docker container can run its own Linux distribution regardless of the distribution on the host. The host can be a physical machine or a VPS (KVM, XEN, Virtualbox) and installing and using Docker requires root access.

Defined by a single configuration file, Docker containers can be rebuilt from scratch very quickly and will work identically regardless of which server they are rebuilt on. It is advantageous to develop applications locally using Docker so they can later be moved to production with few surprises.

Installing Docker (Ubuntu 14.04)

For installation on other distributions, visit Docker's site.

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 \
     --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9

sudo sh -c "echo deb https://get.docker.io/ubuntu \
     docker main /etc/apt/sources.list.d/docker.list"

sudo apt-get update
sudo apt-get install lxc-docker

Docker Images / Docker Instances

Docker images are essentially predefined filesystems that Docker can use. You can use predefined images like ubuntu, ubuntu:12.04, centos, busybox, tianon/gentoo:latest, or images built starting from base images with your own modifications, updates, installations and configurations. All Docker commands must be run as root.

# download the "ubuntu" image from the internet
docker pull ubuntu:latest

# list all locally accessible images
docker images

# start an ubuntu instance running /bin/bash
# can detach with ^P^Q and reattach with docker attach
docker run -i -t ubuntu /bin/bash

# delete the image / delete all images
docker rmi ubuntu
docker rmi $(docker images -q)

# list active instances
docker ps

# list all instances
docker ps -a

# delete all stopped instances
docker rm $(docker ps -a -q)

# restart the instance with ID 15786070c102
docker start 15786070c102

# connect to the instance with ID 15786070c102
docker attach 15786070c102

# save modifications from instance 15786070c102
docker commit 15786070c102 new_image

New Images / Dockerfile

New images can be created by saving the modifications of a Docker instance or by executing a Dockerfile. Executing a Dockerfile means starting an existing image, successively executing a list of commands, and defining execution parameters, all in an automated system. A minimal Dockerfile example is shown below. Note: Docker instances stop automatically when the initial command finishes execution. To run services long-term, supervisord is commonly used.

FROM       ubuntu:latest
MAINTAINER Cosmin L. Neagu <cosmin@rohost.com>

RUN apt-get update
RUN apt-get -y upgrade

ENTRYPOINT /bin/bash
docker build -t="xxx" .

Docker Template: Functional Example

Regardless of what project we implement, each of us has our own preferences for settings or favorite utilities. For this reason we will create a base Docker image, a template, which we will then use as a starting point. There are multiple ways of working but for now we will explore the more comfortable variant, in which we use Docker like a virtual machine running multiple services simultaneously.

In an empty directory, create the Dockerfile with the content below. We tell Docker to start from Ubuntu 14.04, update system packages, install our desired utilities, then configure SSH for remote access and supervisord to easily add new services later. The authorized_keys file must contain the public SSH keys of people you want to have access (most likely the content of your ~/.ssh/id_rsa.pub). The supervisord.conf ensures that the service remains active in the foreground. The supervisord.sshd.conf ensures the SSH server is running.

FROM ubuntu:14.04
MAINTAINER Cosmin L. Neagu <cosmin@rohost.com>

# Set locale
RUN locale-gen --no-purge en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
RUN echo 'LANG="en_US.UTF-8"'    >> /etc/environment
RUN echo 'LC_ALL="en_US.UTF-8"'  >> /etc/environment

# Upgrade packages
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i.bk 's/main$/main universe/' /etc/apt/sources.list && \
    apt-get update && \
    apt-get upgrade -y

# Install & setup supervisord and SSH
RUN mkdir -p /var/run/sshd
RUN mkdir -p /var/log/supervisor
RUN apt-get install -y supervisor openssh-server \
    rsync git vim mc

ADD authorized_keys         /root/.ssh/authorized_keys
ADD supervisord.conf        /etc/supervisor/conf.d/supervisord.conf
ADD supervisord.sshd.conf   /etc/supervisor/conf.d/sshd.conf

EXPOSE 22/tcp

CMD ["/usr/bin/supervisord"]
[supervisord]
nodaemon=true
[program:sshd]
command=/usr/sbin/sshd -D
stdout_logfile=/var/log/supervisor/%(program_name)s.out
stderr_logfile=/var/log/supervisor/%(program_name)s.err
autorestart=true

Creating the Image

On any computer with Docker installed, if we have the above files, we can recreate the template image from scratch. In this case the name is "base" but we can use any name. The IP used must be set on the host and port 222 must be free. GitRepo is an example of a project installed and maintained using Docker and the base image created above.

# create the image
docker build -t "base" .

# list available images
docker images

# start a base image instance accessible via SSH with:
# ssh root@93.115.111.248 -p 222
docker run -d -i -p 93.115.111.248:222:22/tcp -t base