Page
Use Podman Quadlets to manage Flask stack containers as system services
Quadlets are a specific type of configuration file that Podman uses to automatically create systemd service files. Instead of writing complex scripts to manage container lifecycles, you write a .container file that functions like a standard Red Hat® Enterprise Linux® configuration file. You will also configure the AutoUpdate setting so the containers can update automatically without requiring an OS reboot.
Prerequisites:
- Create and run a Flask application locally.
- Your application and NGINX proxy configuration files are in the
flaskdev-hardenedproject directory.
In this lesson, you will:
- Configure the pod, storage, and PostgreSQL container Quadlets.
- Configure the Flask application container.
- Configure the NGINX container as a web proxy.
Use Podman Quadlets to manage containers as system services
Before you configure Quadlets to manage your containers as system services through systemd, first create the directory flaskdev-hardened/quadlets where you will keep your Quadlet configuration files:
mkdir flaskdev-hardened/quadlets Step 1: Configure the pod Quadlet
A Podman pod groups your three containers into a single logical unit. All containers in the pod share the same network namespace, so they communicate on localhost rather than by container hostname. Port 8080 is published once at the pod level, not on any individual container. Place the following in the file flaskdev-hardened/quadlets/flask.pod:
[Pod]
PublishPort=8080:8080Step 2: Configure the storage Quadlet
This configuration file explicitly declares the volume as a systemd-managed resource, giving you an explicit dependency chain. If you later modify your application to use separate storage for your database, this file is where you will specify the storage location. Create the file flaskdev-hardened/quadlets/db-data.volume with the following contents:
[Volume]
# This defines a persistent location for our database files. Step 3: Configure the PostgreSQL container Quadlet
The following Quadlet runs your database. Note the Requires= and After= lines; they tell Red Hat Enterprise Linux to run the secrets setup service first, so the database password is ready before the container starts. Place the following contents in the file flaskdev-hardened/quadlets/postgresql.container:
[Unit]
Description=PostgreSQL database
Requires=flask-secrets.service
After=flask-secrets.service
[Container]
Image=registry.access.redhat.com/hi/postgresql:latest
ContainerName=postgresql
Pod=flask.pod
Volume=db-data.volume:/var/lib/postgresql/data:Z
Environment=POSTGRES_USER=appuser
Environment=POSTGRES_DB=hellodb
Secret=postgres_password,type=env,target=POSTGRES_PASSWORD
# Enable independent updates without a full OS reboot
AutoUpdate=registry
[Service]
Restart=always
TimeoutStartSec=30
[Install]
WantedBy=multi-user.target default.targetStep 4: Configure the Flask application container
This runs the Python logic you wrote in the previous lesson. It waits for the database to be up before it starts. Place this content in the file flaskdev-hardened/quadlets/flask-app.container:
[Unit]
Description=Flask application (Gunicorn)
After=postgresql.service
Requires=postgresql.service
[Container]
# YOUR_USERNAME is the name of your quay.io account
Image=quay.io/YOUR_USERNAME/flask-runtime:latest
ContainerName=flask-app
Pod=flask.pod
Volume=/srv/app:/app:z
Environment=DB_HOST=localhost
Environment=DB_USER=appuser
Environment=DB_NAME=hellodb
Secret=postgres_password,type=env,target=DB_PASS
AutoUpdate=registry
[Service]
Restart=always
TimeoutStartSec=30
[Install]
WantedBy=multi-user.target default.targetStep 5: Configure the NGINX container as a web proxy
Configures NGINX to serve traffic and proxy to Flask. Place the following content in the file flaskdev-hardened/quadlets/nginx.container:
[Unit]
Description=NGINX reverse proxy (Red Hat Hardened Image)
Requires=flask-app.service
After=flask-app.service
[Container]
Image=registry.access.redhat.com/hi/nginx:latest
ContainerName=nginx
Pod=flask.pod
Volume=/etc/nginx/conf.d:/etc/nginx/conf.d:Z,ro
# Enable independent updates without a full OS reboot
AutoUpdate=registry
[Service]
Restart=always
[Install]
WantedBy=multi-user.target default.targetStep 6: Test and verify
Before deploying the Quadlets into a permanent Red Hat Enterprise Linux image, you must verify the syntax. Podman includes a tool that simulates the conversion from a Quadlet file to a standard systemd service.
Open your terminal in the folder where you saved your .pod, .container, and .volume files. Run the following command:
QUADLET_UNIT_DIRS=$(pwd) /usr/lib/systemd/system-generators/podman-system-generator --dryrunThe tool will output configuration text. Look for the ExecStart lines. If you see ExecStart=/usr/bin/podman run ..., Podman successfully processed your request. It mapped your volumes, pod, and environment variables into a format Red Hat Enterprise Linux uses during boot. If the output is empty or shows an error, a path is likely incorrect or a bracket is missing.
Success! You've configured the Podman Quadlets to tell the operating system how to manage your containers. Next, you will package the application and operating system into a verified image.