- 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/
496 lines
13 KiB
Plaintext
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"
|
|
}
|
|
}
|
|
}
|