Orchestrating the LGTM Stack via Podman: Rootless Observability and Automated Provisioning

The modern observability landscape demands a paradigm shift from manual configuration toward highly automated, scalable, and secure infrastructure. At the heart of this transition is the integration of Grafana—the industry-leading open-source platform for monitoring, metrics, logs, and traces—with Podman, a daemonless, OCI-compliant container engine. By leveraging Podman's unique ability to execute rootless containers, engineers can deploy powerful observability dashboards that significantly reduce the attack surface of the underlying host. This orchestration goes beyond simple container execution; it encompasses the deployment of the full LGTM stack (Loki, Grafana, Tempo, and Mimir), the implementation of persistent storage strategies to ensure data durability, and the application of "Configuration as Code" through automated provisioning of data sources and dashboards. Such a setup is indispensable for modern DevOps workflows, where development, staging, and production environments require consistent, repeatable, and secure deployment patterns.

The Architectural Advantages of Podman in Observability

Podman, which serves as a "Pod Manager," offers a fundamental architectural departure from traditional container engines like Docker. While Docker relies on a central, high-privilege daemon to manage container lifecycles, Podman operates in a daemonless manner. This design choice has profound implications for security and system stability within an observability pipeline.

The primary advantage is the support for rootless containers. In a rootless configuration, the container engine and the containers themselves run without administrative privileges on the host operating system. This isolation ensures that even if a vulnerability is exploited within a Grafana instance or one of its backend components, the impact is confined to the user's unprivileged namespace, preventing a complete host takeover.

Furthermore, Podman is fully compatible with the Open Container Initiative (OCI) standards. This compatibility allows it to utilize images built with Buildah, Docker, or Podman itself. For engineers transitioning from Docker-based workflows, Podman provides a seamless experience, as the CLI is designed to be a drop-in replacement. This level of compatibility is often realized through simple shell aliasing:

bash alias docker=podman

The engine's availability across Linux, Mac, and Windows ensures that observability stacks can be prototyped on local workstations and deployed to production-grade Linux distributions with minimal friction.

Preparing the Linux Host Environment

Deploying a robust Grafana stack requires a stable, updated foundation. The most effective implementation occurs on RPM-based Linux distributions, which provide the necessary package management tools for a streamlined installation. Specifically, environments such as Red Hat Enterprise Linux (RHEL), CentOS, Rocky Linux, or AlmaLinux are highly recommended due to their stability and enterprise-ready repositories.

The deployment process must begin with a complete synchronization of the host's package index and an upgrade of all installed components to mitigate known vulnerabilities.

  1. Update all system packages and initiate a reboot to ensure all kernel-level changes take effect:
    bash sudo dnf update -y && sudo reboot

  2. Install the Podman container engine to provide the necessary orchestration capabilities:
    bash sudo dnf install -y podman

Once the engine is active, the infrastructure is prepared to host the OCI-compliant images required for the observability stack.

Deploying the Complete Grafana LGTM Stack

For advanced observability, a single Grafana instance is insufficient; it must be backed by specialized engines for different telemetry types. The LGTM stack—consisting of Loki (logs), Grafana (dashboards), Tempo (traces), and Mimir (metrics)—provides a unified view of the entire system state.

A highly efficient method for deploying this complex architecture is through Kubernetes-style YAML manifests using Podman's play kube capability. This allows for the orchestration of multiple interconnected containers as a single unit.

  1. Clone the specialized deployment repository to your local machine:
    bash git clone https://github.com/Cast/grafana-stack-podman

  2. Navigate to the repository directory:
    bash cd grafana-stack-podman

  3. Execute the deployment using the Kubernetes-compatible configuration:
    bash podman play kube grafana-stack.yaml

  4. Verify the operational status of the containers in the stack:
    bash podman ps

After the containers are running, the host's firewall must be configured to allow traffic to the various ports used by the stack components. Failure to open these ports will result in unreachable dashboards and broken data pipelines.

Service Default Port Function
Grafana 3000 Dashboard UI and API
Loki 3100 Log Aggregation
Tempo 3200 Distributed Tracing
Prometheus/Mimir 9009 Metrics Collection
OpenTelemetry 4317/4318 Trace Ingestion
Other Components 9095, 9096, 9097, 9411, 14268 Internal Communication

