Skip to content

Provisioning

Provisioning in Odin defines how and where components are deployed. While service definitions describe what to deploy, provisioning configurations specify the deployment details for each cloud provider and platform.

Provisioning configuration maps components to actual cloud resources:

  • Kubernetes deployments: Pods, services, ingress
  • AWS resources: EC2 instances, RDS databases, ElastiCache
  • GCP resources: Compute Engine, Cloud SQL, Memorystore
  • Azure resources: VMs, Azure Database, Cache for Redis

Provisioning configs are JSON files that specify deployment parameters for each component:

[
{
"component_name": "api-server",
"deployment_type": "kubernetes-deployment",
"params": {
"namespace": "production",
"cpu": "2",
"memory": "4Gi",
"image": "myregistry/user-api:1.0.0"
},
"env_variables": {
"DB_HOST": "postgres.prod.svc.cluster.local",
"CACHE_URL": "redis://cache:6379"
}
},
{
"component_name": "database",
"deployment_type": "rds-postgres",
"params": {
"instance_class": "db.t3.medium",
"storage": "100",
"multi_az": true
}
}
]

Each provisioning entry contains:

PropertyRequiredDescription
component_nameYesMust match a component in the service definition
deployment_typeYesProvider-specific deployment type
paramsYesDeployment-specific parameters (varies by type)
env_variablesNoEnvironment variables to inject

Different deployment types are available for different platforms:

Deploy a containerized application:

{
"component_name": "api",
"deployment_type": "kubernetes-deployment",
"params": {
"namespace": "staging",
"cpu": "500m",
"memory": "1Gi",
"replicas": 3,
"image": "myregistry/api:1.0.0",
"port": 8080,
"service_type": "LoadBalancer"
},
"env_variables": {
"LOG_LEVEL": "info",
"DB_CONNECTION_STRING": "postgres://db:5432/myapp"
}
}

Deploy a stateful application:

{
"component_name": "cache",
"deployment_type": "kubernetes-statefulset",
"params": {
"namespace": "staging",
"cpu": "1",
"memory": "2Gi",
"replicas": 3,
"image": "redis:7.0",
"volume_size": "10Gi",
"storage_class": "fast-ssd"
}
}

Deploy a managed database:

{
"component_name": "database",
"deployment_type": "rds-postgres",
"params": {
"instance_class": "db.r5.large",
"storage": "200",
"storage_type": "gp3",
"multi_az": true,
"backup_retention_days": 7,
"engine_version": "14.5",
"subnet_group": "private-db-subnet",
"security_groups": ["sg-12345678"]
}
}

Deploy a managed Redis cluster:

{
"component_name": "cache",
"deployment_type": "elasticache-redis",
"params": {
"node_type": "cache.r5.large",
"num_nodes": 3,
"engine_version": "7.0",
"subnet_group": "private-cache-subnet",
"security_groups": ["sg-87654321"],
"automatic_failover": true
}
}

Deploy on EC2:

{
"component_name": "worker",
"deployment_type": "ec2-instance",
"params": {
"instance_type": "t3.medium",
"ami": "ami-12345678",
"vpc_id": "vpc-abcdef",
"subnet_id": "subnet-123456",
"key_name": "my-keypair",
"security_groups": ["sg-11111111"],
"user_data": "#!/bin/bash\n# initialization script"
},
"env_variables": {
"SERVICE_PORT": "8080"
}
}

Deploy on Google Compute Engine:

{
"component_name": "app",
"deployment_type": "gce-instance",
"params": {
"machine_type": "n1-standard-2",
"zone": "us-central1-a",
"image": "projects/debian-cloud/global/images/debian-11",
"network": "default",
"disk_size": "50"
}
}

Deploy Cloud SQL:

{
"component_name": "database",
"deployment_type": "cloudsql-postgres",
"params": {
"tier": "db-n1-standard-2",
"database_version": "POSTGRES_14",
"region": "us-central1",
"availability_type": "REGIONAL",
"disk_size": "100"
}
}

Provisioning configs can inject environment variables into components:

{
"component_name": "api",
"deployment_type": "kubernetes-deployment",
"params": {
"namespace": "production",
"image": "myregistry/api:1.0.0"
},
"env_variables": {
"NODE_ENV": "production",
"LOG_LEVEL": "warn",
"DB_HOST": "database.prod.example.com",
"DB_PORT": "5432",
"DB_NAME": "myapp",
"CACHE_URL": "redis://cache.prod.example.com:6379",
"API_TIMEOUT": "30000"
}
}

