# Docker

## Summary


A container is a standard unit of software that packages an application with all of its dependencies and libraries. This makes it easy to deploy applications within containers regardless of hardware configuration or operating system. Unlike virtual machines, containers use the host OS rather than bundling an OS with the application. 

Docker is a container platform. It provides a complete ecosystem of tools to build container images, pull these images from known registries, deploy containers, and manage or orchestrate running containers across a cluster of machines. Docker has popularized container adoption. Even the phrase "dockerize my app" has become common. 

The word "Docker" usually refers to its engine. The commercial offering is called *Docker Enterprise*. There's also the free community edition that's simply called *Docker Engine*. Docker was initially available on Linux but later become available on MacOS and Windows as well.

## Discussion

### What are the benefits of using Docker?

Docker provides a consistent runtime across all phases of a product cycle: development, testing, and deployment. For example, if development team has upgraded one dependency, other teams must also do the same. If they don't, app may work during development but fail in deployment or work with unexpected side effects. Docker overcomes this complexity by providing a consistent environment for your app. Hence, it's become essential for DevOps practice. 

Docker containers are smaller in size and boot up faster compared to VMs. They're also more cost efficient since many more containers than VMs can run on a machine. 

Docker is open source. There's freedom of choice since any type of application (legacy, cloud native, monolithic, 12-factor) can run in a Docker container. Security is built into the Docker Engine by default. It's powered by some of the best components such as the *containerd*. There's also powerful CLI and API to manage containers. Via certified plugins, we can extend the capabilities of the Docker Engine. 


### What do you mean by the term "Docker image"?

A Docker image is a read-only template from which containers are created. Here's a useful analogy: just as objects are instantiated from classes in object-oriented languages, Docker containers are instantiated from Docker images.

For example, your application may require an OS and runtimes such as Apache, Java or ElasticSearch. All these can be bundled into a Docker image. Thus, your app can have this exact runtime environment wherever it runs. 

An image is built in multiple read-only layers. At the bottom, we might have bootfs and OS base image such as Debian. Higher layers could have custom software or libraries such as Emacs or Apache. This layering mechanism makes it easy to build new images on top of existing images. When an image gets instantiated into a running container, a thin writable layer is added on top, called **Container Layer**. This means that all changes go into the topmost layer. In fact, the underlying file system doesn't make a copy of the lower layers since they are read-only. This helps us bring up containers quickly. 


### How do developers share Docker images?

A remote location where Docker images are stored is called the **Docker Registry**. Images are pulled from and new images are pushed to the registry. Without registries, it would be difficult to share and reuse images across projects. There are many registries online and **Docker Hub** is the default one. Just as developers share code via GitHub, Docker images are shared via Docker Hub. 

Besides Docker Hub, here are some other registries: Gitlab, Quay, Harbor, and Portus. Registries from cloud providers include Amazon Elastic Container Registry, Azure Container Registry, and Google Container Registry. 

A collection of images with the same name but different tags is called **Docker Repository**. A tag is an identifier for an image. For example, "Python" is name of the repository but when we pull the image "Python:3.7-slim", we refer to the image tagged with "3.7-slim". In fact, it's possible to pull by mentioning only the repository name. A default tag (such as "latest") will be used and only that image will be pulled. Thus, these two commands are equivalent: `docker pull rhel7` or `docker pull registry.access.redhat.com/rhel7:latest` . 


### Which are the essential components of the Docker ecosystem?

The **Docker Engine** is a client-server app of two parts: the **Docker Client** and the **Docker Daemon**. Docker commands are invoked using the client on the user's local machine. These commands are sent to daemon, which is typically running on a remote host machine. The daemon acts on these commands to manage images, containers and volumes. 

Using **Docker Networking** we can connect Docker containers even if they're running on different machines. What if your app involves multiple containers? This is where **Docker Compose** is useful. This can start, stop or monitor all services of the app. What if you need to orchestrate containers across many host machines? **Docker Swarm** allows us to do this, basically manage a cluster of Docker Engines. 

**Docker Machine** is a CLI tool that simplifies creation of virtual hosts and install Docker on them.  **Docker Desktop** is an application that simplifies Docker usage on MacOS and Windows. 

Among the commercial offerings are **Docker Cloud**, **Docker Data Center** and **Docker Enterprise Edition**. 


### Which are the command-line interfaces (CLIs) that Docker provides?