To permit access, execute the following firewall commands:

bash sudo firewall-cmd --permanent --add-port={3000/tcp,3100/tcp,4317/tcp,4318/tcp,9009/tcp,9095/tcp,9096/tcp,9097/tcp,9411/tcp,14268/tcp} sudo firewall-cmd --reload

Once the network layer is secured, the backend services can be accessed via their respective URLs. For example, Prometheus is accessible at http://{machine_ip}:9099/prometheus, Loki at http://{machine_ip}:3100, and Tempo at http://{machine_ip}:3200.

Implementing Containerized Grafana: Three Deployment Strategies

Deployment strategies for Grafana within Podman can be categorized into three levels of complexity: basic, persistent, and custom-configured.

Basic Deployment

The simplest method involves pulling the latest image and running it in detached mode. This is ideal for rapid testing or ephemeral environments where data loss is not a concern.

  1. Pull the latest official Grafana image from the registry:
    bash podman pull docker.io/grafana/grafana:latest

  2. Run the container on port 3000:
    bash podman run -d \ --name my-grafana \ -p 3000:3000 \ docker.io/grafana/grafana:latest

  3. Verify the image exists in your local storage:
    bash podman images | grep grafana

Persistent Storage Configuration

In a production-grade observability stack, the loss of dashboards and user settings due to container restarts or deletions is unacceptable. This is solved by utilizing Podman named volumes, which decouple the data lifecycle from the container lifecycle.

  1. Create a dedicated volume for Grafana's internal database and configuration:
    bash podman volume create grafana-data

  2. Launch the container with the volume mounted to the internal Grafana data directory:
    bash podman run -d \ --name grafana-persistent \ -p 3001:3000 \ -v grafana-data:/var/lib/grafana:Z \ docker.io/grafana/grafana:latest

The :Z flag is critical in SELinux-enabled systems (like RHEL or Fedora), as it instructs Podman to relabel the volume content, ensuring the container has the necessary permissions to write to the host-managed volume.

Custom Environment and Security Configuration

For environments requiring strict security controls, such as disabling user sign-ups or enforcing custom administrative credentials, environment variables can be passed directly to the container during the run command.

  1. Create a volume for custom data:
    bash podman volume create grafana-custom-data

  2. Execute a container with pre-defined security parameters:
    bash podman run -d \ --name grafana-custom \ -p 3002:3000 \ -e GF_SECURITY_ADMIN_USER=myadmin \ -e GF_SECURITY_ADMIN_PASSWORD=my-grafana-secret \ -e GF_USERS_ALLOW_SIGN_UP=false \ -e GF_SERVER_ROOT_URL=http://localhost:3002 \ -e GF_PLUGINS_PREINSTALL=grafana-clock-panel,grafana-simple-json-datasource \ -v grafana-custom-data:/var/lib/grafana:Z \ docker.io/grafana/grafana:latest

This configuration allows for the pre-installation of specific plugins, such as the grafana-clock-panel, which can be essential for specialized monitoring needs.

Automated Provisioning: Infrastructure as Code

A hallmark of advanced DevOps engineering is the ability to provision data sources and dashboards through code rather than manual UI interaction. This ensures that every time a new Grafana instance is spun up, it arrives fully configured with the necessary connections to Prometheus, Elasticsearch, or Loki.

Data Source Provisioning

