Getting started with Docker: Installation, first steps

; Date: October 8, 2020

Tags: Docker »»»» Docker MAMP

Let's start this journey into Docker by learning how to install it on popular systems, namely macOS, Windows and Linux. Installation is very simple thanks to the hard work of the Docker team. You youngsters don't know how easy you have it now that Docker for Mac and Docker for Windows exist. Long gone are the days when we had to install VirtualBox along with a specialized virtual machine to use Docker.

Docker is an ecosystem of tools, most of which are open source. This includes tools for constructing Docker images, running Docker containers, interacting with remote Docker servers, and orchestrating Docker deployments over multiple machines using either Docker Swarm or Kubernetes.

Learning about all that starts with installing Docker CE on your laptop. The official instructions are available on the website. What follows is our attempt to explain it better than did the Docker team.

On Linux systems, Docker runs natively using normal Linux background processes that are managed by systems like systemctl. Docker containers are a lightweight virtualized Linux execution environment. This is not a virtual machine tool like VirtualBox or KVM, but a light weight container environment. For example processes inside the running Docker container are actually processes running on the host operating system, with Docker creating multiple layers of redirection around each process. The result is that one container might be built with Debian, another built with Arch Linux, another built with Gentoo, but the host operating system is Linux Mint, with Docker keeping everything straight.

On both macOS and Windows, however, the host operating system is not Linux, obviously, and Docker does not run natively. Instead, the Docker for Windows and Docker for macOS applications contain a lightweight virtual Linux environment within which is a Docker execution environment. Inside that virtual Linux machine is the same Docker we'd run natively on Linux, just hidden within a Linux VM. The good news is that, unlike the olden days a few years ago where we had to build that Linux VM ourselves, the Docker team has made sure the Docker application takes care of everything for us. You'll find that Docker is very lightweight and can be left running in the background of your laptop with no impact on system performance.

In this article we'll first discuss installing Docker Desktop for macOS and Windows, then installing Docker Community Edition for Linux, and wrap up with a quick introduction to using Docker command-line tools.

Installing Docker on macOS

Official instructions: (docs.docker.com) https://docs.docker.com/docker-for-mac/install/

Pre-requisites:

  • The Mac hardware must be a 2010 or later model, with Intel’s hardware support for memory management unit (MMU) virtualization, including Extended Page Tables (EPT) and Unrestricted Mode. The command sysctl kern.hv_support detects whether the computer has the required support.
  • The macOS version must be at least 10.14, a.k.a. Mojave or Catalina. It will run on macOS 10.13 but you will be constantly nagged to upgrade.
  • VirtualBox prior to version 4.3.30 must not be installed.

Installation couldn't be simpler - you download the Docker for Mac bundle, which is named Docker.dmg. As the name implies this is a macOS disk image, which you double-click to open. Once opened, you drag the Docker icon to the Applications folder just like zillions of other macOS applications.

The Docker application icon on macOS. For Windows, you'll find Docker on the Start menu.

Once copied to the Applications folder, you double click the Docker icon to launch the application.

It starts like a regular Mac application, and in all ways behaves like one. The first time it's launched you'll be taken through a setup process.

An icon is added to the top status bar. The icon shows current status, and gives access to a menu showing further details.

Docker for Mac relies on an extremely light-weight hypervisor, HyperKit. Inside that hypervisor is running a Linux system with enough capability to host Docker services. Processes associated with your Docker containers are not running in macOS, but instead are running in this Linux image inside the hypervisor.

Installing Docker on Windows

Official instructions: (docs.docker.com) https://docs.docker.com/docker-for-windows/install/

Pre-requisites:

  • Windows 10, 64-bit, either Pro, Enterprise or Education versions
  • The Hyper-V and Containers features of Windows must be enabled
  • The CPU must support 64-bit execution and have Second Level Address Translation (SLAT)
  • BIOS-level hardware virtualization must be enabled

Once you've downloaded the installer, Docker for Windows Installer.exe, run it to go through the install wizard.

Once Docker is installed, it is launched through the Start menu, just like any Windows application. From here it behaves like a Windows app, for example an icon is added to the taskbar.

Docker for Windows relies on an extremely light-weight hypervisor, Hyper-V. This is an optional feature of Windows 10 Pro/Enterprise/etc that can be enabled. Like for Docker for Mac, the Docker containers you run on Windows will not be Windows processes, but instead will run in the Linux image running inside the Hyper-V hypervisor.

The Docker Desktop GUI

Both the Windows and macOS Docker installations come with a GUI application with which we can manage Docker. This application is started either from the application icon, or the taskbar menu.

The Docker desktop GUI.

If there were any Docker containers executing they'd be listed here. But, as we can see there are none, and instead there's a helpful suggestion for getting started. We'll get to this later on.

