# Voltfile / Constellation Format A **Constellation** is the definition of how containers, VMs, services, and resources form a coherent system. `volt compose` manages Constellations as declarative multi-service stacks — define containers, VMs, services, tasks, networks, and volumes in a single YAML file and deploy them together. ## File Discovery `volt compose` looks for Constellation definitions in this order: 1. `-f ` flag (explicit) 2. `volt-compose.yaml` in current directory 3. `volt-compose.yml` in current directory 4. `Voltfile` in current directory (YAML format) ## Quick Example ```yaml version: "1" name: web-stack containers: web: image: armoredgate/nginx:1.25 ports: - "80:80" networks: - frontend depends_on: api: condition: service_started api: image: armoredgate/node:20 ports: - "8080:8080" environment: DATABASE_URL: "postgresql://app:secret@db:5432/myapp" networks: - frontend - backend vms: db: image: armoredgate/ubuntu-24.04 cpu: 2 memory: 4G networks: - backend networks: frontend: subnet: 10.20.0.0/24 backend: subnet: 10.30.0.0/24 internal: true ``` Deploy: ```bash volt compose up -d # Create and start in background volt compose ps # Check status volt compose logs -f # Follow all logs volt compose down # Tear down ``` ## Top-Level Keys | Key | Type | Required | Description | |-----|------|----------|-------------| | `version` | string | Yes | File format version. Currently `"1"`. | | `name` | string | No | Stack name. Used as prefix for workload names. | | `description` | string | No | Human-readable description. | | `containers` | map | No | Container definitions (Voltainer). | | `vms` | map | No | VM definitions (Voltvisor). | | `services` | map | No | systemd service definitions. | | `tasks` | map | No | Scheduled task definitions. | | `networks` | map | No | Network definitions. | | `volumes` | map | No | Volume definitions. | | `configs` | map | No | Configuration file references. | | `secrets` | map | No | Secret file references. | ## Container Definition ```yaml containers: : image: # Image name (required) build: # Build configuration (optional) context: # Build context directory file: # Build spec file ports: # Port mappings - "host:container" volumes: # Volume mounts - host_path:container_path[:ro] - volume_name:container_path networks: # Networks to join - network_name environment: # Environment variables KEY: value env_file: # Load env vars from files - .env depends_on: # Dependencies other_service: condition: service_started|service_healthy|service_completed_successfully restart: no|always|on-failure|unless-stopped restart_max_retries: # Max restart attempts (for on-failure) resources: cpu: "" # CPU shares/quota memory: # e.g., 256M, 1G memory_swap: # Swap limit healthcheck: command: ["cmd", "args"] # Health check command interval: # Check interval (e.g., 30s) timeout: # Check timeout retries: # Retries before unhealthy start_period: # Grace period on start labels: key: value ``` ### Container Example ```yaml containers: app-server: image: armoredgate/node:20 build: context: ./app file: build-spec.yaml ports: - "8080:8080" volumes: - app-data:/app/data - ./config:/app/config:ro networks: - backend environment: NODE_ENV: production DATABASE_URL: "postgresql://app:${DB_PASSWORD}@db:5432/myapp" env_file: - .env - .env.production depends_on: db: condition: service_healthy cache: condition: service_started restart: on-failure restart_max_retries: 5 resources: cpu: "2" memory: 1G memory_swap: 2G healthcheck: command: ["curl", "-sf", "http://localhost:8080/health"] interval: 15s timeout: 3s retries: 5 ``` ## VM Definition ```yaml vms: : image: # Base image (required) cpu: # vCPU count memory: # Memory allocation (e.g., 4G) disks: # Additional disks - name: size: mount: # Mount point inside VM networks: - network_name ports: - "host:vm" provision: # First-boot scripts - name: shell: | commands to run healthcheck: command: ["cmd", "args"] interval: timeout: retries: restart: no|always|on-failure tune: # Performance tuning cpu_pin: [, ...] # Pin to physical CPUs hugepages: # Use hugepages io_scheduler: # I/O scheduler ``` ### VM Example ```yaml vms: db-primary: image: armoredgate/ubuntu-24.04 cpu: 4 memory: 8G disks: - name: system size: 40G - name: pgdata size: 200G mount: /var/lib/postgresql/data networks: - backend ports: - "5432:5432" provision: - name: install-postgres shell: | apt-get update && apt-get install -y postgresql-16 systemctl enable postgresql healthcheck: command: ["pg_isready", "-U", "postgres"] interval: 30s timeout: 5s retries: 3 restart: always tune: cpu_pin: [4, 5, 6, 7] hugepages: true io_scheduler: none ``` ## Service Definition Define systemd services managed by the Constellation: ```yaml services: : unit: type: simple|oneshot|forking|notify exec: # Command to run (required) user: group: restart: no|always|on-failure networks: - network_name healthcheck: command: ["cmd", "args"] interval: resources: memory: depends_on: other_service: condition: service_started ``` ### Service Example ```yaml services: cache-redis: unit: type: simple exec: "/usr/bin/redis-server /etc/redis/redis.conf" user: redis group: redis restart: always networks: - backend healthcheck: command: ["redis-cli", "ping"] interval: 10s resources: memory: 512M ``` ## Task Definition Define scheduled tasks (systemd timers): ```yaml tasks: : exec: # Command to run (required) schedule: on_calendar: # systemd calendar syntax every: # Alternative: interval environment: KEY: value user: persistent: # Run missed tasks on boot ``` ### Task Example ```yaml tasks: db-backup: exec: "/usr/local/bin/backup.sh --target db-primary" schedule: on_calendar: "*-*-* 02:00:00" environment: BACKUP_DEST: /mnt/backups cleanup: exec: "/usr/local/bin/cleanup-old-logs.sh" schedule: every: 6h ``` ## Network Definition ```yaml networks: : driver: bridge # Network driver (default: bridge) subnet: # e.g., 10.20.0.0/24 internal: # If true, no external access options: mtu: # MTU (default: 1500) ``` ### Network Examples ```yaml networks: # Public-facing network frontend: driver: bridge subnet: 10.20.0.0/24 options: mtu: 9000 # Internal only — no external access backend: driver: bridge subnet: 10.30.0.0/24 internal: true ``` ## Volume Definition ```yaml volumes: : driver: local # Storage driver size: # Optional size for file-backed volumes ``` ### Volume Examples ```yaml volumes: web-static: driver: local app-data: driver: local size: 10G pgdata: driver: local size: 200G ``` ## Configs and Secrets ```yaml configs: : file: # Path to config file secrets: : file: # Path to secret file ``` ### Example ```yaml configs: nginx-conf: file: ./config/nginx.conf app-env: file: ./.env.production secrets: db-password: file: ./secrets/db-password.txt tls-cert: file: ./secrets/server.crt tls-key: file: ./secrets/server.key ``` ## Dependency Conditions When specifying `depends_on`, the `condition` field controls when the dependent service starts: | Condition | Description | |-----------|-------------| | `service_started` | Dependency has started (default) | | `service_healthy` | Dependency passes its health check | | `service_completed_successfully` | Dependency ran and exited with code 0 | ```yaml depends_on: db: condition: service_healthy migrations: condition: service_completed_successfully cache: condition: service_started ``` ## Environment Variable Interpolation The Constellation definition supports shell-style variable interpolation: ```yaml environment: DATABASE_URL: "postgresql://app:${DB_PASSWORD}@db:5432/myapp" APP_VERSION: "${APP_VERSION:-latest}" ``` Variables are resolved from: 1. Host environment variables 2. `.env` file in the same directory as the Constellation definition 3. Files specified in `env_file` Unset variables with no default cause an error. ## Compose Commands ### Lifecycle ```bash # Deploy the Constellation — create and start everything volt compose up # Detached mode (background) volt compose up -d # Specific Constellation file volt compose -f production.yaml up -d # Build images first volt compose up --build # Force recreate volt compose up --force-recreate # Tear down the Constellation volt compose down # Also remove volumes volt compose down --volumes ``` ### Status and Logs ```bash # Stack status volt compose ps # All logs volt compose logs # Follow logs volt compose logs --follow # Logs for one service volt compose logs api # Last 50 lines volt compose logs --tail 50 api # Resource usage volt compose top # Events volt compose events ``` ### Operations ```bash # Start existing (without recreating) volt compose start # Stop (without removing) volt compose stop # Restart volt compose restart # Execute command in a service volt compose exec api -- node --version # Pull images volt compose pull # Build images volt compose build # Validate Constellation volt compose config ``` ### Project Naming ```bash # Override project name volt compose --project my-project up # This prefixes all workload names: my-project-web, my-project-api, etc. ``` ## Full Example: Production Constellation ```yaml # volt-compose.yaml — Production Constellation version: "1" name: production description: "Production web application" containers: web-proxy: image: armoredgate/nginx:1.25 ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - web-static:/usr/share/nginx/html:ro networks: - frontend - backend depends_on: app-server: condition: service_healthy restart: always resources: cpu: "0.5" memory: 256M healthcheck: command: ["curl", "-sf", "http://localhost/health"] interval: 30s timeout: 5s retries: 3 start_period: 10s app-server: image: armoredgate/node:20 build: context: ./app file: build-spec.yaml environment: NODE_ENV: production DATABASE_URL: "postgresql://app:${DB_PASSWORD}@db-primary:5432/myapp" REDIS_URL: "redis://cache-redis:6379" env_file: - .env.production ports: - "8080:8080" volumes: - app-data:/app/data networks: - backend depends_on: db-primary: condition: service_healthy cache-redis: condition: service_started restart: on-failure restart_max_retries: 5 resources: cpu: "2" memory: 1G healthcheck: command: ["curl", "-sf", "http://localhost:8080/health"] interval: 15s timeout: 3s retries: 5 vms: db-primary: image: armoredgate/ubuntu-24.04 cpu: 4 memory: 8G disks: - name: system size: 40G - name: pgdata size: 200G mount: /var/lib/postgresql/data networks: - backend ports: - "5432:5432" provision: - name: install-postgres shell: | apt-get update && apt-get install -y postgresql-16 systemctl enable postgresql healthcheck: command: ["pg_isready", "-U", "postgres"] interval: 30s timeout: 5s retries: 3 restart: always tune: cpu_pin: [4, 5, 6, 7] hugepages: true io_scheduler: none services: cache-redis: unit: type: simple exec: "/usr/bin/redis-server /etc/redis/redis.conf" user: redis group: redis restart: always networks: - backend healthcheck: command: ["redis-cli", "ping"] interval: 10s resources: memory: 512M log-shipper: unit: type: simple exec: "/usr/local/bin/vector --config /etc/vector/vector.toml" restart: on-failure depends_on: app-server: condition: service_started tasks: db-backup: exec: "/usr/local/bin/backup.sh --target db-primary" schedule: on_calendar: "*-*-* 02:00:00" environment: BACKUP_DEST: /mnt/backups cleanup: exec: "/usr/local/bin/cleanup-old-logs.sh" schedule: every: 6h networks: frontend: driver: bridge subnet: 10.20.0.0/24 options: mtu: 9000 backend: driver: bridge subnet: 10.30.0.0/24 internal: true volumes: web-static: driver: local app-data: driver: local size: 10G configs: nginx-conf: file: ./config/nginx.conf secrets: db-password: file: ./secrets/db-password.txt tls-cert: file: ./secrets/server.crt tls-key: file: ./secrets/server.key ``` ## Full Example: Developer Constellation ```yaml # volt-compose.yaml — Developer Constellation version: "1" name: dev-environment vms: dev-box: image: armoredgate/fedora-workstation cpu: 4 memory: 8G disks: - name: system size: 80G volumes: - ~/projects:/home/dev/projects networks: - devnet ports: - "2222:22" - "3000:3000" - "5173:5173" provision: - name: dev-tools shell: | dnf install -y git nodejs rust golang npm install -g pnpm containers: test-db: image: armoredgate/postgres:16 environment: POSTGRES_PASSWORD: devpass POSTGRES_DB: myapp_dev volumes: - test-pgdata:/var/lib/postgresql/data networks: - devnet ports: - "5432:5432" mailhog: image: armoredgate/mailhog:latest networks: - devnet ports: - "1025:1025" - "8025:8025" networks: devnet: subnet: 10.99.0.0/24 volumes: test-pgdata: driver: local ```