By creating configuration files in a specific directory structure on the host and mounting them into the container, you can automate the setup of data sources.

  1. Create the necessary directory structure on the host:
    bash mkdir -p ~/grafana-provisioning/datasources mkdir -p ~/grafana-provisioning/dashboards

  2. Define the Prometheus and Elasticsearch data sources using a YAML configuration:
    ```bash
    cat > ~/grafana-provisioning/datasources/prometheus.yml <<'EOF'
    apiVersion: 1
    datasources:

  • name: Prometheus
    type: prometheus
    access: proxy
    url: http://host.containers.internal:9090
    isDefault: true
    editable: true
    jsonData:
    timeInterval: '15s'
  • name: Elasticsearch
    type: elasticsearch
    access: proxy
    url: http://host.containers.internal:9200
    editable: true
    jsonData:
    index: 'app-logs-*'
    timeField: '@timestamp'
    EOF
    ```
  1. Deploy a Grafana instance that consumes these provisioned files:
    bash podman volume create grafana-provisioned-data podman run -d \ --name grafana-provisioned \ -p 3003:3000 \ -e GF_SECURITY_ADMIN_PASSWORD=admin-secret \ -v ~/grafana-provisioning/datasources:/etc/grafana/provisioning/datasources:ro \ -v grafana-provisionan-data:/var/lib/grafana:Z \ docker.io/grafana/grafana:latest

Dashboard Provisioning via Volume Mounts

Dashboard provisioning follows the same logic. By mounting a directory containing JSON dashboard definitions into the /etc/grafana/provisioning/dashboards path within the container, the dashboards become instantly available upon startup. This is often verified by inspecting the dashboard JSON, which might contain strings like "This dashboard is provisioned via Podman volume mount."

Programmatic Management via the Grafana API

Once the stack is operational, the Grafana API allows for the programmatic management of the observability platform. This is vital for automated testing and continuous integration/continuous deployment (CI/CD) pipelines.

The following commands demonstrate how to interact with the running instance:

  1. Verify the health status of the Grafana deployment:
    bash curl -s http://localhost:3003/api/health | python3 -m json.tools

  2. Search for all available dashboards in the system:
    bash curl -s -u admin:admin-secret http://localhost:3003/api/search | python3 -m json.tools

  3. Inspect the list of installed plugins to ensure pre-installed plugins are active:
    bash curl -s -u admin:admin-secret http://localhost:3003/api/plugins | python3 -m json.tools | head -20

  4. Verify that the custom administrative user can successfully authenticate:
    bash curl -s -u myadmin:my-grafana-secret http://localhost:3002/api/org | python3 -m json.tools

Lifecycle Management and Container Maintenance

Managing a production observability stack requires a mastery of container lifecycle commands. Regular maintenance includes viewing logs for troubleshooting, stopping services during host maintenance, and cleaning up deprecated resources to prevent storage exhaustion.

Monitoring and Troubleshooting

When a component of the LGTM stack fails to ingest data, the logs are the primary source of truth.

bash podman logs my-grafana

Service Control

Standard operations for managing the running state of the containers:

bash podman stop my-grafana podman start my-grafana

Resource Cleanup

To prevent "container sprawl" and the accumulation of unused volumes, engineers should periodically remove unused containers and volumes.

```bash

Remove specific containers and their associated volumes

podman rm -f my-grafana grafana-custom grafana-provisioned
podman volume rm grafana-data grafana-custom-data grafana-provisioned-data
```

Technical Analysis of the Rootless Deployment Model

The convergence of Podman's rootless execution and Grafana's multi-tenant observability capabilities represents a significant advancement in secure systems engineering. The implementation of the LGTM stack via Podman provides a triple-layered security model: the host is protected by standard Linux permissions, the container engine is isolated through user namespaces, and the observability data is partitioned through Grafana's internal security controls.

From a DevOps perspective, the use of Podman volumes for both data persistence and configuration injection (as seen in the provisioning of Prometheus and Elasticsearch) creates a highly portable deployment unit. This setup is not merely a collection of containers but a cohesive, programmable infrastructure component. The ability to use podman play kube to launch the entire stack from a single YAML file bridges the gap between local development and large-scale Kubernetes orchestration, allowing for a "write once, run anywhere" approach to observability.

The transition from manual configuration to an automated, file-driven approach—leveraging environment variables for secrets and volume mounts for configuration—minimizes the "configuration drift" that often plagues long-lived monitoring environments. Ultimately, this architecture provides a robust, scalable, and highly secure foundation for any organization looking to master the complexities of modern, distributed telemetry.

Sources

  1. OneUptime Blog - Running Grafana in Podman
  2. Grafana Blog - How to Deploy the Grafana Stack using Podman
  3. GitHub - CastawayEGR/grafana-stack-podman

Related Posts