Notice a "gear" icon at the top. This gets you into the Preferences pane. For example we can control whether Docker automatically starts when the computer boots, and other settings.

Settings for Docker advanced features.

Enabling the experimental features does what it sounds like, which is to keep our Docker environment updated with the latest features. As of this writing these features include closer integration with AWS that we will use later in the book.

Before heading to the Docker command-line let's talk about installation on Linux.

Linux installation

Unlike with Windows or macOS, on Linux we install several components separately. This starts with installing Docker Engine, or the component that handles Docker execution and some of the command line tools.

The documentation root is at: (docs.docker.com) https://docs.docker.com/engine/install/

There are specific instructions for CentOS, Debian, Fedora and Ubuntu:

Docker runs natively on Linux and therefore does not require a hypervisor. Installation is done through the official package management system for the above distros. On other distros you have a couple hoops to jump through.

You may need to remove old versions first:

$ sudo apt-get remove docker docker-engine docker.io

The Docker CE version is newer than the docker.io version, and it's best to completely remove old traces before continuing.

For Ubuntu this is the official instructions:

sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get -y install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo apt-key fingerprint 0EBFCD88

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install -y docker-ce docker-ce-cli containerd.io

This configures the OS to access the Docker package repository, then to install the Docker CE and Containerd packages. The last command tells Linux to automatically start Docker when the system boots.

For other Linux distros, see the official instructions page.

Post-install instruction for Linux

All versions of Linux have some post-install steps to make it more convenient to use Docker.

See: (docs.docker.com) https://docs.docker.com/install/linux/linux-postinstall/

$ sudo groupadd docker
$ sudo usermod -aG docker $USER

This adds a new group named docker. Any user in the docker group can freely run the Docker commands. Otherwise running Docker commands requires using sudo docker. Repeat the usermod command for each user ID that is to have access to the docker command.

Then we enable Docker to run in the background:

# for systemctl
$ sudo systemctl enable docker
# for upstart
$ echo manual | sudo tee /etc/init/docker.override
# for chkconfig
$ sudo chkconfig docker on

The next step is configuring Docker to launch when the system reboots. If you do not do this, you'll be required to start Docker manually before running any containers. By doing this we can treat any Docker container as a background daemon service.

Installing Docker Compose on Linux

Docker Compose is a very important part of the Docker ecosystem. Compose lets us easily launch and manage a group of Docker containers via use of a Docker Compose (YAML) file.

For the Windows and macOS platforms, Docker Compose is automatically installed. On Linux, however, we must install it separately.

See the documentation: (docs.docker.com) https://docs.docker.com/compose/

The official documentation gives a complex process for installing Compose on Linux. You might, however, find it in the regular package management system.

As of this writing some changes are occurring that may make docker-compose irrelevant. That's because of a new docker compose sub-command that seems to be intended to take its place.

Familiarizing ourselves with Docker

Now that we have Docker and Docker Compose installed, let's kick the tires. While there is a GUI application we can use on macOS or Windows, the primary user interface is at the command line. That's where we must go.

As with so many software tutorials, let's start by saying Hello World:

$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
ca4f61b1923c: Pull complete 
Digest: sha256:97ce6fa4b6cdc0790cda65fe7290b74cfebd9fa0c9b8c38e979330d547d22ce1
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://cloud.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/engine/userguide/

The docker run command does several things at once. The hello-world portion of the command line specifies the name of the Docker image to run. The first thing the command does is to check whether the image already exists on the local computer, and if not it will download the image. In this case you see Unable to find followed by Pulling from, indicating that docker run did indeed download the hello-world image. Once downloaded, it executed the image which in this case caused the message to be printed.

This particular image is useful for a quick verification that Docker is correctly installed. It also suggests a next step in our exploration:

MacBook-Pro-4:ebooks david$ docker run -it ubuntu bash 
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
d72e567cc804: Pull complete 
0f3630e5ff08: Pull complete 
b6a83d81d1f4: Pull complete 
Digest: sha256:bc2f7250f69267c9c6b66d7b6a81a54d3878bb85f1ebb5f951c896d13e6ba537
Status: Downloaded newer image for ubuntu:latest
root@9c18de0b90a3:/# uname -a
Linux 9c18de0b90a3 4.19.76-linuxkit #1 SMP Tue May 26 11:42:35 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
root@9c18de0b90a3:/# exit
MacBook-Pro-4:ebooks david$ uname -a
Darwin MacBook-Pro-4 17.7.0 Darwin Kernel Version 17.7.0: Mon Aug 31 22:11:23 PDT 2020; root:xnu-4570.71.82.6~1/RELEASE_X86_64 x86_64

