How To Install and Use Docker on Ubuntu 20.04/22.04 LTS

Install and Use Docker on Ubuntu 20.04/22.04 lts

Introduction

Docker, as a programme, simplifies the administration of application processes in containers, allowing you to execute your apps in resource-isolated processes. Containers are comparable to virtual machines, except they are more portable, resource-friendly, and dependent on the host operating system.

This article will walk you through installing and configuring Docker Community Edition (CE) on Ubuntu 20.04 and 22.04 LTS. You will first install Docker, then handle containers and images before storing an image in a Docker Repository.

Prerequisites

You will need the following things to follow this guide:

  • Set up one Ubuntu 20.04 or 22.04 LTS server.
  • Have an account on Docker Hub if you prefer to make images on your own and push them to Docker Hub, as you’ll see in Steps 7 and 8 of this guide.

Step 1: Install Docker

The Docker installation package offered in the official Ubuntu repository is unlikely to be the most recent version. To ensure that we obtain it, we’ll install Docker from the official Docker repository. We’ll be introducing a new package source for this, so install the package after adding the GPG key from Docker to ensure the downloads’ validity.

Before you begin, you must update your existing list of packages:

$ sudo apt-get update

Next, to enable apt to use packages over HTTPS, you will need to install a few prerequisite packages:

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

Now add the GPG key to your system’s official Docker repository:

$ sudo mkdir -p /etc/apt/keyrings
$  curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

Now add the Docker repository to APT sources:

$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Go ahead now and update the package database using the the newly added repo’s Docker packages:

$ sudo apt-get update

Now the last thing in this step is to install Docker:

$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Docker is now installed, the daemon is running, and the process is set to start on boot. Verify that it’s running:

$ sudo systemctl status docker

The output should show that the service is active and running and should look something like the following:

root@ServerB:/home/ubuntu# systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2022-07-28 09:49:02 UTC; 8min ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 6958 (dockerd)
      Tasks: 8
     Memory: 30.2M
        CPU: 1.276s
     CGroup: /system.slice/docker.service
             └─6958 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

You now have the Docker service (daemon) as well as the docker command line program, commonly known as the Docker client, after installing Docker. Later in this article, we will learn how to utilize the docker command.

Step 2: Execute the Docker Command Without Sudo (Not Mandatory).

The docker command may only be executed by the root user or a member of the docker group, which is created by default during the Docker installation process. If you try to run the docker command without prefixing it with or being a member of the docker group, the output will look like this:

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json": dial unix /var/run/docker.sock: connect: permission denied

To avoid having to type sudo everytime you run the docker command, you need to add your username to the docker group:

$ sudo usermod -aG docker ${USER}

Log out of the server and back in or type the following in order to apply the new group membership:

$ su - ${USER}

You will be prompted to enter your user password before proceeding:

Type the following to confirm that your user is now added to the docker group:

$ id -nG
ubuntu adm cdrom sudo dip plugdev lxd docker

When needed, you can explicitly declare the username of the user you need to add to the docker group that you’re not logged in as, through using:

$ sudo usermod -aG docker username

The rest of this guide is based on the fact that you are running the docker command as a user in the docker group. If you prefer not to, go ahead and prepend the commands with sudo.

Step 3: Use the Docker Command

The use of docker means passing it on a chain of options and commands after which will come arguments. The syntax looks like the following:

$ docker [option] [command] [arguments]
$ docker -v
ubuntu@ServerB:~$ docker -v
Docker version 20.10.17, build 100c701

To visualize all of the available subcommands, type:

$ docker

The full list of all possible subcommands includes:

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

To visualize the options possible for a specific command, type:

$ docker docker-subcommand --help

To visualize the system-wide information regarding Docker, type:

$ docker info

In this next step we will be exploring some of these images.

Step 4: Handling Docker Images

Images created with Docker are used to create containers. By default, Docker fetches these images from Docker Hub, which is a Docker registry managed by Docker. Because anybody may use Docker Hub to publish their images, the great majority of apps and Linux distributions will have images uploaded there.

To verify if you have access and can download the images found on Docker Hub, type:

$ docker run hello-world

The following output will tell you that Docker is correctly functioning:

ubuntu@ServerB:~$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:53f1bbee2f52c39e41682ee1d388285290c5c8a76cc92b42687eecf38e0af3f0
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
...

Docker was at first not able to find the hello-world image locally, so it proceeded to download it from Docker Hub, which is the default repository. Once the image has been downloaded, Docker created a container from it and had the application inside the container executed, while eventually displaying the message.

You can find the images that are available on Docker Hub by using the docker command and the search subcommand. For example, to find the Ubuntu image you should type:

$ docker search ubuntu

