
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.