Skip to main content

Stacks

Stacks is an Infrastructure as Code (IaC) system that enables declarative deployment of complete application stacks including infrastructure resources, secrets, bootstrap jobs, and services.

Overview​

Stacks provides four major capabilities:

  1. Secrets Management - Generate, store, and inject secrets via HashiCorp Vault
  2. Bootstrap Jobs - Run initialization tasks like database migrations
  3. Service Deployments - Deploy Helm charts or raw Kubernetes manifests
  4. Multi-Tenant Isolation - Vault policies scoped per tenant

Execution Phases​

Stack deployment follows a strict four-phase execution model:

PhaseDescriptionComponents
1. InfrastructureProvision resourcesDatabases, Namespaces, Storage
2. SecretsGenerate and store secretsVault KV, Dynamic credentials
3. BootstrapRun initialization jobsMigrations, Seeds, Init scripts
4. ServicesDeploy applicationsHelm Charts, K8s Manifests

Template Structure​

Complete Template Example​

version: "1"
name: my-application
tenant: acme-corp

# Phase 1: Infrastructure Resources
resources:
database:
type: database
properties:
engine: postgres
version: "15"
storage_size: 10Gi

cache:
type: valkey
properties:
memory: 256Mi

# Phase 2: Secrets
secrets:
db_password:
type: generated
generator_type: password
length: 32
charset: alphanumeric_special

api_key:
type: generated
generator_type: token
length: 64

external_api_token:
type: static
vault_path: "external/stripe/api-key"

# Phase 3: Bootstrap Jobs
bootstrap:
migrate:
image: "myapp/migrations:v1.2.0"
command: ["./migrate", "up"]
secrets:
DATABASE_URL: "${resources.database.connection_string}"
DB_PASSWORD: "${secrets.db_password.vault_path}"
timeout: "10m"
backoff_limit: 3

seed:
image: "myapp/seeds:v1.2.0"
command: ["./seed", "--env", "production"]
depends_on:
- migrate
secrets:
DATABASE_URL: "${resources.database.connection_string}"

# Phase 4: Services
services:
backend:
type: helm
depends_on:
- migrate
properties:
chart: "oci://registry.sparbz.cloud/charts/backend"
version: "1.2.0"
values:
replicas: 3
image:
tag: "v1.2.0"
database:
host: "${resources.database.host}"
port: "${resources.database.port}"
name: "${resources.database.name}"
secrets:
inject_method: external_secrets
mappings:
- secret: db_password
inject_as: env
env_prefix: DB
- secret: api_key
inject_as: env

# Stack Outputs
outputs:
api_endpoint:
value: "${services.backend.endpoint}"
database_host:
value: "${resources.database.host}"
sensitive: false

Reference Resolution​

Stacks supports cross-phase references using the ${namespace.name.attribute} syntax:

Supported Namespaces​

NamespaceDescriptionAvailable After
resourcesInfrastructure resource outputsPhase 1
secretsSecret vault paths and metadataPhase 2
bootstrapJob execution outputsPhase 3
servicesService deployment outputsPhase 4

Reference Examples​

# Reference a resource output
database_url: "${resources.database.connection_string}"

# Reference a secret's vault path
secret_path: "${secrets.db_password.vault_path}"

# Reference a bootstrap job output
migration_version: "${bootstrap.migrate.outputs.version}"

# Reference a service endpoint
api_url: "${services.backend.endpoint}"

Secrets Management​

Secret Types​

Generated Secrets​

Automatically generate secure values:

secrets:
# Password with special characters
db_password:
type: generated
generator_type: password
length: 32
charset: alphanumeric_special # or: alphanumeric, hex

# UUID
instance_id:
type: generated
generator_type: uuid

# URL-safe token
api_token:
type: generated
generator_type: token
length: 64

# RSA key pair
signing_key:
type: generated
generator_type: rsa
generator_config:
key_size: 4096

Static Secrets​

Reference existing secrets in Vault:

secrets:
stripe_key:
type: static
vault_path: "external/stripe/secret-key"

Dynamic Secrets​

Use Vault's database secrets engine for rotating credentials:

secrets:
db_creds:
type: dynamic
engine: database
role: "myapp-readonly"
ttl: "1h"

Secret Injection​

Secrets can be injected into services using two methods:

services:
backend:
type: helm
secrets:
inject_method: external_secrets
mappings:
- secret: db_password
inject_as: env
env_prefix: DATABASE
- secret: api_key
inject_as: env

Vault Agent​

services:
backend:
type: helm
secrets:
inject_method: vault_agent
mappings:
- secret: db_password
inject_as: file
mount_path: /secrets

Bootstrap Jobs​

Bootstrap jobs run Kubernetes Jobs for initialization tasks:

bootstrap:
migrate:
image: "myapp/migrations:latest"
command: ["./migrate"]
args: ["up", "--env", "production"]
secrets:
DATABASE_URL: "${resources.database.connection_string}"
timeout: "15m"
backoff_limit: 3
namespace: "myapp" # optional, defaults to stack namespace

seed:
image: "myapp/seeds:latest"
depends_on:
- migrate # Waits for migrate to complete

Service Deployments​

Helm Charts​

services:
backend:
type: helm
properties:
chart: "oci://registry.sparbz.cloud/charts/backend"
version: "1.2.0"
release_name: "myapp-backend"
values:
replicas: 3
resources:
requests:
memory: "256Mi"
cpu: "250m"

Raw Manifests​

services:
custom_resource:
type: manifest
properties:
manifest: |
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
DATABASE_HOST: "${resources.database.host}"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: custom-app
spec:
replicas: 1
# ... deployment spec

API Endpoints​

MethodEndpointDescription
POST/v1/stacksCreate a new stack
GET/v1/stacksList all stacks
GET/v1/stacks/{id}Get stack details
PUT/v1/stacks/{id}Update stack template
DELETE/v1/stacks/{id}Delete stack
POST/v1/stacks/{id}/applyApply stack changes
POST/v1/stacks/{id}/destroyDestroy stack resources
GET/v1/stacks/{id}/planPreview changes
GET/v1/stacks/{id}/outputsGet stack outputs

CLI Commands​

# Create a new stack
szc stack create --name my-app --file stack.yaml

# List all stacks
szc stack list

# Get stack details
szc stack get my-stack

# Apply changes
szc stack apply my-stack

# Preview changes (dry-run)
szc stack plan my-stack

# View stack outputs
szc stack outputs my-stack

# Destroy stack
szc stack destroy my-stack

Best Practices​

  1. Use Generated Secrets - Never hardcode secrets in templates
  2. Dependency Order - Declare explicit dependencies between components
  3. Idempotent Bootstrap - Design migration scripts to be re-runnable
  4. Version Helm Charts - Always pin chart versions
  5. Tenant Isolation - Use unique tenant IDs per environment
  6. Secret Rotation - Use dynamic secrets where possible

Troubleshooting​

Common Issues​

IssueCauseSolution
Secret not foundVault path doesn't existVerify static secret exists in Vault
Job timeoutMigration taking too longIncrease timeout value
Reference errorCircular dependencyCheck depends_on declarations
Helm install failedChart not foundVerify chart registry access

Debug Commands​

# Check stack status
szc stack get my-stack

# View execution logs
szc stack logs my-stack

# List secrets
szc stack secrets my-stack

# Check job status
szc stack jobs my-stack