Intro

Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. With Docker, you can manage your infrastructure in the same ways you manage your applications. By taking advantage of Docker’s methodologies for shipping, testing, and deploying code, you can significantly reduce the delay between writing code and running it in production.

Prerequisites

  • A server running Ubuntu 20.04 or later
  • A user with sudo privileges

Development Environment

  • Ubuntu 20.04 LTS
  • Docker version 27.1.1, build 6312585

Steps

Step 1: Installing Docker

The Docker package is included in the default Ubuntu repositories. However, it may not always be the latest version. The recommended approach is to install Docker from the official Docker repository. To do this, we will need to add the Docker repository, the GPG key, and then install the Docker package.

First, update your existing list of packages:

sudo apt update

Install the required packages to allow apt to use a repository over HTTPS:

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

Then add the Docker GPG key:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Add the Docker repository to APT sources:

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

Update the package database with the Docker packages from the newly added repository:

sudo apt update

Make sure you are about to install from the Docker repository instead of the default Ubuntu repository:

apt-cache policy docker-ce

You should see output similar to this:

docker-ce:
  Installed: (none)
  Candidate: 5:27.1.1-1~ubuntu.20.04~focal
  Version table:
     5:27.1.1-1~ubuntu.20.04~focal 500
        500 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages
     5:27.1.0-1~ubuntu.20.04~focal 500
        500 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages

apt cache policy docker-ce

ⓘ NOTE
Notice that docker-ce is not installed, but the candidate for installation is from the Docker repository for Ubuntu 20.04 (focal). The docker-ce version number might be different.

Finally, install Docker:

sudo apt install docker-ce

Once the installation is complete, check the version.

docker --version

You should see output similar to this, showing the Docker version number:

Docker version 27.1.1, build 6312585

docker version

Now check the status of the Docker service:

sudo systemctl status docker

You should see output similar to this, showing that the service is active and running:

● docker.service - Docker Application Container Engine
     Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2024-08-09 20:00:54 CST; 3h 18min ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 2545366 (dockerd)
      Tasks: 7
     Memory: 35.4M
     CGroup: /system.slice/docker.service
             └─2545366 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Aug 09 20:00:52 yume systemd[1]: Starting Docker Application Container Engine...
Aug 09 20:00:53 yume dockerd[2545366]: time="2024-08-09T20:00:53.219520920+08:00" level=info msg="Starting up"
Aug 09 20:00:53 yume dockerd[2545366]: time="2024-08-09T20:00:53.233981841+08:00" level=info msg="detected 127.0.0.53 nameserver, assu>Aug 09 20:00:53 yume dockerd[2545366]: time="2024-08-09T20:00:53.587673152+08:00" level=info msg="Loading containers: start."
Aug 09 20:00:54 yume dockerd[2545366]: time="2024-08-09T20:00:54.086716963+08:00" level=info msg="Loading containers: done."
Aug 09 20:00:54 yume dockerd[2545366]: time="2024-08-09T20:00:54.195641146+08:00" level=warning msg="WARNING: No swap limit support"
Aug 09 20:00:54 yume dockerd[2545366]: time="2024-08-09T20:00:54.196219187+08:00" level=info msg="Docker daemon" commit=cc13f95 contai>Aug 09 20:00:54 yume dockerd[2545366]: time="2024-08-09T20:00:54.196382621+08:00" level=info msg="Daemon has completed initialization"
Aug 09 20:00:54 yume dockerd[2545366]: time="2024-08-09T20:00:54.322659066+08:00" level=info msg="API listen on /run/docker.sock"
Aug 09 20:00:54 yume systemd[1]: Started Docker Application Container Engine.
lines 1-21/21 (END)

docker daemon

Step 2: Using Docker as a Non-Root User (Optional)

By default, Docker requires administrator privileges to run.

when you run the docker command, you will get an error like this:

docker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Head "http://%2Fvar%2Frun%2Fdocker.sock/_ping": dial unix /var/run/docker.sock: connect: permission denied.
See 'docker run --help'.

