Podman Kubernetes Integration and Log Driver Orchestration

Podman represents a paradigm shift in containerization by providing a daemonless, OCI-compliant container engine specifically engineered to build, manage, and execute containers securely on Linux systems. Unlike traditional container tools that rely on a central background service, Podman operates without a daemon, a structural choice that fundamentally improves system stability and reduces the attack surface by eliminating a single point of failure and a high-privileged process. Podman Desktop further extends these capabilities, providing a cross-platform graphical user interface for Windows, macOS, and Linux, enabling users to manage containers and Kubernetes environments without relying solely on the command line. Because the Podman CLI is fully compatible with the Docker CLI—excluding Docker Swarm commands—it serves as a seamless drop-in replacement for those transitioning from Docker ecosystems.

The integration of Podman with Kubernetes is a strategic capability that allows Podman to parse and generate Kubernetes manifests. This bidirectional relationship provides immense flexibility, enabling the transfer of workloads from a Kubernetes cluster to a local Podman installation or the deployment of Podman-developed workloads into a production Kubernetes cluster. While Podman lacks its own orchestration tool similar to Docker Swarm, it is designed to complement Kubernetes. In advanced deployment scenarios where high availability, scalability, and fault tolerance are mandatory across numerous hosts, Kubernetes serves as the orchestrator that manages the complexity of the workloads that Podman helps build and test locally.

Rootful Podman Execution Without Privileged Flags

Running Podman as root inside a Kubernetes pod without utilizing the full privileged: true flag requires a precise configuration of Linux capabilities. This approach adheres to the principle of least privilege while still providing the necessary permissions for the container engine to function. To achieve this, specific capabilities must be explicitly added to the pod's security context.

The capabilities CAP_SYS_CHROOT and CAP_SETFCAP are mandatory because they are part of the default capability list used by Podman. When a Podman command is executed, the engine dynamically adds the capabilities it requires for that specific operation; consequently, if the Kubernetes pod is launched without these specific capabilities, Podman will fail to execute.

Furthermore, CAP_SYS_ADMIN is critical for Podman running as root inside a container to mount the required file systems. Similarly, CAP_MKNOD is required to allow Podman to create the necessary devices within the /dev directory. This granular control allows the operator to avoid the security risks associated with the privileged flag while ensuring the container engine has the operational power to manage other containers.

The following YAML configuration demonstrates the implementation of a rootful Podman pod without the privileged flag:

yaml apiVersion: v1 kind: Pod metadata: name: no-priv-rootful spec: containers: - name: no-priv-rootful image: quay.io/podman/stable args: - sleep - "1000000" securityContext: capabilities: add: - "SYS_ADMIN" - "MKNOD" - "SYS_CHROOT" - "SETFCAP" resources: limits: github.com/fuse: 1

When executing commands within this environment, the user can verify root access and run containers. For instance, executing kubectl exec -it no-priv-rootful -- sh allows the user to run id, which confirms uid=0(root) gid=0(root) groups=0(root). From this shell, running podman run ubi8 echo hello will trigger the resolution of "ubi8" as an alias via /etc/containers/registries.conf.d/000-shortnames.conf, pull the image from registry.access.redhat.com/ubi8:latest, and output the message "hello".

Podman-Remote Architecture in Kubernetes

Podman-remote allows a Kubernetes pod to interact with a Podman socket running on the host machine, effectively decoupling the Podman CLI from the engine's execution environment. This architecture is useful for managing host-level containers from within a controlled pod environment.

To implement this use case, two primary host-level requirements must be met:
1. SELinux must be disabled on the host.
2. The Podman socket must be enabled on the host.

The implementation involves mounting the host's Podman socket into the container. The corresponding YAML configuration for this setup is as follows:

yaml apiVersion: v1 kind: Pod metadata: name: podman-remote spec: containers: - name: remote image: quay.io/podman/stable args: - sleep - "1000000" volumeMounts: - mountPath: /var/run/podman name: podman-socket volumes: - name: podman-socket hostPath: path: /var/run/podman.sock

By mounting /var/run/podman (or the relevant socket path), the containerized Podman client can send instructions to the host's Podman engine, leveraging the host's resources and network while remaining isolated within the Kubernetes pod.

Podman Log Driver Configuration and Management

Podman's log driver configuration provides granular control over where container logs are stored and how they are formatted. This is critical for developers and system administrators who need to balance the need for visibility with the constraints of disk I/O and system performance.

The available log drivers and their specific behaviors are detailed in the following table:

Log Driver Primary Use Case Storage Format Key Feature
k8s-file Podman-generated K8s YAML Plain text files Accessible via podman logs
journald Centralized system logging Systemd journal Structured metadata (ID, Image)
json-file Docker-compatible scripting Kubernetes log format Supports max-size limits
passthrough Interactive containers No capture Minimal overhead
none Log-heavy containers Not stored Minimizes disk I/O

Detailed Analysis of Log Drivers

The k8s-file driver is designed for simplicity. It stores logs as plain text files, making it the ideal choice when running Podman-generated Kubernetes YAML or when the user requires basic access via the podman logs command.

The journald driver is the default setting. It integrates container logs directly into the systemd journal, which allows for centralized system logging. The primary advantage of this driver is the ability to utilize structured metadata, such as the container name, ID, and image, which can be queried using journalctl. For example, the command journalctl CONTAINER_NAME=test-journald --no-pager allows for precise filtering of logs.

