Introduction to Docker

What the heck is Docker?


What’s Docker?

Docker is a virtualization tool that effectively allows you to run many, lightweight virtual machines on your computer. Imagine if you were to use VirtualBox but only to deploy services. Other virtualization softwares, such as Vagrant are more designed for providing an environment to explicitly work in, whereas Docker is designed to deploy your code in a reproducible manner.

Why Docker?

A sub-question to “Why Docker?” is: Why virtualization at all? Virtualization allows you to run a separate guest OS on your main host computer. With the example of VirtualBox, you can install and run Linux without messing up your Windows installation.

Docker allows you to run software with many dependencies and installation requirements without messing up your own personal machine or production server. One container might want one version of a dependency, and another container might need an older version. Containers are completely separate from each other (except for the network stack), so as long as you have Docker installed, you can run any Docker container, regardless of what dependencies you have installed locally.

This also fixes issues during testing and deployment. In a world before docker, development environments would typically be much different than continuous integration environments, which would still be much different than production environments. Now, as long as you, your CI, and deployment server have docker, they should all work the same.


Dockerfile: A configuration file describing how to build your application into an image.

Images: The built version of your code. Imagine a Docker image as if it were a Linux ISO that had your application & dependencies pre-installed on it.

Containers: Running version of your code. Image a Docker container as if the Linux ISO had finished installing and you are booting up & running the machine.

Registry: A cloud/service containing a collection of images allowing for easier image distribution. DockerHub’s registry is the official Docker registry.

Building Images

Before you can run a Docker container of your application, you first must build a Docker image.

To best describe a Docker image, imagine a Linux ISO/Image that already has your code & dependencies installed. When you run the image as a container, the image is not modified and can be turned into a container multiple times in the same way you can use a single Linux ISO/Image on multiple computers in parallel.

docker build [OPTIONS] PATH | URL | -
  • --build-arg ARG=VALUE — Arguments that can be supplied at build-time
  • -f FILE , --file FILE — Specify a Dockerfile (defaults to ./Dockerfile)
  • -t NAME , --tag NAME — Specify a “name” to give the new Docker image

The most basic example :

docker build .

This will look in the current directory for a Dockerfile and use that to configure a new image with an automatically generated tag name.

A more complicated example:

docker build -t development \
--build-arg CC=${CC} \
--build-arg CXX=${CXX} \
--f .

This example builds an image named development from a located in the current working directory. Environment variables CMAKE_BUILD_TYPE, CC, and CXX, are passed in as build-args because this specific Dockerfile is able to accept those args to modify the way the code is built. Such build args will usually be documented in the project’s README, or visible within the Dockerfile itself.

Running Containers

A container is a running Docker image. Following the Linux ISO with pre-installed packages & dependencies analogy before, this is the equivalent of running the Linux OS after installing the ISO/Image to that computer.

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
  • -d, --detach — Run the container in the background
  • -e ARG=VALUE, --env ARG=VALUE — Specify an environment variable
  • --name NAME — Specify a name for the container. Good for long running services and general organization.
  • --rm — Automatically remove the container when it exits. Good for scripting when you only want a single thing from the container (such as generated documentation or running a suite of tests)
  • -v HPATH:GPATH, --volume HPATH:GPATH— Allows a link between a host’s directory and the container’s directory. Good for supplying secret credentials or getting data out of the container. HPATH is a folder/file path on the host system. GPATH is a folder/file path on the guest/container.
  • --restart (no/failure/always) — When/If the container should restart automatically. no means never restart automatically. failure means to only restart if docker container failed, always means to restart the container as soon as it exits. The always option is typically good for long running services where there is potential for the host to reboot.

The most basic example:

docker run hello-world

This is the Hello, World! of Docker containers. If Docker does not immediately recognize an image on your local system (such as hello-world ), it will automatically try to download it from the official Docker registry and run it.

A more complicated example:

docker run --rm -v ${TRAVIS_BUILD_DIR}/docs:/prj/docs development doxygen

In this example, we are running an image development with the doxygen command. Doxygen generates automatic documentation in the container’s /prj/docs folder. We use an environment variable ${TRAVIS_BUILD_DIR} to tell Docker to link the container’s /prj/docs folder to our ${TRAVIS_BUILD_DIR}/docs folder. We finally tell the container to remove itself on completion with the rm flag.

Writing Dockerfiles — Dockerfile

A Dockerfile is a per-project configuration on how to build your code.

  • FROM <IMAGE> — Specify a foundation for your image. Typically these will be from the DockerHub registry.
  • LABEL maintainer <EMAIL> — Contact information about the maintainer/owner of the Dockerfile/image.
  • ADD <SRC> <DST> — Copy files from the host’s SRC path to the container’s DST path. Good for initially getting your code into the image.
  • WORKDIR <PATH> — Change directories to the new path.
  • RUN <COMMAND> — Execute a command.
  • EXPOSE <PORT> — Specify a port for the running container to expose.
  • CMD ["COMMAND", "ARG1", "ARG2", ... ] — The command ran when no command is specified by the Docker run command. It is recommended to make this command execute your production code.

Here is a simple example of a NodeJS project’s Dockerfile:

FROM node:latest
LABEL maintainer ""
ADD . prj
RUN npm run setup
RUN npm run build
CMD ["npm", "start"]

Writing Dockerfiles — .dockerignore

In the same way that a .gitignore file keeps certian files from being committed in git, a .dockerignore file keeps certian files/folders from being added to a Docker image.

It is usually a good idea to keep the following from being added to images:

  • Sensitive information
  • Editor configurations (Vagrant, VSCode, Webstorm, etc.)
  • Built files (Executables, minified JS, compiled JS, etc.)
  • Generated documentation
  • Git information (.git/.gitignore.gitattributes)
  • Docker information (Dockerfile.dockerignore)
  • Downloaded dependencies (node_modules/, bower_components/)
# Editors & Environment
.vscode/ #VS Code
.idea/ #JetBrains
.env #Environment variable file
# NodeJS & NPM
* #JS Map files
*.min.js #Minified JS files
# Git
# Misc
*.log #Logs
docs/ #Generated docs

Configuring DockerHub Auto-build

Assuming your project is open source, DockerHub provides an easy way to get your images up onto the official Docker registry.

Select “Create Automated Build” from drop-down

After connecting with GitHub, you’ll be able to select which repo you want it to automatically build. By default, it will look for a Dockerfile in the project root. The master branch will be served as the latest label, and you can configure other branches to be other labels. For example, creating a stable branch and making DockerHub serve that up as the stable label.

Learning More

There are tons of references out there, including official Docker documentation and other personal blog posts, including an interactive tutorial:

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.