Jesús Pérez 44648e3206
chore: complete nickel migration and consolidate legacy configs
- Remove KCL ecosystem (~220 files deleted)
- Migrate all infrastructure to Nickel schema system
- Consolidate documentation: legacy docs → provisioning/docs/src/
- Add CI/CD workflows (.github/) and Rust build config (.cargo/)
- Update core system for Nickel schema parsing
- Update README.md and CHANGES.md for v5.0.0 release
- Fix pre-commit hooks: end-of-file, trailing-whitespace
- Breaking changes: KCL workspaces require migration
- Migration bridge available in docs/src/development/
2026-01-08 09:55:37 +00:00

496 lines
13 KiB
Plaintext

# Multi-Provider Web Application Workspace
# Architecture: DigitalOcean (compute) + AWS (database) + Hetzner (storage)
#
# This workspace demonstrates a realistic three-provider setup where:
# - DigitalOcean provides cost-effective web servers with load balancing
# - AWS provides a managed PostgreSQL database with high availability
# - Hetzner provides affordable backup storage
#
# Cost: ~$77/month (vs $150+ for all-cloud setup)
# Deployment: 3 regions, 8 total compute instances, managed database
let hetzner = import "../../../extensions/providers/hetzner/nickel/main.ncl" in
let aws = import "../../../extensions/providers/aws/nickel/main.ncl" in
let digitalocean = import "../../../extensions/providers/digitalocean/nickel/main.ncl" in
{
# Workspace Metadata
workspace_name = "multi-provider-web-app",
description = "Web application across three cloud providers",
version = "1.0",
# Provider Configuration
providers = {
digitalocean_primary = "digitalocean",
aws_database = "aws",
hetzner_backup = "hetzner"
},
# Environment and Tags
environment = "production",
owner = "platform-team",
cost_center = "engineering",
tags = {
"project" = "web-app",
"deployment" = "multi-provider",
"environment" = "production",
"managed-by" = "provisioning-system"
},
# =============================================================================
# Networking Infrastructure
# =============================================================================
networks = {
# DigitalOcean VPC
do_vpc = digitalocean.VPC & {
name = "web-app-vpc",
region = "nyc3",
ip_range = "10.0.0.0/16",
description = "Private network for web tier"
},
# AWS VPC
aws_vpc = aws.VPC & {
cidr_block = "10.1.0.0/16",
enable_dns_hostnames = true,
enable_dns_support = true,
tags = [
{ key = "Name", value = "db-vpc" }
]
},
# AWS Private Subnet for RDS
aws_db_subnet = aws.Subnet & {
vpc_id = "{{ aws_vpc.id }}",
cidr_block = "10.1.1.0/24",
availability_zone = "us-east-1a",
map_public_ip_on_launch = false,
tags = [
{ key = "Name", value = "db-subnet" }
]
},
# Hetzner Private Network
hetzner_network = hetzner.Network & {
name = "backup-network",
ip_range = "10.2.0.0/16",
labels = { "tier" = "backup" }
},
# Hetzner Subnet for backup storage
hetzner_subnet = hetzner.Subnet & {
network = "backup-network",
network_zone = "eu-central",
ip_range = "10.2.1.0/24"
}
},
# VPN Tunnels between providers
vpn_tunnels = {
do_to_aws = {
name = "do-aws-vpn",
protocol = "ipsec",
source_provider = "digitalocean",
source_network = "10.0.0.0/16",
destination_provider = "aws",
destination_network = "10.1.0.0/16",
encryption = "aes-256",
authentication = "sha256",
description = "IPSec tunnel from DO web tier to AWS database"
},
aws_to_hetzner = {
name = "aws-hz-vpn",
protocol = "ipsec",
source_provider = "aws",
source_network = "10.1.0.0/16",
destination_provider = "hetzner",
destination_network = "10.2.0.0/16",
encryption = "aes-256",
authentication = "sha256",
description = "IPSec tunnel from AWS database to Hetzner backup"
}
},
# =============================================================================
# DigitalOcean: Web Tier (3 Droplets + Load Balancer)
# =============================================================================
web_tier = {
# Web Application Servers
# - 3 droplets for high availability
# - 2 vCPU, 4GB RAM each
# - Ubuntu 22.04 LTS
# - Behind load balancer
# - Cost: $24/month each = $72/month total
droplets = digitalocean.Droplet & {
name = "web-server",
region = "nyc3",
size = "s-2vcpu-4gb",
image = "ubuntu-22-04-x64",
count = 3,
# Attach to private VPC
vpc_uuid = "{{ networks.do_vpc.id }}",
# SSH Configuration
ssh_keys = ["default"], # Reference your SSH key ID
# Backup Configuration
backups = true,
# Monitoring
monitoring = true,
# IPv6 Support
ipv6 = true,
# Volumes to attach
volumes = [
{
size = 50,
name = "web-data",
filesystem_type = "ext4",
filesystem_label = "web"
}
],
# Firewall Rules
firewall = {
inbound_rules = [
# SSH from anywhere (restrict this in production!)
{
protocol = "tcp",
ports = "22",
sources = {
addresses = ["0.0.0.0/0"]
}
},
# HTTP from load balancer
{
protocol = "tcp",
ports = "80",
sources = {
addresses = ["0.0.0.0/0"] # Load balancer IPs
}
},
# HTTPS from load balancer
{
protocol = "tcp",
ports = "443",
sources = {
addresses = ["0.0.0.0/0"] # Load balancer IPs
}
},
# Database access to AWS RDS
{
protocol = "tcp",
ports = "5432",
sources = {
addresses = ["10.0.0.0/8"] # AWS VPC
}
}
],
outbound_rules = [
# Allow all TCP outbound
{
protocol = "tcp",
destinations = {
addresses = ["0.0.0.0/0"]
}
},
# Allow DNS
{
protocol = "udp",
ports = "53",
destinations = {
addresses = ["8.8.8.8/32", "8.8.4.4/32"]
}
}
]
},
# Tags for organization
tags = ["web", "production", "multi-provider"]
},
# Load Balancer
# - Round-robin load balancing
# - Health checks every 10 seconds
# - SSL/TLS termination
# - Sticky sessions with 5-minute TTL
# - Cost: Free (included with droplets)
load_balancer = digitalocean.LoadBalancer & {
name = "web-lb",
algorithm = "round_robin",
region = "nyc3",
# Forwarding Rules
forwarding_rules = [
# HTTP -> HTTP (port 80)
{
entry_protocol = "http",
entry_port = 80,
target_protocol = "http",
target_port = 80,
certificate_id = null
},
# HTTPS -> HTTP (SSL termination at LB)
{
entry_protocol = "https",
entry_port = 443,
target_protocol = "http",
target_port = 80,
certificate_id = "your-certificate-id"
}
],
# Health Checks
health_check = {
protocol = "http",
port = 80,
path = "/health",
check_interval_seconds = 10,
response_timeout_seconds = 5,
healthy_threshold = 5,
unhealthy_threshold = 3
},
# Sticky Sessions (for session affinity)
sticky_sessions = {
type = "cookies",
cookie_name = "LB_SESSION",
cookie_ttl_seconds = 300
}
}
},
# =============================================================================
# AWS: Database Tier (Managed PostgreSQL RDS)
# =============================================================================
database_tier = aws.RDS & {
identifier = "webapp-db",
engine = "postgres",
engine_version = "14.6",
instance_class = "db.t3.medium",
allocated_storage = 100,
storage_type = "gp3",
storage_iops = 3000,
storage_throughput = 125,
# High Availability
multi_az = true,
publicly_accessible = false,
# Backups
backup_retention_days = 30,
backup_window = "03:00-04:00",
maintenance_window = "sun:04:00-sun:05:00",
skip_final_snapshot = false,
final_snapshot_identifier = "webapp-db-final-snapshot",
# Performance Insights
performance_insights_enabled = true,
performance_insights_retention_period = 7,
# Database Configuration
parameter_group_name = "default.postgres14",
storage_encrypted = true,
enable_cloudwatch_logs_exports = ["postgresql"],
# Monitoring
enable_enhanced_monitoring = true,
monitoring_interval = 60,
# Tags
tags = [
{ key = "Environment", value = "production" },
{ key = "Application", value = "web-app" },
{ key = "Provider", value = "aws" }
]
},
# =============================================================================
# Hetzner: Backup Storage (Affordable Volume Storage)
# =============================================================================
backup_storage = hetzner.Volume & {
name = "webapp-backups",
size = 500, # 500 GB
location = "nbg1",
automount = false,
format = "ext4",
labels = {
"purpose" = "database-backups",
"retention" = "30-days",
"provider" = "hetzner"
}
},
# =============================================================================
# Network Configuration
# =============================================================================
networking = {
# VPC/Network definitions would go here
# For multi-provider, you typically need:
# - VPN tunnel between providers
# - Peering configurations
# - Security group coordination
vpn_tunnels = [
{
name = "do-aws-vpn",
source_provider = "digitalocean",
destination_provider = "aws",
protocol = "ipsec",
encryption = "aes-256",
authentication = "sha256"
},
{
name = "aws-hetzner-vpn",
source_provider = "aws",
destination_provider = "hetzner",
protocol = "ipsec",
encryption = "aes-256",
authentication = "sha256"
}
]
},
# =============================================================================
# Deployment Configuration
# =============================================================================
deployment = {
strategy = "rolling",
batch_size = 1,
health_check_wait = 60,
rollback_on_failure = true,
# Deployment order
order = [
"hetzner.backup_storage",
"aws.database_tier",
"digitalocean.web_tier"
]
},
# =============================================================================
# Monitoring and Alerting
# =============================================================================
monitoring = {
enabled = true,
# DigitalOcean Monitoring
digitalocean_metrics = {
cpu_threshold = 80,
memory_threshold = 85,
disk_threshold = 90,
network_alert = true
},
# AWS CloudWatch
aws_metrics = {
database_cpu = 75,
database_connections = 100,
database_disk = 90,
rds_failover_alerts = true
},
# Hetzner Monitoring (via custom scripts)
hetzner_metrics = {
volume_usage = 85,
disk_iops = true
},
# Alerting
alerts = [
{
condition = "web_tier.cpu > 80%",
action = "scale_up",
notification = "slack:#alerts"
},
{
condition = "database_tier.connection_count > 100",
action = "alert",
notification = "email:ops@example.com"
},
{
condition = "backup_storage.usage > 85%",
action = "alert",
notification = "pagerduty:on-call"
}
]
},
# =============================================================================
# Backup and Disaster Recovery
# =============================================================================
backup_strategy = {
frequency = "daily",
retention_days = 30,
locations = ["digitalocean", "aws", "hetzner"],
procedures = [
{
name = "daily-database-backup",
type = "aws-rds",
frequency = "daily",
retention = "30-days"
},
{
name = "weekly-full-backup",
type = "full",
frequency = "weekly",
destination = "hetzner-backup-volume",
retention = "90-days"
}
]
},
# =============================================================================
# Cost Tracking
# =============================================================================
cost_estimate = {
monthly_breakdown = {
digitalocean = {
droplets = "$72.00", # 3 x $24/month
load_balancer = "$0.00", # Included
volumes = "$5.00",
subtotal = "$77.00"
},
aws = {
rds_db_t3_medium = "$60.00",
enhanced_monitoring = "$5.00",
data_transfer = "$10.00",
subtotal = "$75.00"
},
hetzner = {
volume_500gb = "$13.00",
subtotal = "$13.00"
},
total_monthly = "$165.00",
total_annual = "$1980.00"
}
}
}