Skip to content

Running PostgreSQL Instances as Containers with Podman

Avatar photo

https://www.linkedin.com/in/gineesh/ https://twitter.com/GiniGangadharan

PostgreSQL is a powerful, open-source relational database system widely used in modern applications. Running PostgreSQL as a container offers a range of benefits, particularly when using Podman, a rootless container engine. This post will guide you through the steps to set up PostgreSQL instances using Podman and systemd.

Why Run PostgreSQL as a Container?

Running PostgreSQL as a container has several advantages:

  1. Isolation: Each container runs independently, ensuring that libraries and dependencies are isolated from the host system and other containers.
  2. Portability: Containers can be easily moved between environments, such as development, staging, and production.
  3. Quick Deployment: Starting a new PostgreSQL instance is as simple as running a container, reducing setup time.
  4. Simplified Configuration: Containerized PostgreSQL uses environment variables for easy configuration.
  5. Rootless Execution: Podman allows running containers without requiring root privileges, enhancing security.

Advantages of Using Podman with Systemd

Integrating Podman containers with systemd adds the following benefits:

  1. Automatic Startup: Containers can be configured to start automatically with the system.
  2. Service Management: Systemd enables familiar service management commands like start, stop, and status.
  3. Reliability: Systemd can restart failed containers automatically.
  4. Resource Isolation: With cgroups, systemd can manage resource limits for containers.

Disclaimer

The steps and configurations provided in this article are intended for demonstration and educational purposes only. Users must carefully consider the following before deploying PostgreSQL containers in any environment:

  • Storage Backend: Ensure proper planning and management of storage backend and volume data, just like any critical application storage system.
  • System Resources: Evaluate the system’s resource capacity (CPU, memory, disk I/O) before deploying multiple container instances on a single machine to avoid resource exhaustion.
  • Production Readiness: This is an opinionated approach, and it is the user’s responsibility to implement all necessary production-level configurations, including security, monitoring, and high availability.
  • Sensitive Information: Handle sensitive information, such as passwords and credentials, with care. Avoid hardcoding credentials in container definitions, scripts, or environment files.

The author is not responsible for any data loss, performance issues, or security vulnerabilities arising from improper implementation of the concepts discussed in this article. Proceed at your own discretion and ensure thorough testing before deploying to production environments.

Setting Up PostgreSQL as a Container with Podman

Follow these steps to run PostgreSQL instances with Podman and systems. If you are installing Podman for the first time, refer to this guide – Installing Podman on Red Hat Enterprise Linux 9.

Step 1: Pull the PostgreSQL Container Image

The PostgreSQL image from the container registry provides a secure and optimized database engine. Pull the image:

podman pull postgres:latest

Alternatively, you can use the official image registry.redhat.io/rhel8/postgresql-15:latest from Red Hat’s container registry which provides a secure and optimized database engine. Remember, you need to authenticate before pulling an image from Red Hat container registry.

Step 2: Run the First PostgreSQL Container

Alternatively, you can use the podman-compose command to quickly spin up containers with volumes and networks without worrying about command line arguments as shown in the following sections. Refer to the sample podman-compose.yaml file in this repository.

Step 2.1: Create a volume for the PostgreSQL server

If you don’t specify a volume, the PostgreSQL data stored in /var/lib/postgresql/data/ will be lost once the container is stopped or removed. To ensure data persistence, it’s essential to mount a volume for the PostgreSQL data store. You can either use a local directory from your host system or create a dedicated container volume to store the data securely.

Note: You can also mount the local directory path to the container without creating a Podman volume if there is a requirement.

Create a container volume as follows.

$ podman volume create postgresapp1
postgresapp1

Verify the volume details.

$ podman volume inspect postgresapp1
[
     {
          "Name": "postgresapp1",
          "Driver": "local",
          "Mountpoint": "/home/devops/.local/share/containers/storage/volumes/postgresapp1/_data",
          "CreatedAt": "2025-01-07T13:32:15.964258532Z",
          "Labels": {},
          "Scope": "local",
          "Options": {},
          "MountCount": 0,
          "NeedsCopyUp": true,
          "NeedsChown": true,
          "LockNumber": 36
     }
]

Step 2.2: Create a secret to store PostgreSQL admin password

It is possible to pass the sensitive information via environment variables but we are using the Podman secret to store the PostgreSQL admin password as follows.

$ echo "postgresadmin" | podman secret create postgresql_app1_admin_password -

Verify the secret using to ensure the secret it created.

$ podman secret inspect postgresql_app1_admin_password
[
    {
        "ID": "0dd142faa2448d107d8849145",
        "CreatedAt": "2025-01-07T13:27:10.295864132Z",
        "UpdatedAt": "2025-01-07T13:27:10.295864132Z",
        "Spec": {
            "Name": "postgresql_app1_admin_password",
            "Driver": {
                "Name": "file",
                "Options": {
                    "path": "/home/devops/.local/share/containers/storage/secrets/filedriver"
                }
            },
            "Labels": {}
        }
    }
]

Step 2.3: Start a PostgreSQL contaner

Create and run the first PostgreSQL instance with the container name postgresql-app1:

Important: Make sure you are using the available ports and not conflicting with the existing port. For example, you can use a custom port such as 5433 or 5434 as the host port to avoid any port conflicts.

$ podman run -d \
  --name postgresql-app1 \
  --secret postgresql_app1_admin_password,type=env,target=POSTGRES_PASSWORD \
  -v postgresapp1:/var/lib/pgsql/data:Z \
  -p 5433:5432 \
  postgres:latest 

Here:

  • 5433:5432 maps the container’s PostgreSQL port to the host.
  • postgresapp1 is the container volumes for database storage.
  • POSTGRES_PASSWORD is the superuser password; mapped from Podman secret postgresql_app1_admin_password

Step 2.4: Verify the PostgreSQL container

$ podman ps
CONTAINER ID  IMAGE                              COMMAND     CREATED         STATUS         PORTS                             NAMES
45d65f183c3e  docker.io/library/postgres:latest                                                 postgres              About a minute ago  Up About a minute  0.0.0.0:5433->5432/tcp, 5432/tcp  postgresql-app1

Step 3: Generate a Systemd Service File

Generate a systemd service file for the container:

$ mkdir -p ~/.config/systemd/user
$ podman generate systemd --new --name postgresql-app1 > ~/.config/systemd/user/postgresql-app1.service

Step 4: Enable and Start the Service

Enable and start the systemd service for the container under the specific user:

$ systemctl --user daemon-reload
$ systemctl --user enable postgresql-app1.service
$ systemctl --user start postgresql-app1.service

Verify the status:

$ systemctl --user status postgresql-app1.service

Step 6: Testing systemd service – stop and start PostgreSQL Containers

Let us experiment with the systemd service for PostgreSQL – stop and service and check if the PostgreSQL container is running.

$ systemctl --user stop postgresql-app1.service
$ podman ps
CONTAINER ID  IMAGE       COMMAND     CREATED     STATUS      PORTS       NAMES

Now, start back the systemd service and verify the if PostgreSQL container is running.

$ systemctl --user start postgresql-app1.service
$ podman ps
CONTAINER ID  IMAGE                              COMMAND     CREATED        STATUS        PORTS                             NAMES
c8b819776241  docker.io/library/postgres:latest                                                 postgres              2 seconds ago  Up 3 seconds   0.0.0.0:5433->5432/tcp, 5432/tcp  postgresql-app1

Step 7: Verify PostgreSQL Instances

Now our PostgreSQL instance should now be running:

Install the psql utility coming with the PostgreSQL package. (You can also use alternative utilities)

$ sudo yum install postgresql

Access the PostgreSQL instance: psql -h localhost -p 5432 -U admin -d appdb

$ psql -h localhost -p 5433 -U postgres --password
Password: 
psql (13.18, server 17.2 (Debian 17.2-1.pgdg120+1))
WARNING: psql major version 13, server major version 17.
         Some psql features might not work.
Type "help" for help.

postgres=# 

Step 8: Verify PostgreSQL access from outside of the machine

Ensure the required ports are open and enabled – in this case the custom port 5433.

$ sudo firewall-cmd --list-all
$ sudo firewall-cmd --permanent --add-port=5433/tcp
$ sudo firewall-cmd --reload
$ sudo firewall-cmd --list-ports

Now, you can repeat the steps with different container names, ports and systemd services to run multiple isolated PostgreSQL instances.

Conclusion

Running PostgreSQL as a container using Podman provides portability, isolation, and ease of management. Integrating with systemd further enhances reliability and automation. By following the steps above, you can efficiently run and manage multiple PostgreSQL instances on the same host, leveraging the robust features of Podman and Red Hat’s trusted container images.

Disclaimer:

The views expressed and the content shared in all published articles on this website are solely those of the respective authors, and they do not necessarily reflect the views of the author’s employer or the techbeatly platform. We strive to ensure the accuracy and validity of the content published on our website. However, we cannot guarantee the absolute correctness or completeness of the information provided. It is the responsibility of the readers and users of this website to verify the accuracy and appropriateness of any information or opinions expressed within the articles. If you come across any content that you believe to be incorrect or invalid, please contact us immediately so that we can address the issue promptly.

Avatar photo


https://www.linkedin.com/in/gineesh/ https://twitter.com/GiniGangadharan
Gineesh Madapparambath is the founder of techbeatly and he is the co-author of The Kubernetes Bible, Second Edition. and the author of 𝗔𝗻𝘀𝗶𝗯𝗹𝗲 𝗳𝗼𝗿 𝗥𝗲𝗮𝗹-𝗟𝗶𝗳𝗲 𝗔𝘂𝘁𝗼𝗺𝗮𝘁𝗶𝗼𝗻. He has worked as a Systems Engineer, Automation Specialist, and content author. His primary focus is on Ansible Automation, Containerisation (OpenShift & Kubernetes), and Infrastructure as Code (Terraform). (aka Gini Gangadharan - iamgini.com)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.