When deploying a service, provide both the service definition and provisioning config:

Terminal window
odin deploy service --env staging \
--file service.json \
--provisioning provisioning.json

Odin validates that:

  • Every component in the service has a provisioning config
  • All component_name values match components in the service
  • Deployment types are supported
  • Required parameters are provided

You can create different provisioning configs for different environments:

provisioning-dev.json:

[
{
"component_name": "api",
"deployment_type": "kubernetes-deployment",
"params": {
"namespace": "dev",
"cpu": "100m",
"memory": "256Mi",
"replicas": 1,
"image": "myregistry/api:dev"
}
},
{
"component_name": "database",
"deployment_type": "rds-postgres",
"params": {
"instance_class": "db.t3.micro",
"storage": "20"
}
}
]

provisioning-prod.json:

[
{
"component_name": "api",
"deployment_type": "kubernetes-deployment",
"params": {
"namespace": "production",
"cpu": "2",
"memory": "4Gi",
"replicas": 10,
"image": "myregistry/api:1.0.0"
}
},
{
"component_name": "database",
"deployment_type": "rds-postgres",
"params": {
"instance_class": "db.r5.2xlarge",
"storage": "500",
"multi_az": true,
"backup_retention_days": 30
}
}
]

Deploy to different environments:

Terminal window
# Dev
odin deploy service --env dev \
--file service.json \
--provisioning provisioning-dev.json
# Production
odin deploy service --env prod \
--file service.json \
--provisioning provisioning-prod.json

Don’t use the same provisioning config for all environments. Create specific configs:

provisioning/
├── dev.json
├── staging.json
└── production.json

Development:

  • Small instances/resources
  • Minimal replicas
  • Basic monitoring

Production:

  • Right-sized based on load testing
  • High availability (multi-AZ, replicas)
  • Enhanced monitoring and backups

Use secret management tools instead of hardcoding:

{
"env_variables": {
"DB_PASSWORD": "${SECRET:db-password}",
"API_KEY": "${SECRET:api-key}"
}
}

Isolate environments with network configuration:

{
"params": {
"vpc_id": "vpc-prod-12345",
"subnet_id": "subnet-private-67890",
"security_groups": ["sg-app-prod"]
}
}

Add tags for cost tracking and organization:

{
"params": {
"tags": {
"Environment": "production",
"Team": "backend",
"CostCenter": "engineering",
"Service": "user-api"
}
}
}

service.json:

{
"name": "user-api",
"version": "1.0.0",
"team": "backend",
"components": [
{
"name": "api",
"type": "webservice",
"version": "1.0.0",
"depends_on": ["database", "cache"]
},
{
"name": "database",
"type": "postgres",
"version": "14.5"
},
{
"name": "cache",
"type": "redis",
"version": "7.0"
}
]
}

provisioning.json:

[
{
"component_name": "api",
"deployment_type": "kubernetes-deployment",
"params": {
"namespace": "production",
"cpu": "2",
"memory": "4Gi",
"replicas": 5,
"image": "myregistry/user-api:1.0.0",
"port": 8080,
"service_type": "LoadBalancer"
},
"env_variables": {
"NODE_ENV": "production",
"LOG_LEVEL": "info",
"DB_HOST": "user-db.prod.rds.amazonaws.com",
"DB_PORT": "5432",
"DB_NAME": "userdb",
"CACHE_HOST": "cache.prod.cache.amazonaws.com",
"CACHE_PORT": "6379"
}
},
{
"component_name": "database",
"deployment_type": "rds-postgres",
"params": {
"instance_class": "db.r5.xlarge",
"storage": "200",
"storage_type": "gp3",
"multi_az": true,
"engine_version": "14.5",
"backup_retention_days": 14,
"backup_window": "03:00-04:00",
"maintenance_window": "sun:04:00-sun:05:00",
"subnet_group": "private-db-subnet",
"security_groups": ["sg-db-prod"]
}
},
{
"component_name": "cache",
"deployment_type": "elasticache-redis",
"params": {
"node_type": "cache.r5.large",
"num_nodes": 3,
"engine_version": "7.0",
"subnet_group": "private-cache-subnet",
"security_groups": ["sg-cache-prod"],
"automatic_failover": true,
"snapshot_retention_limit": 7
}
}
]

Deploy:

Terminal window
odin deploy service --env production \
--file service.json \
--provisioning provisioning.json