The script will go over Docker Hub and view a list of all images whose name match the search request. In this case, the output will look something like the following:

ubuntu@ServerB:~$ docker search ubuntu
NAME                             DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
ubuntu                           Ubuntu is a Debian-based Linux operating sys…   14664     [OK]
websphere-liberty                WebSphere Liberty multi-architecture images …   286       [OK]
ubuntu-upstart                   DEPRECATED, as is Upstart (find other proces…   112       [OK]
neurodebian                      NeuroDebian provides neuroscience research s…   92        [OK]
ubuntu/nginx                     Nginx, a high-performance reverse proxy & we…   55
open-liberty                     Open Liberty multi-architecture images based…   53        [OK]
ubuntu-debootstrap               DEPRECATED; use "ubuntu" instead                46        [OK]
ubuntu/apache2                   Apache, a secure & extensible open-source HT…   39
ubuntu/mysql                     MySQL open source fast, stable, multi-thread…   36
kasmweb/ubuntu-bionic-desktop    Ubuntu productivity desktop for Kasm Workspa…   31
...

Once you picked the image that you’ll be using, you can download it to your computer with the pull subcommand.

$ docker pull ubuntu

The output you’ll get will look like this:

ubuntu@ServerB:~$ docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
405f018f9d1d: Pull complete
Digest: sha256:b6b83d3c331794420340093eb706a6f152d9c1fa51b262d9bf34594887c2c7ac
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest

After an image has been downloaded, you can then run a container using the downloaded image with the run subcommand. As you saw with the hello-world example, if an image has not been downloaded when docker is executed with the run subcommand, the Docker client will first download the image, then run a container using it.

To view the images that have been downloaded to your computer, type the following:

$ docker images

The output will look something like this:

ubuntu@ServerB:~$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
ubuntu        latest    27941809078c   7 weeks ago     77.8MB
hello-world   latest    feb5d9fea6a5   10 months ago   13.3kB

You will later see in this tutorial how you can modify the images you use to run containers and use them to generate new images which may then be inserted (pushed is the technical term) into Docker Hub or other Docker registries.

Step 5: Running a Container in Docker

The hello-world container which you ran in the last step is an example of a container that, after emitting a test message, will run and exit. Containers can be more useful than this, as well as interactive. They function somewhat like virtual machines, only difference is that they’re more resource-friendly.

As an example, let’s run a container and use the most recent image of Ubuntu. The combination of the -i and -t switches will give you interactive shell access into the container:

$ docker run -it ubuntu

Your command prompt should be reformulated to show that you’re now working inside the container and should look like this:

ubuntu@ServerB:~$ docker run -it ubuntu
root@a9bb67c47592:/#

Look closely at the container id in the command prompt which is a9bb67c47592 in here. That container ID is later necessary to identify the container when you want to delete it.

Now you can run any command inside the container. For instance, when updating the package database inside the container you will not need to prefix any command with sudo, because you’re operating inside the container as the root user:

root@a9bb67c47592:/# apt update

Now let’s go ahead and install any application in it, Node.js for instance:

root@a9bb67c47592:/# apt install nodejs

This will install Node.js in the container found in the official Ubuntu repository. Once installed, verify that through:

root@a9bb67c47592:/# node -v

The version number will be displayed in your terminal:

v12.22.9

All the changes you make inside the container will only apply to that container.

Type exit at the prompt to exit the container.

Step 6: Managing Containers in Docker

Once you have been on Docker for some time, you’ll notice that there are many active (running) and inactive containers on your computer. To visualize the active ones, use:

$ docker ps

The output you’ll get is similar to this:

ubuntu@ServerB:~$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

You started two containers so far in the previous steps; one from the hello-world image and the second from the ubuntu image. Both of them are no longer running, but they’re still on your system.

To visualize both active and inactive containers , run docker ps with the -a switch:

$ docker ps -a

You’ll get a similar output:

ubuntu@ServerB:~$ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                        PORTS     NAMES
a9bb67c47592   ubuntu        "bash"     6 minutes ago    Exited (127) 27 seconds ago             magical_shirley
ee421c96d926   hello-world   "/hello"   30 minutes ago   Exited (0) 30 minutes ago               wonderful_raman

Pass the -l switch to visualize the last container you created:

$ docker ps -l
ubuntu@ServerB:~$ docker ps -l
CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS                        PORTS     NAMES
a9bb67c47592   ubuntu    "bash"    15 minutes ago   Exited (127) 10 minutes ago             magical_shirley

Use docker start to start a stopped container, followed by the ID of the container or its name. Let’s start the one which is Ubuntu-based with the ID of a9bb67c47592:

$ docker start a9bb67c47592

You can use docker ps to see the container status once it starts:

ubuntu@ServerB:~$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED          STATUS              PORTS     NAMES
a9bb67c47592   ubuntu    "bash"    23 minutes ago   Up About a minute             magical_shirley

Use docker stop to stop a running container, followed by its ID or name. This time, we’ll be using the name that Docker assigned to the container, which is quizzical_mcnulty:

$ docker stop magical_shirley

When you no longer need a container, you can remove it with the docker rm command, this time as well, using either the container ID or its name. Use the docker ps -a command to find the name or ID of the container that is associated with the hello-world image and delete it.

$ docker rm wonderful_raman

You can create a new container and name it using the --name switch. It is also possible to use the --rm switch to start a container that deletes itself when it gets stopped. See the docker run help command for more information on these options and other ones.

I can transform containers into images, which can be used to build new containers.

Step 7: Bringing Changes Inside a Container to an Image on Docker

You can create, modify, and delete files just like with a virtual machine when you start up a Docker image. The changes that you make will apply to that one container only. I can start and stop it, but when I use the docker rm command to destroy it, the changes are permanently lost.

This part will show you how you can save a container’s state as a new Docker image.

Once you installed Node.js in the Ubuntu container, you now have one which runs off an image, but the container is not the same as the image that you used to make it. But you might want to use this Node.js container another time as the foundation for new images later on.

Then make the changes to a new Docker image instance with the following command.

$ docker commit -m "What you did to the image" -a "Author Name" container_id repository/new_image_name

The -m switch is related to the commit message, which helps you and others identify the changes you made, however -a is used to specify the author. The container_id is the one you saw earlier in this guide when you launched the interactive Docker session. The repository is usually your Docker Hub username, unless you create new repositories on Docker Hub.

For instance, for the user ubuntu whose container ID is a9bb67c47592, the command would be:

$ docker commit -m "added Node.js" -a "ubuntu" a9bb67c47592 ubuntu/ubuntu-nodejs

After I commit the image, I will have a new one saved locally on my computer. You’ll later learn in this guide how to push an image to a Docker registry like Docker Hub, so other people can have access to it.

Listing the Docker images again will visualise both the new and old ones that they came from:

$ docker images

You’ll see the following output:

ubuntu@ServerB:~$ docker images
REPOSITORY             TAG       IMAGE ID       CREATED         SIZE
ubuntu/ubuntu-nodejs   latest    45f8857f0719   9 seconds ago   197MB
...

In this case, ubuntu-nodejs is the new image which was extracted from the existing ubuntu image from Docker Hub. The difference in size reflects the edits that I made. And the change I made is that NodeJS got installed. Therefore, the next time you will need to run a container with Ubuntu with NodeJS pre-installed, you can just use the new image.

You can also create Images from a Dockerfile which lets you automate the installation of software within a new image. However, this is unrelated to this guide.

Step 8: Pushing a Docker Image to a Docker Repository

The next obvious step after creating a new image from an existing one is to share it with a few people you select, the wide public on Docker Hub, or other Docker registry that you can access. To push an image to Docker Hub or any other Docker registry, you need to have an account there.

To do that, you need to first log into Docker Hub.

$ docker login -u docker-registry-username

I will authenticate using your Docker Hub password. 

Note: If your Docker registry username differs from the local username you used to create the image, you will need to tag your image with your registry username. In the case of the last example, you would type:

$ docker tag ubuntu/ubuntu-nodejs docker-registry-username/ubuntu-nodejs

Then you will be able to push your own image using:

$ docker push docker-registry-username/docker-image-name

To push the ubuntu-nodejs image into the ubuntu repository, use the following command:

$ docker push ubuntu/ubuntu-nodejs

Be patient as the process takes time while it uploads the images, but when completed, the output will be similar to this:

The push refers to a repository [docker.io/ubuntu/ubuntu-nodejs]
e3fbbfb44187: Pushed
5f70bf18a086: Pushed
a3b5c80a4eba: Pushed
7f18b442972b: Pushed
3ce512daaf78: Pushed
7aae4540b42d: Pushed
...

If there is any an error of this sort, then it is possibly because you did not log in:

The push refers to a repository [docker.io/ubuntu/ubuntu-nodejs]
e3fbbfb44187: Preparing
5f70bf18a086: Preparing
a3b5c80a4eba: Preparing
7f18b442972b: Preparing
3ce512daaf78: Preparing
7aae4540b42d: Waiting
unauthorized: authentication required

Log in with docker login and restart the pushing process again. Then verify that it is indeed on your Docker Hub repository page.

It is now possible for you to use docker pull ubuntu/ubuntu-nodejs to pull the image to a new machine and run a new container.

LEAVE A COMMENT