PodWarden
Guides

Stacks

Create and manage application stacks in PodWarden

Overview

Stacks are templates that describe how to run a containerized workload. Each stack specifies the container image, resource requirements, environment variables, volumes, ports, and deployment configuration. Stacks are reusable — create one stack and deploy it to multiple clusters.

Creating a Stack

Navigate to Apps & Stacks in the sidebar and click Create.

Basic Fields

FieldRequiredDescription
nameYesDisplay name for the workload
kindYesWorkload type: deployment (long-running), job (batch), or daemonset (per-node)
image_nameYesContainer image name (e.g. ollama/ollama, postgres)
image_tagNoImage tag (defaults to fleet-level setting from Settings → Registry)
registry_urlNoOverride the default registry for this workload
registry_credentialsNoRegistry auth credentials (for private registries)
commandNoContainer command override (overrides the image's CMD)
host_networkNoUse host networking (hostNetwork: true). For UDP multicast, IPTV, or direct network access
dns_policyNoKubernetes dnsPolicy for pods. Default: ClusterFirst. Use Default for Docker-in-Docker workloads (see Networking)

Resource Requests

FieldDescriptionExamples
cpu_requestCPU cores or millicores500m, 1, 2, 4
memory_requestRAM allocation512Mi, 2Gi, 8Gi
gpu_countNumber of NVIDIA GPUs0, 1, 2
vram_requestGPU VRAM requirement8Gi, 24Gi
concurrent_jobsMax concurrent instances (for job kind)1, 4

PodWarden converts these into Kubernetes resource requests. GPU workloads use nvidia.com/gpu resource limits.

Environment Variables

Stacks support two types of environment variables:

Static Environment Variables (env)

Fixed key-value pairs embedded directly in the definition. These are set at definition time and applied as-is to every deployment.

[
  { "name": "OLLAMA_HOST", "value": "0.0.0.0" },
  { "name": "LOG_LEVEL", "value": "info" }
]

Use static env vars for values that are the same across all deployments — host bindings, log levels, feature flags with known values.

Configurable Environment Variables (env_schema)

Schema-defined variables that document available configuration. Each entry has a name, optional default value, a required flag, and a description.

[
  {
    "name": "OLLAMA_MODELS",
    "required": false,
    "default_value": "/models",
    "description": "Path where Ollama stores downloaded models"
  },
  {
    "name": "OLLAMA_NUM_PARALLEL",
    "required": false,
    "default_value": "1",
    "description": "Number of parallel model requests"
  }
]

env_schema serves as documentation and configuration guidance. When deploying from the Hub catalog, configurable variables help operators understand what can be tuned.

Schema FieldDescription
nameVariable name (e.g. OLLAMA_MODELS)
requiredWhether the variable must be set
default_valueDefault value if not overridden
descriptionHuman-readable explanation
generateAuto-generation strategy for secrets (optional). When set, the Hub's one-click installer generates a random value using openssl rand. Strategies: password (18-byte alphanumeric), hex16, hex32, hex64 (hex strings), base64 (32-byte base64), uuid.

Example with generate:

[
  {
    "name": "DB_PASSWORD",
    "required": true,
    "description": "Database password",
    "generate": "password"
  },
  {
    "name": "SECRET_KEY_BASE",
    "required": true,
    "description": "Rails session encryption key",
    "generate": "hex64"
  }
]

Variables with generate hints show an "Auto-generate secrets" toggle in the Hub catalog's install modal. The .env.example file in the download bundle includes # generate:<strategy> markers that the install script reads to produce random values.

Secret References (secret_refs)

References to secrets stored in PodWarden's encrypted secret store. At deploy time, PodWarden injects these as environment variables from Kubernetes secrets.

Ports

Define which container ports to expose:

[
  { "containerPort": 11434, "protocol": "TCP" },
  { "containerPort": 8080, "protocol": "TCP" }
]

Exposed ports are included in the generated Kubernetes Service manifest.

Config Files (config_schema)

Stacks can declare mountable config files — configuration files that operators can edit per deployment. Each config slot specifies a file name, mount path, file type, and optional default content. At deploy time, PodWarden creates a Kubernetes ConfigMap for each slot and mounts it into the container.

See the Config Files guide for details on defining config slots, editing content per assignment, and examples.

Volume Mounts

Attach persistent storage to the container. See the Storage guide for all volume types (emptyDir, hostPath, PVC, NFS, S3, configMap, secret).

Scheduling

FieldDescription
node_selectorKubernetes node selector labels (JSON object, e.g. {"gpu": "a100"})
tolerationsKubernetes tolerations for tainted nodes
required_network_typesNetwork types the target cluster must support (see Networking)

Network Requirements

The Required connectivity field declares what network types the target cluster must support for this workload. Options: public, mesh, lan.

Before deployment, PodWarden runs a pre-flight check comparing the workload's required network types against the cluster's available networks. See Networking for details.

Security Context

The Security context section controls container-level security settings. These map directly to the Kubernetes pod securityContext.

FieldDescriptionExample
PrivilegedRun the container with elevated privileges (full host device access)Required for VPN tunnels, network tools
Capabilities AddLinux capabilities to add to the containerNET_ADMIN, SYS_PTRACE
Capabilities DropLinux capabilities to remove from the containerALL (then add back only what's needed)

Common capability combinations:

Use CaseCapabilities
VPN / mesh networking (Nebula, WireGuard)NET_ADMIN (creates tun/tap interfaces)
Network debugging (tcpdump, ping)NET_RAW
Full device access (USB passthrough)Privileged mode
Hardened containerDrop ALL, add only what's needed

The security context is stored as a JSON object:

{
  "privileged": true,
  "capabilities": {
    "add": ["NET_ADMIN"],
    "drop": ["ALL"]
  }
}

Health Probes

Health probes let Kubernetes monitor your container and restart it if it becomes unhealthy. PodWarden supports three probe types:

ProbePurpose
LivenessDetects stuck containers. If the probe fails, Kubernetes restarts the container.
ReadinessDetects containers not ready to serve traffic. Failing containers are removed from the Service.
StartupGives slow-starting containers time to initialize before liveness checks begin.

Each probe can use one of three methods:

MethodWhen to useExample
execRun a command inside the container["pg_isready", "-U", "postgres"]
httpGetHTTP GET to a path and port{"path": "/health", "port": 8080}
tcpSocketCheck if a TCP port is open{"port": 5432}

Probes are configured as a JSON object:

{
  "liveness": {
    "httpGet": { "path": "/health", "port": 8080 },
    "periodSeconds": 30,
    "timeoutSeconds": 5,
    "failureThreshold": 3
  },
  "readiness": {
    "tcpSocket": { "port": 8080 },
    "periodSeconds": 10
  }
}

Probes are optional. If not set, Kubernetes assumes the container is healthy as long as the main process is running.

Stack Types

Every stack is one of two types:

  • Single Service — A single container deployed as one Kubernetes Deployment. This is the default when you create a stack manually or import a single-image template from Hub.
  • Compose Stack — A multi-service template imported from a docker-compose.yml file. Each service becomes a separate Kubernetes Deployment.

Compose Stacks

PodWarden supports importing docker-compose.yml files as stacks. A Compose Stack is a multi-service template where each service becomes a separate Kubernetes Deployment.

How compose stacks work

  1. Import a docker-compose.yml from the Apps & Stacks page (or from Hub)
  2. PodWarden parses the compose file and creates a single stack marked as a compose stack
  3. When deployed, PodWarden creates a parent assignment plus child assignments for each service
  4. Each service is translated to Kubernetes resources (Deployment + Service + PVCs)

Compose-to-Kubernetes translation

ComposeKubernetes
Each serviceDeployment + ClusterIP Service
portscontainerPort + Service ports
volumes (bind mount /host:/ctr)hostPath volume
volumes (named vol:/ctr)PVC
environmentContainer env
healthchecklivenessProbe + readinessProbe
cap_addsecurityContext.capabilities.add
privileged: truesecurityContext.privileged
network_mode: hosthostNetwork: true
command / entrypointContainer command / args
deploy.resources.limitsresources.limits
deploy.resources.reservationsresources.requests
depends_onNo equivalent (services use DNS discovery)

The x-podwarden extension

Compose templates can include an x-podwarden block with PodWarden-specific metadata:

services:
  app:
    image: myapp:latest
    ports:
      - "8080:8080"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 5s

x-podwarden:
  name: My Application
  description: "Full-stack application with health monitoring"
  required_network_types: [public]
  form_fields:
    - name: APP_SECRET
      label: Application Secret
      required: true
      description: "Secret key for session encryption"
    - name: LOG_LEVEL
      label: Log Level
      default: "info"

The form_fields in x-podwarden map to env_schema entries, making variables configurable per deployment.

Variable substitution

Compose templates use {{VAR_NAME}} placeholders (double braces) in the compose source and config templates. At deploy time, PodWarden substitutes these with values from the assignment's environment variables. The double-brace syntax avoids collision with shell $VAR syntax in scripts.

Pre-deploy scripts

Compose templates can include scripts that run on the target host before deployment:

x-podwarden:
  scripts:
    pre_deploy:
      - name: setup-certs
        run_on: host
        content: |
          #!/bin/bash
          mkdir -p /etc/myapp/certs
          # Generate certificates...

Pre-deploy scripts execute via SSH on the target host with sudo privileges. They run before any Kubernetes resources are created and fail the deployment if they exit with a non-zero status.

Importing a compose file

  1. Go to Apps & Stacks and click Import from Compose
  2. Paste the docker-compose.yml content (with optional x-podwarden block)
  3. PodWarden parses the compose file and creates a stack
  4. The definition is marked as a Compose Stack with the parsed services listed

Editing Stacks

Click any stack to open the edit form. All fields are editable. Changes apply to future deployments — already-running workloads are not affected until you redeploy.

Deploying Stacks

Stacks are deployed to clusters via Deployments:

  1. Go to Deployments and click Create
  2. Select a Stack (the template)
  3. Select a Cluster (the target)
  4. Optionally override the namespace
  5. Click Deploy to generate the Kubernetes manifest and apply it

PodWarden generates a complete Kubernetes manifest (Deployment/Job/DaemonSet + Service + PVCs) and applies it via kubectl. Deployment status is tracked in real-time.

See the Deployment guide for details on assignments, undeploying, logs, and rollbacks.

Importing from PodWarden Hub

Connect to PodWarden Hub to browse and import curated stacks.

How to Import

  1. Go to Apps & Stacks and click Import from Hub
  2. Browse templates by category, search by name, or filter by tags
  3. Click Import on any template
  4. PodWarden creates a local stack with all fields copied:
    • Image, registry, resources (CPU, memory, GPU, VRAM)
    • Environment variables (static and configurable)
    • Ports, volumes, node selectors, tolerations, network requirements
  5. The imported definition tracks its Hub origin (hub_template_slug and hub_template_version)

After import, the definition is independent — customize any field before deploying.

Checking for Updates

Imported definitions show a Hub badge. PodWarden can check if newer versions are available by comparing your local hub_template_version against the current version on Hub.

Hub Connection Required

To use the import feature, configure your Hub connection under Settings → Hub. See Connecting to Hub for setup instructions.

Stack Fields Reference

FieldTypeDescription
namestringDisplay name
kindstringdeployment, job, or daemonset
image_namestringContainer image name
image_tagstringImage tag
registry_urlstringOverride registry URL
registry_credentialsstringRegistry auth credentials
commandstringContainer command override
cpu_requeststringCPU request (e.g. 500m, 2)
memory_requeststringMemory request (e.g. 512Mi, 8Gi)
gpu_countintegerNumber of GPUs
vram_requeststringVRAM requirement
concurrent_jobsintegerMax concurrent instances
envJSON arrayStatic environment variables
env_schemaJSON arrayConfigurable environment variable schema (name, required, default_value, description, generate)
config_schemaJSON arrayMountable config file definitions (see Config Files)
secret_refsJSONSecret references
portsJSON arrayContainer port mappings
volume_mountsJSON arrayVolume mount configurations
node_selectorJSON objectKubernetes node selector
tolerationsJSONKubernetes tolerations
required_network_typestext[]Required network types (public, mesh, lan)
host_networkbooleanUse host networking (binds to node's network stack)
dns_policystringKubernetes dnsPolicy for pods (ClusterFirst, Default, None, ClusterFirstWithHostNet)
security_contextJSONContainer security context (capabilities, privileged)
probesJSONHealth probes (liveness, readiness, startup)
is_compose_stackbooleanWhether this is a compose stack (multi-service template)
compose_sourcetextRaw docker-compose.yml source (compose stacks only)
compose_servicesJSONExtracted service list for compose stacks
hub_template_slugstringHub template slug (if imported)
hub_template_versionstringHub template version (if imported)
hub_imported_attimestampWhen the template was imported from Hub