Docker is all the rage these days, and for good reason. It allows you to run instances of an application inside of a container. A container is similar to a virtual machine, but instead of running a full operating system, it runs the minimal runtime requirements of an application or set of applications. This allows multiple isolated applications or services to run on a host machine and access the same OS kernel and it's other components (network, file system, etc.). Some of the advantages of containerization is that is allows for easy portability across machines, uses much less resources than a virtual machine, and speeds up delivery and deployment because of it's lightweight footprint.

Verisons

Docker comes in two different versions:
Docker-CE is the Community Edition, which is free to use but does not come with any paid support. If you have any issues you will have to use the community forums and read through the documentation.

Docker-EE is the Enterprise Edition, which is the licensed version and allows for support contracts with Docker (the company), SLAs, Image management and other features.

For a comparison see the Docker Overview of Docker editions.

In the following tutorial we will learn how to install docker in multiple operating systems, configure docker to be used without root privileges, and learn the basic commands associated with running docker containers.

Terminology

Before we dive in, let's learn a little about the basic terms we are going to hear. I wish I had this list when I was starting to learn docker. I think this will make understanding docker much easier.

  • Images - All docker containers are run from images. Images are files that are a complete version of an application which relies on the host OS kernel and other components.
  • Containers - These are the instances of the application (image) that can be run. You can create multiple containers from an image. All your runtime configuration of the application happen in the container.
  • Docker Hub - This is sort of a repository for prebuilt images ran by the company Docker. Anyone can build an image and host it on Docker Hub. Docker Hub hosts images for MOST applications and Linux distributions, including Ubuntu and CentOS.
  • Pull - Pull is basically download an image from Docker Hub or another location.

Installing docker-ce on CentOS 7 / Red Hat 7

First we ensure all the required packages are installed:

$ sudo yum install -y yum-utils device-mapper-persistent-data lvm2

Now we will add the docker-ce repository.

$ sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

The above command will create a file in /etc/yum.repos.d called docker-ce.repo. This will allow us to easily install and more importantly update docker.
Now we will install docker using yum.

$ sudo yum -y install docker-ce

Installing Docker in Ubuntu 18.04

First let's make sure everything is up to date.

$ sudo apt update
$ sudo apt upgrade

Next, let's install some required packages.

$ sudo apt -y install apt-transport-https ca-certificates curl software-properties-common

Add the GPG key and official Docker repository.

$ wget -qO - https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"

Update the apt database with the new packages from the Docker repo.

$ sudo apt update

Finally install docker-ce

$ sudo apt -y install docker-ce

That's it, docker is now installed and ready to use.

Starting Docker and Enable Docker at Boot

Now that we have docker installed, we can start it, stop it, restart it or check the status of it just like any other service.

$ sudo systemctl start docker
$ sudo systemctl stop docker
$ sudo systemctl restart docker
$ sudo systemctl status docker

Now let's tell docker to start automatically on boot. We do this just like any other service with systemctl.

$ sudo systemctl enable docker

Setup Docker without using Sudo

By default, the docker command requires elevated privileges causing you to type sudo before every command. If you prefer to run docker without root privileges you can add yourself to the docker group. The docker group is created when you install docker-ce.

$ grep docker /etc/group
docker:x:983:

To add yourself (user currently logged in) to the docker group, and avoid the onslaught of sudo commands, just enter the following command.

$ sudo usermod -aG docker $(whoami)

Now we can check to ensure we were added to the additional group called docker.

$ id $(whoami)
uid=1000(savona) gid=1000(savona) groups=1000(savona),983(docker)

NOTE: You must log out of the session and back in for the groups to take effect.

To add other users to the docker group just replace whoami with the username.

$ sudo usermod -aG docker <username>

Using the Docker Command

Now we are ready to use docker, let's take a look at some at the basic command syntax and then we will pull and build our first image.
The basic structure of a docker command is not much different than any other.

$ docker [option] [command] [arguments]

You can also get help by simply asking for it.

$ docker --help

This above line with list out all available commands, here is a sample output.

$ docker
Usage: docker [OPTIONS] COMMAND
A self-sufficient runtime for containers
Options:
--config string Location of client config files (default "/home/savona/.docker")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/home/savona/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/home/savona/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/home/savona/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit
Management Commands:
builder Manage builds
config Manage Docker configs
container Manage containers
engine Manage the docker engine
image Manage images
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes
Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes
Run 'docker COMMAND --help' for more information on a command.