The json-file driver acts as an alias for k8s-file. It is primarily used when Docker-compatible scripting is required. It follows the Kubernetes log format and allows for the implementation of size limits via the max-size option to prevent log files from consuming excessive disk space.

The passthrough driver is intended for interactive containers where the application manages its own logging. By bypassing the capture process, it reduces system overhead.

The none driver completely disables log storage. This is essential for containers that generate excessive, unneeded logs that would otherwise degrade disk I/O performance. It is important to note that while logs are not stored, they remain visible in interactive sessions.

Implementation and Testing of Log Drivers

To test and compare the behavior of these drivers, the following commands can be utilized:

For k8s-file:
bash podman run -d --log-driver k8s-file --name test-k8s alpine sh -c 'echo "hello from k8s-file"' podman logs test-k8s podman inspect --format '{{.HostConfig.LogConfig.Path}}' test-k8s

For journald:
bash podman run -d --log-driver journald --name test-journald alpine sh -c 'echo "hello from journald"' podman logs test-journald journalctl CONTAINER_NAME=test-journald --no-pager

For json-file:
bash podman run -d --log-driver json-file --name test-json alpine sh -c 'echo "hello from json-file"' podman logs test-json podman inspect --format '{{.HostConfig.LogConfig.Path}}' test-json

After testing, containers should be cleaned up using:
bash podman rm test-k8s test-journald test-json

Log Driver Options and System-Wide Configuration

Podman supports driver-specific options via the --log-opt flag. This allows for the fine-tuning of log behavior.

To implement a json-file driver with a maximum size of 10 megabytes:
bash podman run -d \ --log-driver json-file \ --log-opt max-size=10m \ --name my-app my-image:latest

To implement a journald driver with a custom tag based on the container name:
bash podman run -d \ --log-driver journald \ --log-opt tag="{{.Name}}" \ --name my-app my-image:latest

To implement a k8s-file driver with a maximum size of 50 megabytes:
bash podman run -d \ --log-driver k8s-file \ --log-opt max-size=50m \ --name my-app my-image:latest

For system-wide changes, the default log driver can be modified in the containers.conf file. For rootless users, this file is located at ~/.config/containers/containers.conf, while for root users, it is located at /etc/containers/containers.conf.

To set the default driver to journald for rootless users:
bash mkdir -p ~/.config/containers cat >> ~/.config/containers/containers.conf << 'EOF' [containers] log_driver = "journald" EOF

The new default can be verified using the following command:
bash podman info --format '{{.Host.LogDriver}}'

Log Driver Integration in Podman Compose

Log drivers can be defined within a podman-compose.yml file to ensure consistency across services.

yaml services: web: image: nginx:latest logging: driver: journald options: tag: "{{.Name}}" api: image: my-api:latest logging: driver: json-file options: max-size: "10m" worker: image: my-worker:latest logging: driver: k8s-file options: max-size: "50m"

Podman Image Construction and Local Development

Podman allows for the creation of images using Containerfiles, which can be built with different isolation levels. For example, using the --isolation chroot flag allows for building images within a restricted environment.

Consider a basic containerfile with the following content:
dockerfile FROM ubi8 RUN echo "hello" ENV foo=bar

The build process is initiated as follows:
bash podman build --isolation chroot -t myimage -f containerfile .

The output of this process involves several steps:
- STEP 1: FROM ubi8 (Loading base image)
- STEP 2: RUN echo "hello" (Executing the shell command)
- STEP 3: ENV foo=bar (Setting environment variables)
- STEP 4: COMMIT myimage (Finalizing the image)

Once the image is built, it can be verified using the podman images command, which will list the repository, tag, image ID, creation date, and size. For instance, the localhost/myimage would show as latest with a specific image ID and a size of approximately 245 MB.

Analysis of Podman and Kubernetes Synergy

The relationship between Podman and Kubernetes is symbiotic. Podman addresses the development and local testing phase of the container lifecycle, while Kubernetes addresses the production and orchestration phase.

The ability to generate Kubernetes manifests directly from Podman allows developers to move from a local environment to a cluster without rewriting their infrastructure definitions. This eliminates the friction typically found when moving between different container engines. Furthermore, the daemonless nature of Podman ensures that the local development environment mirrors the security profile of a production Kubernetes node more closely than a daemon-based system would.

The integration of Podman with Kubernetes manifests means that the desired state of a cluster can be prototyped locally. This allows for the testing of pod specifications, resource limits, and security contexts before they are applied to a live production environment. When combined with a sophisticated log driver strategy, this creates a complete pipeline from image creation (podman build) and local testing (podman run) to cluster deployment and monitoring.

The overall impact for the user is a reduced cognitive load. A developer can use a single set of CLI commands for almost all their container needs, only switching to Kubernetes-specific tools for high-level orchestration. The technical synergy is further enhanced by the OCI compliance of Podman, ensuring that any image built locally will run identically in any OCI-compliant orchestrator, providing absolute consistency across the software development life cycle.

Sources

  1. Red Hat Blog
  2. OneUptime Blog
  3. GeeksforGeeks
  4. BetterStack Community

Related Posts