Files
volt/docs/compose.md
Karl Clinger 81ad0b597c Volt CLI: source-available under AGPSL v5.0
Complete infrastructure platform CLI:
- Container runtime (systemd-nspawn)
- VoltVisor VMs (Neutron Stardust / QEMU)
- Stellarium CAS (content-addressed storage)
- ORAS Registry
- GitOps integration
- Landlock LSM security
- Compose orchestration
- Mesh networking

Copyright (c) Armored Gates LLC. All rights reserved.
Licensed under AGPSL v5.0
2026-03-21 00:31:12 -05:00

742 lines
15 KiB
Markdown

# 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 <path>` 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:
<name>:
image: <string> # Image name (required)
build: # Build configuration (optional)
context: <path> # Build context directory
file: <path> # 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: <int> # Max restart attempts (for on-failure)
resources:
cpu: "<number>" # CPU shares/quota
memory: <size> # e.g., 256M, 1G
memory_swap: <size> # Swap limit
healthcheck:
command: ["cmd", "args"] # Health check command
interval: <duration> # Check interval (e.g., 30s)
timeout: <duration> # Check timeout
retries: <int> # Retries before unhealthy
start_period: <duration> # 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:
<name>:
image: <string> # Base image (required)
cpu: <int> # vCPU count
memory: <size> # Memory allocation (e.g., 4G)
disks: # Additional disks
- name: <string>
size: <size>
mount: <path> # Mount point inside VM
networks:
- network_name
ports:
- "host:vm"
provision: # First-boot scripts
- name: <string>
shell: |
commands to run
healthcheck:
command: ["cmd", "args"]
interval: <duration>
timeout: <duration>
retries: <int>
restart: no|always|on-failure
tune: # Performance tuning
cpu_pin: [<int>, ...] # Pin to physical CPUs
hugepages: <bool> # Use hugepages
io_scheduler: <string> # 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:
<name>:
unit:
type: simple|oneshot|forking|notify
exec: <string> # Command to run (required)
user: <string>
group: <string>
restart: no|always|on-failure
networks:
- network_name
healthcheck:
command: ["cmd", "args"]
interval: <duration>
resources:
memory: <size>
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:
<name>:
exec: <string> # Command to run (required)
schedule:
on_calendar: <string> # systemd calendar syntax
every: <duration> # Alternative: interval
environment:
KEY: value
user: <string>
persistent: <bool> # 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:
<name>:
driver: bridge # Network driver (default: bridge)
subnet: <cidr> # e.g., 10.20.0.0/24
internal: <bool> # If true, no external access
options:
mtu: <int> # 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:
<name>:
driver: local # Storage driver
size: <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:
<name>:
file: <path> # Path to config file
secrets:
<name>:
file: <path> # 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
```