To get help with a specific subcommamd, for example "pull" you can ask for that as well.

$ docker pull --help

Pulling Docker Images

Now that we have that out of the way, let's build our first docker. This will also teach us how to pull an image from the Docker Hub. First let's search the Hub for an image called "hello_world".

$ docker search hello_world

This will list all the available images called "hello_world". At the top of the list you should see an image called "dockerinaction/hello_world". Let's pull that image and test it out.

$ docker pull dockerinaction/hello_world
Using default tag: latest
latest: Pulling from dockerinaction/hello_world
a3ed95caeb02: Pull complete
1db09adb5ddd: Pull complete
Digest:sha256:cfebf86139a3b21797765a3960e13dee000bcf332be0be529858fca840c00d7f
Status: Downloaded newer image for dockerinaction/hello_world:latest

We just pulled our first docker image from the Docker Hub.

Build a Container from an Image

Now let's build a container from that image.

$ docker container create dockerinaction/hello_world
0dad2f9de3604bb71b939fc80d313810ebad98e738ed69c2f2aec3215ecc14a8

NOTE: When a container is created, it is given a unique ID.

Run a Container

Now let's run the container. This container is simply going to output "hello world" when it is run.

$ docker run dockerinaction/hello_world
hello world

That is it, we pulled an image from Docker Hub. Created a container from that image, and ran the container. Let's dive in a little more.

You can also use the run command to pull the image, create the container and run it all at once.

$ docker run dockerinaction/hello_world
Unable to find image 'dockerinaction/hello_world:latest' locally
latest: Pulling from dockerinaction/hello_world
a3ed95caeb02: Pull complete
1db09adb5ddd: Pull complete
Digest: sha256:cfebf86139a3b21797765a3960e13dee000bcf332be0be529858fca840c00d7f
Status: Downloaded newer image for dockerinaction/hello_world:latest
hello world

List All Images

Now that we have an image, let's list out our images to see what we have. To list all images on your system, you can use the following command.

$ docker image ls

Look familiar? I really appreciate the fact that docker made the commands really clean and recognizable.

List All Containers

We can also list out our containers, but there is a small caveat. When listing containers using the ls command you will ONLY see running containers. You must use the -a switch to see the non-running containers.

$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0dad2f9de360 dockerinaction/hello_world "echo 'hello world'" 5 minutes ago Created xenodochial_jennings

IMPORTANT: You MUST use the -a switch to see non-running containers.
As you can see from the output above we have one non-running container. The reason it is not running is because the image is built to just print out "hello world" and then it stops.

NOTE: Take note of the first column, which is the container ID. You will need that for certain commands run against the container.

Deleting Containers

We can delete containers very easily by using another familiar command. Using the rm option we can delete containers, but we have to use the container ID. In our output above we saw that the hello_world container had a container ID of "0dad2f9de360". Let's use the docker container rm command to delete that container.

$ docker container rm 0dad2f9de360
0dad2f9de360

Deleting Images

We have successfully deleted the container, now let's delete the image. Again we will be using the image ID to specify which image we are deleting. You can always get the image ID by listing out your images using the "docker image ls" command.
NOTE: You cannot delete an image if it is being used by a container (stopped or otherwise)

$ docker image rm a1a9a5ed65e9
Untagged: dockerinaction/hello_world:latest
Untagged: dockerinaction/hello_world@sha256:cfebf86139a3b21797765a3960e13dee000bcf332be0be529858fca840c00d7f
Deleted: sha256:a1a9a5ed65e9083dce88ada93a3290b08af9b44a27930e4bdad4da59d728c911
Deleted: sha256:94d2256953fb45ae6d71b09c840b42b490b8437c318d2ccc624f23aae1fa52f6
Deleted: sha256:1a22c6462844ec4c40a854d696a7d532a3d946546986701c6a520649818dfc7f
Deleted: sha256:be0afd7c222710fd2d083bf77227b607cb57490f9b9b0b74c91402c49f2eaef6
Deleted: sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef

That's it folks, I hope this helped you understand the basics if docker. In our next tutorial we will be building more complex containers, creating different network configurations and configuring volumes.