Since Docker has many components, there are also multiple CLIs: 

    + **Docker CLI**: This is the basic CLI used by Docker clients. For example, `docker pull` is part of this CLI with "pull" being the child command. These commands are invoked by user using the Docker Client. Commands are translated to Docker API calls that are sent to the Docker Daemon.
    + **Docker Daemon CLI**: The Docker Daemon has its own CLI, which is invoked using the `dockerd` command. For example, the command `$ sudo dockerd -H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock &` asks the daemon to listen on both TCP and a Unix socket.
    + **Docker Machine CLI**: This is invoked with the command `docker-machine`.
    + **Docker Compose CLI**: This is invoked with the command `docker-compose`. This uses Docker CLI under the hood.
    + **DTR CLI**: Invoked with `docker/dtr`, this is the CLI for Docker Trusted Registry (DTR).
    + **UCP CLI**: Invoked with `docker/dtr`, this is the CLI for installing and managing Docker Universal Control Plane (UCP) on a Docker Engine.

### What are Volumes in Docker and where are they useful?

Containers are meant to be temporary. Any changes made to it at runtime are usually not saved. Sometimes we may save the changes into a new image. Otherwise, changes are discarded. However, there's merit in saving data or state so that other containers can use them. Volumes are therefore used for **persistent storage**. 

A volume is a directory mounted inside a container. It points to a filesystem outside the container. We can therefore exit containers without losing app data. Newer containers that come up can access the same data using volumes. The important thing is to implement locks or something equivalent for concurrent write access. Volumes can be created via Dockerfile or Docker CLI tool. 

Apart from sharing data or state across containers, volumes are useful for sharing data (such as code) between containers and host machines. They're also useful for handling large files (logs or databases) because writing to volumes is faster than writing to Docker's Union File System (UFS) that uses IO expensive copy-on-write (CoW). 


### What's the purpose of a Dockerfile?

Dockerfile is nothing more than a text file containing instructions to build a Docker image. Each instruction creates one read-only layer of the image. When the container runs, a new writable layer is created on top to capture runtime changes. 

Let's take the example of a Node.js application. The instruction `FROM node:9.3.0-alpine` specifies the base image of Node.js version 9.3.0 running on Alpine Linux. `ADD` instruction can be used to add files. `RUN` can be used for framework installation or application build. To expose ports from the container, use `EXPOSE`. To finally launch the app within the container, use the `CMD`. 

For more details, read Dockerfile Reference and the best practices for writing Dockerfiles.


### What are some basic Docker commands that a beginner should know?

We describe some Docker commands listed in the official Docker documentation:

To build a new image from a Dockerfile use the `build` command. We can then push this to a registry using `push`. Commands `search` and `pull` can be used to find and download an image from registry to our local system. To create a new image from a running container's changes, we can use `commit`. To list images, use `images`. A downloaded image can be removed using `rmi`. 

Once we have an image, we can create and start a container using `create` and `start`. Containers can be stopped using `stop` or `kill`. A running container can be restarted using `restart`. We can use `rm` to remove containers. The command `ps` will list all running containers. To list stopped containers as well, use "-all" option. 

Commands that deal with processes inside containers include `run`, `exec`, `pause`, `unpause` and `top`. Commands that deal with container filesystem include `cp`, `diff`, `export` and `import`. 

## Milestones

Mar  
2013

Docker is debuted publicly and open sourced at PyCon, Santa Clara. Earlier work on Docker can be traced to 2010. 

Sep  
2013

Red Hat and Docker announce a collaboration around Fedora, Red Hat Enterprise Linux, and OpenShift. 

Mar  
2014

Docker replaces LXC with *libcontainer* as the runtime. The latter is written in Golang and developed by the Docker team. 

Jun  
2015

Docker, CoreOS and others form the **Open Container Initiative (OCI)**. At the same time, Docker's libcontainer becomes a standalone OCI-compliant runtime called *runc*.  In December 2015, Docker announces *containerd*, a daemon to manage runc. 

2016

By this time, many companies including Cisco, IBM, Google, Microsoft, Huawei and Red Hat are main contributors to Docker. In June, Docker starts to support container orchestration with **swarm mode**. 

Jan  
2017

A YAML compose file `docker-compose.yml` can be used to deploy swarm mode services. 

Mar  
2017

Docker releases **Docker Enterprise Edition**. It renames the free open source product to **Docker Community Edition**. 

Jul  
2017

Version 1.0 of OCI runtime and image format specifications are released. 

Mar  
2018

Docker celebrates its fifth birthday. By now, there's an estimated 37 billion container downloads, 3.5 million dockerized apps and 450+ customers using Docker Enterprise Edition.