docker: permission denied

To avoid having to use sudo with every Docker command, add your user to the Docker group:

sudo usermod -aG docker ${USER}

Then logout and log back in so that your group membership is re-evaluated. or you can run the following command:

su - ${USER}

You will be prompted to enter your user’s password to continue.

or apply the new group membership by running:

newgrp docker

or you can reboot your system:

sudo reboot

Check that your user is now added to the Docker group by running:

groups

or

id -nG

You should see docker in the list of groups for your user:

Output:

hiiruki sudo docker

groups

To add another user to the Docker group that you’re not currently logged in as, run the following command:

sudo usermod -aG docker `username`

Step 3: Testing Docker

Now that Docker is installed, let’s run a simple container to test it.

Run the following command:

docker run hello-world

If it works, you will see the following output:

hiiruki@yume:~$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete 
Digest: sha256:1408fec50309afee38f3535383f5b09419e6dc0925bc69891e79d84cc4cdcec6
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://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

docker run hello-world

ⓘ NOTE
If you see the Unable to find image 'hello-world:latest' locally message, it means that the hello-world image was not found on your local system. Docker then pulled the image from the Docker Hub, which is the default repository for Docker images.

Step 4: Docker Compose

Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.

Docker Compose is already included in the Docker package that we installed earlier. To check the version, run:

docker compose version

You should see output similar to this, showing the Docker Compose version number:

Docker Compose version v2.29.1

docker compose version

Operation Check

Now, let’s start a web server with nginx to check the operation. Prepare three files: Dockerfile, compose.yaml, and src/index.html

The project structure should look like this:

ⓘ NOTE
composetest is just an example, you can use any name for the directory.

composetest/
├── Dockerfile
├── compose.yaml
└── src
    └── index.html

Before creating the files, create the composetest directory and navigate to it:

mkdir composetest
cd composetest
Dockerfile

The image we will use is from the nginx official image nginx:1.26.1-alpine-slim

Create a file named Dockerfile

nano Dockerfile

and add the following content:

FROM nginx:1.26.1-alpine-slim
COPY ./src/index.html /usr/share/nginx/html
compose.yaml

Compose simplifies the control of your entire application stack, making it easy to manage services, networks, and volumes in a single, comprehensible YAML configuration file.

Create a file called compose.yaml in your project directory

nano compose.yaml

and paste the following:

services:
  nginx:
    build: ./
    image: web-server:1.0.0
    container_name: web-server
    ports:
      - 1337:80

Explanation:

This compose.yaml file defines a single service named nginx. Docker Compose will build a Docker image from the current directory and tag it as web-server:1.0.0. It then creates a container named web-server, which exposes port 80 of the container to port 1337 on the host machine.

src/index.html

Create a directory named src and navigate to it:

mkdir src
cd src

create a file named index.html:

nano index.html

This is the page that will displayed when you access the web address. For the tutorial, I will use a simple HTML file:

<!DOCTYPE html>
<html>
<head>
    <title>Docker Compose Test</title>
</head>
<body>
    <h1>Hello World!</h1>

    <h2>This file is served by nginx running in a Docker container.</h2>
</body>
</html>
Build and Run

Now that you have created the necessary files, you can build and run the Docker container using Docker Compose.

Navigate back to the composetest directory:

cd ..

Run the following command to build the Docker image and start the container:

docker compose up -d --build

You should see output similar to this:

docker compose up

To check the status of the container, run:

docker ps

You should see output similar to this, showing that the container is running:

CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS          PORTS                                   NAMES
f3c369713e9f   web-server:1.0.0   "/docker-entrypoint.…"   12 seconds ago   Up 11 seconds   0.0.0.0:1337->80/tcp, :::1337->80/tcp   web-server

docker ps

Now, open your web browser and navigate to http://your_server_ip:port. You should see the index.html page that you created earlier.

web page

Containerize all the things!

Containerize all the things!

References