We can all agree that in this era the concept of containerization is almost everywhere. This technology was mainly started to curb the complexity of applications and infrastructure which were resource intensive and very expensive. With containerization, an application is bundled with all the required dependencies in a lightweight executable referred to as a container. This makes it easier to run and maintain the application. Containerization offers a lot of features and benefits such as portability, scalability, isolation, efficiency, simplified deployment and management, versioning and rollbacks etc.

There are quite a number of tools used to run containers, among them are Docker, Podman, Kubernetes, contained, CRI-O, rkt, LXC/LXD etc. In this guide, our main focus is on Podman and Docker.

Podman and Docker are container runtime platforms that hold a lot of similarities. They allow users to build, run, and manage containers. However, they possess some differences:

Docker is a popular and widely used tool that offers a complete ecosystem for container management using Docker Engine, Docker CLI, and Docker Compose. The key features of Docker are:

  • Dockerfile: This is a declarative configuration file that defines the steps required when building container images.
  • Docker Hub; It is a cloud-based registry that stores and helps you share the container images.
  • Docker CLI: Thi is a command-line tool that makes it possible to interact with the Docker daemon to build images, run containers and manage other container resources.
  • Docker Compose: This tool is used to run multiple container applications defined in a YAML file.

Podman is the short form of Pod Manager. This is an open-source container runtime that acts as a drop-in replacement for Docker. It is a component of a large container ecosystem, libpod, which provides other tools like Buildah and Skopeo. As opposed to Docker, Podman is daemonless. It doesn’t require a separate daemon to run containers as it interacts directly with the container runtime in the Linux kernel.

Podman Compose just like Docker Compose is used to run multiple containers defined in a declarative YAML file. In this guide, we will learn how to use Docker / Podman Compose on Debian 12 (Bookworm).

Install Docker / Podman Compose

Docker Compose relies on the Docker daemon to operate, while Podman Compose is designed to work with Podman. So use any of the tools, and ensure that the required container runtime is installed.

Once installed, verify with the command:

$ docker-compose version
Docker Compose version v2.18.1

Verify the installation with the command:

$ podman-compose version
['podman', '--version', '']
using podman version: 4.3.1
podman-composer version  1.0.3
podman --version 
podman version 4.3.1
exit code: 0

Now we are set to use Docker / Podman Compose on Debian 12 (Bookworm).

Using Docker / Podman Compose

Now Docker/Podman Compose can be used to perform several container management tasks. In this guide, we will cover some of the tasks that can be performed using Docker / Podman Compose.

To work with any of these tools, you need to have a declarative YAML file. The file can contain directives. The most popular ones are:

  • version: specifies the Docker / Podman Compose version to be used.
  • services: This is the name of the container. The section contains several other directives
  • networks: this is used to configure the application’s network. You can define the app-specific network
  • volumes: maps volumes on the host machine to the container

The services section contains many other directives, the common ones are:

  • image: specifies the images to be used by the container. This can be from the local registry or an external one like Docker Hub.
  • build: can be used in place of the image directive. This specifies the location of the Dockerfile used to build the image.
  • Name: this can be any name for the container for example web, db etc
  • restart: instructs the container to restart when the system restarts
  • volumes: this links the path on the host machine to the container
  • environment: all the environment variables for the container are declared here
  • depends_on: sets a dependency to another container.
  • port: used to expose container ports with the syntax host:container
  • links: links service to the other in the container using their names

Below is a sample YAML with all the above variables used:

version: '3'
services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:

In this guide, we will have a step-by-step demonstration of how to manage a container(s) using Docker / Podman Compose on Debian 12 (Bookworm).

a. Run a Single Application

We will start by demonstrating how to run a single container. First, create a YAML file:

vim docker-compose.yaml

In the file, declare the required directives. For this guide, we will run a simple Nginx container.

version: '3'
services:
  web:
    image: docker.io/library/nginx:latest
    container_name: Nginx
    ports:
      - "8080:80"
    volumes:
      - ./src:/usr/share/nginx/html
    environment:
      - NGINX_HOST=test.computingforgeeks.com
      - NGINX_port=80

Save the file and start the container:

##Docker Compose
 docker-compose up -d

##Podman Compose
 podman-compose up -d

Here, the image will be pulled and the container started. Verify if the container is running:

docker-compose ps
##OR
podman-compose ps

Sample output:

NAME                IMAGE               COMMAND                  SERVICE             CREATED              STATUS              PORTS
Nginx               nginx:latest        "/docker-entrypoint.…"   web                 About a minute ago   Up About a minute   0.0.0.0:8080->80/tcp, :::8080->80/tcp

That is it, the container is running. You can also use podman or docker commands:

$ podman ps
CONTAINER ID  IMAGE                              COMMAND               CREATED             STATUS             PORTS                   NAMES
378816ee13e2  docker.io/library/nginx:latest     nginx -g daemon o...  About a minute ago  Up About a minute  0.0.0.0:8080->80/tcp    Nginx
2aaa9e372e87  docker.io/library/postgres:latest  postgres              About a minute ago  Up About a minute  0.0.0.0:5432->5432/tcp  postgres_db

b. Run Multiple Services

The main purpose of Docker / Podman Compose is to run multiple containers at once. To achieve this, you need to declare the services in the YAML. Open the YAML:

vim docker-compose.yaml

Add the desired container, for example the database container:

version: '3'

services:
  web:
    image: docker.io/library/nginx:latest
    container_name: Nginx
    ports:
      - "8080:80"
    volumes:
      - ./src:/usr/share/nginx/html
    environment:
      - NGINX_HOST=test.computingforgeeks.com
      - NGINX_port=80

  database:
    image: docker.io/library/postgres:latest
    container_name: postgres_db
    volumes:
      - ./dumps:/tmp/
    environment:
      - POSTGRES_PASSWORD=Passw0rd!
    ports:
      - "5432:5432"

Run the containers:

##Docker Compose
docker-compose up -d

##Podman Compose
 podman-compose up -d

Check the status:

NAME                IMAGE                               COMMAND                  SERVICE             CREATED             STATUS              PORTS
Nginx               docker.io/library/nginx:latest      "/docker-entrypoint.…"   web                 11 minutes ago      Up 11 minutes       0.0.0.0:8080->80/tcp, :::8080->80/tcp
postgres_db         docker.io/library/postgres:latest   "docker-entrypoint.s…"   database            12 seconds ago      Up 11 seconds       0.0.0.0:5432->5432/tcp, :::5432->5432/tcp

Now we have two containers running. You can have as many containers as possible in the YAML.

c. Build and Use container image

Instead of pulling an image, you can build your own image and use it to run a container. But first, you need to have a Dockerfile created.

git clone https://github.com/docker/getting-started.git
cd getting-started/app
vim Dockerfile

Add the desired directives in the Dockerfile:

FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000

You can now create a docker-compose file that uses the Dockerfile:

$ vim docker-compose.yaml
version: '3'
services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: node_app
    ports:
      - 3000:3000

Build the image and start the container:

docker-compose up -d --build
##OR
podman-compose up -d --build

Sample Output:

Using Docker Podman Compose on Debian 12 Bookworm

View the status of the container:

NAME                IMAGE               COMMAND                  SERVICE             CREATED             STATUS              PORTS
node_app            app-web             "docker-entrypoint.s…"   web                 25 seconds ago      Up 24 seconds       0.0.0.0:3000->3000/tcp, :::3000->3000/tcp

d. Persistent Data Storage

Persistent data storage is used to store container data that survives after the container has been restarted. This is so important when running production deployments.

To declare persistent storage, the volumesdirective is used. For example, on our database container, we can add persistent storage as shown:

version: '3'

services:
  web:
    image: docker.io/library/nginx:latest
    container_name: Nginx
    ports:
      - "8080:80"
    volumes:
      - ./src:/usr/share/nginx/html
    environment:
      - NGINX_HOST=test.computingforgeeks.com
      - NGINX_port=80

  database:
    image: docker.io/library/postgres:latest
    container_name: postgres_db
    volumes:
      - data:/var/lib/postgresql
    environment:
      - POSTGRES_PASSWORD=Passw0rd
    ports:
      - "5432:5432"

volumes:
  data:
    external: true

Now in the above file, external: true instructs Docker/Podman to use an existing external volume. If the volume with the name data is not present, you might face errors starting the container.

So create the volume:

docker volume create --name=data
##OR
podman volume create data

Now start the container:

docker-compose up -d
##OR
podman-compose up -d

Once started, the volume will be used to persist data.

$ docker volume inspect data
[
    {
        "CreatedAt": "2023-06-21T07:58:36-04:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/data/_data",
        "Name": "data",
        "Options": null,
        "Scope": "local"
    }
]

e. Start, stop and Remove Containers

you can also start, stop and delete containers using Docker/Podman Compose. Below are the commands to use:

To stop and delete a container

docker-compose down

To stop and remove volumes:

docker-compose down -v

To start a container

docker-compose up -d

Verdict

That marks the end of this guide on how to use Docker / Podman Compose on Debian 12 (Bookworm). I hope you have learned something from this guide.

Are you interested in more articles?

LEAVE A REPLY

Please enter your comment!
Please enter your name here