Latest Thinking

Beyond Kubernetes: Podman + Quadlet for Lean, Reliable Containers

Written by Shannon McKenna | 4 Aug, 2025

Since the release of v1.0 ten years ago, Kubernetes (K8S) has redefined how we manage applications and services at scale and with it, our expectations around workload reliability. Four years later Podman v1.0.0 was released, building on the lessons of K8S to offer a more secure and daemonless alternative to Docker. Fast forward to 2023, Podman v4.4.0 quietly introduced a powerful new feature called "Quadlet": a systemd generator capable of consuming native Kubernetes YAML to produce reliable systemd services.

Despite its potential, the combination of Podman + Quadlet has largely flown under the radar. In this article, we'll put a spotlight on where it fits best - specifically in environments where K8S isn't feasible. We'll walk through practical use cases and demonstrate how to deploy and manage a containerised service using a simple Ansible role and the open-source thinkst/opencanary project.

All the code from the examples shown below is available here: https://github.com/pasdesignal/quadlet-role-opencanary

Why Podman + Quadlet?

We won’t justify the use of containers here. Managing applications as declarative container code is simply the modern baseline. But running those containers on Kubernetes isn't always possible or even desirable. Many organisations have network zones such as as DMZs or edge segments, where K8S cannot be deployed.  Others operate at a scale or complexity that doesn't justify a full orchestration platform.

Here are some examples of where Podman containers, running as systemd-managed services can provide a sensible and powerful alternative:

  • Small environments or teams, where the investment in K8S is not justified
  • DMZ or edge networks, where K8S nodes are unable to operate
  • Environments without (or not yet ready for) K8S
  • Embedded / System-on-Chip (SoC) solutions 
  • Containerised agents

What is Quadlet?

Quadlet is a tool for running Podman containers under systemd, using declarative code that are much simpler than traditional systemd unit files.

Without Quadlet, a systemd unit for a process running with Podman might look like this. Notice the convoluted ExecStart line:

Maintaining and even understanding this requires knowledge of both podman run syntax and systemd conventions.

With Quadlet, that same service becomes dramatically simpler:

The[Kube] section references a standard K8S-style pod definition, canary.yml:

One of Podman's powerful features is 'play kube', which interprets this K8S YAML and creates the required containers, pods or volumes accordingly. Quadlet extends this feature to generate systemd services from our K8S YAML.  This is perfect for local K8S development/testing, quick prototyping, or edge workloads where full orchestration is overkill - but with the advantage of consistency due to the fact we are using the same K8S definitions!

Systemd and health probes

Podman enables us to run applications in containers or pods while providing a "good enough" reliability model. While you won't get the same level of redundancy than with K8S (after all, we're talking about single nodes here), just ensuring that your containers are restarted when a custom health check fails is a powerful pattern that is sufficient in many cases.

Podman supports container health checks natively. And since Podman has tight integrations with features already built into systemd (like systemd health checks), we can couple the two with ease.

Let's expand the pod definition example we used earlier:

The health check is defined using the standard K8S livenessProbe directive as you normally would. Podman translates this into container health check metadata, as can be seen from the output of 'podman inspect':

This is the equivalent of using the podman run --health-cmd syntax. The result is that if a container fails its custom health check, Podman can kill and restart it. If the entire pod fails, systemd takes over and restarts the service, as defined in the unit file:

This gives us two layers of self-healing:

  • Podman handles individual container restarts
  • systemd handles service-level recovery

And the best part? No dark magic! health checks are defined and maintained as code, living side-by-side in the repository alongside the application container definition.

(Caption: A flow diagram showing how the Podman+Quadlet approach can be deployed to manage a complete application life-cycle without Kubernetes)

Deployment and maintenance

With some smart integrations, deployments can be simple, repeatable, and DevOps-friendly.

We can keep all deployment logic for a containerised application in the same repository as the application code. A lightweight Ansible role can manage the setup, configuration, and image updates of a containerised service, without much effort. It is a simple and flexible pattern, that can be used by running Ansible ad-hoc, or by integrating it with a CI/CD pipeline.

Basic host setup and pre-requisites (non-root user creation, config directories, etc.) can also be included in the Ansible role, to ensure maximum portability and repeatability.

Going back to our example repository:

The result is a running systemd user service:

Need to roll out changes? Just update your config, push a PR, and re-run the Ansible playbook:

Note the new POD ID. Changes applied without touching the host OS. A solid pattern which can be managed with automation tools like Ansible Automation Platform, or as part of a DevOps workflow such as in a CI/CD pipeline.

Why Systemd User Services?

The example just shown runs as a user service, not a system service. That's a very deliberate design decision.

User services lets us apply systemd's power within the boundaries and constraints of an unprivileged user - improving our security posture and reducing the risk of container breakout or accidental system-level impact. It is a safe, clean way to run applications as code without root access.

Want to Do Something Similar?

This article demonstrated the simple elegance of the Podman+Quadlet combo. By combining native K8S YAML declarative syntax with systemd's process management, we get a flexible, reliable way to run containerised applications without needing Kubernetes at all.

Whether you're building for the edge, developing locally, or working in environments where full orchestration is overkill, we can help. Our Hybrid Cloud team is deeply experienced with Kubernetes. We even have multiple Red Hat OpenShift Certified Administrators on board! But we also know that sometimes, simple is smarter.

Reach out to us at OSS Group or call 0800-OSS-GRP. Let’s right-size your containers and help your team work smarter.

--

The following pages are great for further reading: