This tutorial includes the concepts and commands covered in the first session in the series, Getting Started with Containers.

Introduction

Docker is a platform to deploy and manage containerized applications. Containers are popular among developers, administrators, and devops engineers due to the flexibility they offer.

Docker has three essential components:

Docker Engine

Docker Tools

Docker Registry

Docker Engine provides the core capabilities of managing containers. It interfaces with the underlying Linux operating system to expose simple APIs to deal with the lifecycle of containers.

Docker Tools are a set of command-line tools that talk to the API exposed by the Docker Engine. They are used to run the containers, create new images, configure storage and networks, and perform many more operations that impact the lifecycle of a container.

Docker Registry is the place where container images are stored. Each image can have multiple versions identified through unique tags. Users pull existing images from the registry and push new images to it. Docker Hub is a hosted registry managed by Docker, Inc. It’s also possible to run a registry within your own environments to keep the images closer to the engine.

By the end of this tutorial, you will have installed Docker on a DigitalOcean Droplet, managed containers, worked with images, added persistence, and set up a private registry.

By default, the docker command requires root privileges. However, you can execute the command without the sudo prefix by running docker as a user in the docker group.

To configure your Droplet this way, run the command sudo usermod -aG docker ${USER}. This will add the current user to the docker group. Then, run the command su - ${USER} to apply the new group membership.

This tutorial expects that your server is configured to run the docker command without the sudo prefix.

Step 1 — Installing Docker

After SSHing into the Droplet, run the following commands to remove any existing docker-related packages that might already be installed and then install Docker from the official repository:

After installing Docker, verify the installation with the following commands:

docker info

The above command shows the details of Docker Engine deployed in the environment. The next command verifies that the Docker Tools are properly installed and configured. It should print the version of both Docker Engine and Tools.

docker version

Step 2 — Launching Containers

Docker containers are launched from existing images which are stored in the registry. Images in Docker can be stored in private or public repositories. Private repositories require users to authenticate before pulling images. Public images can be accessed by anyone.

To search for an image named hello-world, run the command:

docker search hello-world

There may be multiple images matching the name hello-world. Choose the one with the maximum stars, which indicates the popularity of the image.

Check the available images in your local environment with the following command:

docker images

Since we haven’t launched any containers yet, there will not be any images. We can now download the image and run it locally:

docker pull hello-world

docker run hello-world

If we execute the docker run command without pulling the image, Docker Engine will first pull the image and then run it. Running the docker images command again shows that we have the hello-world image available locally.

Let’s launch a more meaningful container: an Apache web server.

docker run -p 80:80 --name web -d httpd

You may notice additional options passed to the docker run command. Here is an explanation of these switches:

-p — This tells Docker Engine to expose the container’s port 80 on the host’s port 80. Since Apache listens on port 80, we need to expose it on the host port.

--name — This switch assigns a name to our running container. If we omit this, Docker Engine will assign a random name.

-d — This option instructs Docker Engine to run the container in detached mode. Without this, the container will be launched in the foreground, blocking access to the shell. By pushing the container into the background, we can continue to use the shell while the container is still running.

To verify that our container is indeed running in the background, try this command:

docker ps

The output shows that the container named web is running with port 80 mapped to the host port 80.

Now access the web server:

curl localhost

Let’s stop and remove the running container with the follow commands:

docker stop web

docker rm web

Running docker ps again confirms that the container is terminated.

Step 3 — Adding Storage to Containers

Containers are ephemeral, which means that anything stored within a container will be lost when the container is terminated. To persist data beyond the life of a container, we need to attach a volume to the container. Volumes are directories from the host file system.

Start by creating a new directory on the host:

mkdir htdocs

Now, let’s launch the container with a new switch to mount the htdocs directory, pointing it to the Apache web server’s document root:

Notice that the container is launched in the background with port 5000 exposed and the registry directory mapped to the host file system. You can verify that the container is running by executing the docker ps command.

We can now tag a local image and push it to the private registry. Let’s first pull the busybox container from Docker Hub and tag it.

docker pull busybox

docker tag busybox localhost:5000/busybox

docker images

The previous command confirms that the busybox container is now tagged with localhost:5000, so push the image to the private registry.

docker push localhost:5000/busybox

With the image pushed to the local registry, let’s try removing it from the environment and pulling it back from the registry.

docker rmi -f localhost:5000/busybox

docker images

docker pull localhost:5000/busybox

docker images

We went through the full circle of pulling the image, tagging it, pushing it to the local registry, and, finally, pulling it back.

There may be instances where you would want to run the private registry in a dedicated host. Docker Engine running in different machines will talk to the remote registry to pull and push images.

Since the registry is not secured, we need to modify the configuration of Docker Engine to enable access to an insecure registry. To do this, edit the daemon.json file located at /etc/docker/daemon.json. Create the file if it doesn’t exist.

Add the following entry:

Editing /etc/docker/daemon.json

{
"insecure-registries" : ["REMOTE_REGISTRY_HOST:5000"]
}

Replace REMOTE_REGISTRY_HOST with the hostname or IP address of the remote registry. Restart Docker Engine to ensure that the configuration changes are applied.

Conclusion

This tutorial helped you to get started with Docker. It covered the essential concepts including the installation, container management, image management, storage, and private registry. The upcoming sessions and articles in this series will help you go beyond the basics of Docker.

Tutorial Series

This series covers the essentials of containers, including container lifecycle management, deploying multi-container applications, scaling workloads, and understanding Kubernetes, along with highlighting best practices for running stateful applications. These tutorials supplement the by the same name.

November 22, 2017

This article supplements the first session, Getting Started with Containers, in a six-part webinar series on Deploying & Managing Containerized Workloads in the Cloud. By the end of this tutorial, you will have installed Docker on a DigitalOcean Droplet, managed containers, worked with images, added persistence, and set up a private registry.

December 22, 2017

In this tutorial, you will use a sample web application based on Node.js and MongoDB to build a Docker image from a Dockerfile, you will create a custom network that allows your Docker containers to communicate, and you will use Docker Compose to launch and scale a containerized application.

In this tutorial, you will learn how Kubernetes primitives work together as you deploy a Pod in Kubernetes, expose it a Service, and scale it through a Replication Controller.

March 7, 2018

In this tutorial, you will apply the concepts from the previous tutorials to build, deploy, and manage an end-to-end microservices application in Kubernetes. The sample web application you'll use in this tutorial is a "todo list" application written in Node.js that uses MongoDB as a database. You'll build a container image for this app from a Dockerfile, and push the image to Docker Hub, and then deploy it to your cluster. Then you'll scale the app to meet increased demand.