Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Customize Infrastructure Guide

Complete guide to customizing infrastructure with layers, templates, and extensions.

Overview

The provisioning platform uses a layered configuration system that allows progressive customization without modifying core code.

Configuration Layers

Configuration is loaded in this priority order (low → high):

1. Core Defaults     (provisioning/config/config.defaults.toml)
2. Workspace Config  (workspace/{name}/config/provisioning.yaml)
3. Infrastructure    (workspace/{name}/infra/{infra}/config.toml)
4. Environment       (PROVISIONING_* env variables)
5. Runtime Overrides (Command line flags)

Layer System

Layer 1: Core Defaults

Location: provisioning/config/config.defaults.toml Purpose: System-wide defaults Modify: ❌ Never modify directly

[paths]
base = "provisioning"
workspace = "workspace"

[settings]
log_level = "info"
parallel_limit = 5

Layer 2: Workspace Configuration

Location: workspace/{name}/config/provisioning.yaml Purpose: Workspace-specific settings Modify: ✅ Recommended

workspace:
  name: "my-project"
  description: "Production deployment"

providers:
  - upcloud
  - aws

defaults:
  provider: "upcloud"
  region: "de-fra1"

Layer 3: Infrastructure Configuration

Location: workspace/{name}/infra/{infra}/config.toml Purpose: Per-infrastructure customization Modify: ✅ Recommended

[infrastructure]
name = "production"
type = "kubernetes"

[servers]
count = 5
plan = "4xCPU-8GB"

[taskservs]
enabled = ["kubernetes", "cilium", "postgres"]

Layer 4: Environment Variables

Purpose: Runtime configuration Modify: ✅ For dev/CI environments

export PROVISIONING_LOG_LEVEL=debug
export PROVISIONING_PROVIDER=aws
export PROVISIONING_WORKSPACE=dev

Layer 5: Runtime Flags

Purpose: One-time overrides Modify: ✅ Per command

provisioning server create --plan 8xCPU-16GB --zone us-west-2

Using Templates

Templates allow reusing infrastructure patterns:

1. Create Template

# Save current infrastructure as template
provisioning template create kubernetes-ha \
    --from my-cluster \
    --description "3-node HA Kubernetes cluster"

2. List Templates

provisioning template list

# Output:
# NAME            TYPE        NODES  DESCRIPTION
# kubernetes-ha   cluster     3      3-node HA Kubernetes
# small-web       server      1      Single web server
# postgres-ha     database    2      HA PostgreSQL setup

3. Apply Template

# Create new infrastructure from template
provisioning template apply kubernetes-ha \
    --name new-cluster \
    --customize

4. Customize Template

# Edit template configuration
provisioning template edit kubernetes-ha

# Validate template
provisioning template validate kubernetes-ha

Creating Custom Extensions

Custom Task Service

Create a custom taskserv for your application:

# Create taskserv from template
provisioning generate taskserv my-app \
    --category application \
    --version 1.0.0

Directory structure:

workspace/extensions/taskservs/application/my-app/
├── nu/
│   └── my_app.nu           # Installation logic
├── kcl/
│   ├── my_app.k            # Configuration schema
│   └── version.k           # Version info
├── templates/
│   ├── config.yaml.j2      # Config template
│   └── systemd.service.j2  # Service template
└── README.md               # Documentation

Custom Provider

Create custom provider for internal cloud:

# Generate provider scaffold
provisioning generate provider internal-cloud \
    --type cloud \
    --api rest

Custom Cluster

Define complete deployment configuration:

# Create cluster configuration
provisioning generate cluster my-stack \
    --servers 5 \
    --taskservs "kubernetes,postgres,redis" \
    --customize

Configuration Inheritance

Child configurations inherit and override parent settings:

# Base: workspace/config/provisioning.yaml
defaults:
  server_plan: "2xCPU-4GB"
  region: "de-fra1"

# Override: workspace/infra/prod/config.toml
[servers]
plan = "8xCPU-16GB"  # Overrides default
# region inherited: de-fra1

Variable Interpolation

Use variables for dynamic configuration:

workspace:
  name: "{{env.PROJECT_NAME}}"

servers:
  hostname_prefix: "{{workspace.name}}-server"
  zone: "{{defaults.region}}"

paths:
  base: "{{env.HOME}}/provisioning"
  workspace: "{{paths.base}}/workspace"

Supported variables:

  • {{env.*}} - Environment variables
  • {{workspace.*}} - Workspace config
  • {{defaults.*}} - Default values
  • {{paths.*}} - Path configuration
  • {{now.date}} - Current date
  • {{git.branch}} - Git branch name

Customization Examples

Example 1: Multi-Environment Setup

# workspace/envs/dev/config.yaml
environment: development
server_count: 1
server_plan: small

# workspace/envs/prod/config.yaml
environment: production
server_count: 5
server_plan: large
high_availability: true
# Deploy to dev
provisioning cluster create app --env dev

# Deploy to prod
provisioning cluster create app --env prod

Example 2: Custom Monitoring Stack

# Create custom monitoring configuration
cat > workspace/infra/monitoring/config.toml <<EOF
[taskservs]
enabled = [
    "prometheus",
    "grafana",
    "alertmanager",
    "loki"
]

[prometheus]
retention = "30d"
storage = "100GB"

[grafana]
admin_user = "admin"
plugins = ["cloudflare", "postgres"]
EOF

# Apply monitoring stack
provisioning cluster create monitoring --config monitoring/config.toml

Example 3: Development vs Production

# Development: lightweight, fast
provisioning cluster create app \
    --profile dev \
    --servers 1 \
    --plan small

# Production: robust, HA
provisioning cluster create app \
    --profile prod \
    --servers 5 \
    --plan large \
    --ha \
    --backup-enabled

Advanced Customization

Custom Workflows

Create custom deployment workflows:

# workspace/workflows/my-deploy.k
import provisioning.workflows as wf

my_deployment: wf.BatchWorkflow = {
    name = "custom-deployment"
    operations = [
        # Your custom steps
    ]
}

Custom Validation Rules

Add validation for your infrastructure:

# workspace/extensions/validation/my-rules.nu
export def validate-my-infra [config: record] {
    # Custom validation logic
    if $config.servers < 3 {
        error make {msg: "Production requires 3+ servers"}
    }
}

Custom Hooks

Execute custom actions at deployment stages:

# workspace/config/hooks.yaml
hooks:
  pre_create_servers:
    - script: "scripts/validate-quota.sh"
  post_create_servers:
    - script: "scripts/configure-monitoring.sh"
  pre_install_taskserv:
    - script: "scripts/check-dependencies.sh"

Best Practices

DO ✅

  • Use workspace config for project-specific settings
  • Create templates for reusable patterns
  • Use variables for dynamic configuration
  • Document custom extensions
  • Test customizations in dev environment

DON’T ❌

  • Modify core defaults directly
  • Hardcode environment-specific values
  • Skip validation steps
  • Create circular dependencies
  • Bypass security policies

Testing Customizations

# Validate configuration
provisioning validate config --strict

# Test in isolated environment
provisioning test env cluster my-custom-setup --check

# Dry run deployment
provisioning cluster create test --check --verbose

Need Help? Run provisioning help customize or see User Guide.