In this variation the -it option says to run the image interactively attached to the users terminal. The image name is ubuntu, which packages up a subset of the Ubuntu operating system. The last token, bash, says to execute the Bash command when the Ubuntu container starts. The first uname -a command verifies that indeed we are running in Linux, and then after we exit from that command line the second uname -a indicates that we are on a MacBook Pro running macOS.

Notice that this process is described as first downloading a Docker image, then executing the Container. This refers to two stages of the Docker lifecycle.

  • A Docker image is a bundle containing everything required to build an execution environment. This involves file system images, executable software, configuration files, metadata, and more.
  • A Docker container is what we get when Docker unpacks and executes an image. A container is very similar to a virtual server, but it has a much lighter weight implementation than virtual machine systems like VirtualBox or KVM.

One way to see the difference is with these commands:

$ docker ps
CONTAINER ID   IMAGE        COMMAND    CREATED          STATUS   PORTS              NAMES
$ docker ps -a
CONTAINER ID   IMAGE        COMMAND    CREATED          STATUS   PORTS              NAMES
9c18de0b90a3   ubuntu       "bash"     19 minutes ago   Exited (0) 18 minutes ago            peaceful_meninsky
$ docker images
REPOSITORY        TAG       IMAGE ID       CREATED        SIZE
ubuntu            latest    9140108b62dc   11 days ago    72.9MB
...
hello-world       latest    bf756fb1ae65   9 months ago   13.3kB

The first command, docker ps, shows the currently running containers on the local system. In this case there are none. The second command, docker ps -a, shows the containers that executed but have exited. The last, docker images, lists the images which are in the local image cache.

The last shows that we've downloaded both the ubuntu and hello-world images. The second shows that we recently executed the ubuntu image, but it exited a little while ago. The first shows there are no currently executing containers.

The name peaceful_meninsky shown for the ubuntu is the user-friendly name it has been assigned by Docker. The actual identifier is the Container ID column, where the code string shown here is shorted from the actual code string for the container. While peaceful_meninsky is a strange name it's a lot easier to deal with than 9c18de0b90a3.

We can delete the container with this command:

$ docker rm peaceful_meninsky
peaceful_meninsky

After which docker ps -a will show nothing.

To assign a name to a container, use the --name option:

$ docker run -it --name ubuntu ubuntu bash 
root@52aab16afff6:/# 

This again starts an Ubuntu container running Bash in the foreground. To run docker ps we must open another command window and type this:

$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS          PORTS      NAMES
52aab16afff6   ubuntu    "bash"    31 seconds ago   Up 30 seconds              ubuntu

This shows that the ubuntu container is currently running, and that we gave it the name ubuntu.

The next thing to try is the command shown in the Docker GUI:

$ docker run -d -p 80:80 docker/getting-started
Unable to find image 'docker/getting-started:latest' locally
latest: Pulling from docker/getting-started
cbdbe7a5bc2a: Already exists 
85434292d1cb: Pull complete 
75fcb1e58684: Pull complete 
2a8fe5451faf: Pull complete 
42ceeab04dd4: Pull complete 
bdd639f50516: Pull complete 
c446f16e1123: Pull complete 
Digest: sha256:79d5eae6e7b1dec2e911923e463240984dad111a620d5628a5b95e036438b2df
Status: Downloaded newer image for docker/getting-started:latest
e01857e87689b0f7c287df52dc0ae6408a9749c46f48b0ca3b17c126c8e3545e

In this case the container does not execute in the foreground, and it does not produce any output for the user to see. This is because it uses the -d option, which is short for --detach, which means to detach the container from the terminal and run it in the background.

The -p option is short for --publish and is how we specify which TCP ports to bind to the container. In this case the container has a service on TCP port 80, which is the standard port for HTTP. We have published the container port 80 to the host machine, our laptop, on port 80. It's possible to use this option to remap the port to any port number. For example, with -p 4080:80 we publish it to port 4080 instead, mapping port 80 to port 4080.

In any case, this means we can visit http://localhost in our browser and see this:

This container is a full website comprising a Docker tutorial. Getting it running simply required downloading and running the container.

With this we start to see the value of Docker. There are tens of thousands of prepackaged applications available through Docker that we can download and execute in the same fashion. For example, do you need a Github clone you run on your own hardware? Both Gitlab and Gitea are available, and Jenkins and other build tools are also available. Installing Gitea and Jenkins can be installed on a spare Mac Mini in a couple hours. Such a small machine can be kept on a shelf in the office to make a local development and build environment.

About the Author(s)

David Herron : David Herron is a writer and software engineer focusing on the wise use of technology. He is especially interested in clean energy technologies like solar power, wind power, and electric cars. David worked for nearly 30 years in Silicon Valley on software ranging from electronic mail systems, to video streaming, to the Java programming language, and has published several books on Node.js programming and electric vehicles.