Cloud Support Matrix
Caracal ships three deployment models. The stack itself is provider-neutral: the same released images, the same environment contract, the same schema migrations. Each model has a provider-neutral core and a small adapter per cloud, so a provider is a translation layer rather than a branch in the deployment logic. To add one, see Add a Cloud Provider.
Status
Section titled “Status”| Model | Core | Azure | AWS | Google Cloud |
|---|---|---|---|---|
| Virtual machine | caracalHost cloud-init | Supported | Experimental | Experimental |
| Managed container platform | containerPlatform topology | Supported (Container Apps) | Experimental (ECS on Fargate) | Experimental (Cloud Run) |
| Kubernetes | Helm chart | Supported (AKS overlay) | Experimental (EKS overlay) | Experimental (GKE overlay) |
Supported means the adapter is implemented, validated in CI, and exercised against a live account. It is not a capacity, availability, or compliance claim.
Experimental means the adapter renders, validates against the provider’s own schema, and satisfies the shared contract, but has not been deployed to a live account. Azure is the reference implementation; treat the others as a starting point you verify in your own environment.
What Never Changes
Section titled “What Never Changes”These hold on every cloud and every model, and no adapter may alter them:
- The published images, with the container start command selecting the service role.
- The environment and secret contract in Configuration Reference.
- Expand-only schema migrations applied to completion before a rollout.
- Postgres with migration privileges, and Redis with Streams and
noeviction. /healthand/ready, and the same readiness semantics.
Virtual Machines
Section titled “Virtual Machines”caracalHost renders cloud-init; a providers/<cloud>/host adapter creates the instance, its inbound exposure, its cloud identity, and its DNS records. Every adapter takes the same inputs and returns the same outputs, so changing cloud means changing a module source. Set tlsProxy on the core to terminate HTTPS and derive the console origin and token issuer from its routes.
| Concept | Azure | AWS | Google Cloud |
|---|---|---|---|
| Instance | Linux virtual machine | EC2 instance | Compute Engine instance |
| Public address | Static public IP | Elastic IP | Static external address |
| Inbound exposure | Network security group | Security group | VPC firewall rule |
| Identity | User-assigned managed identity | IAM role and instance profile | Attached service account |
| DNS | Azure DNS A record | Route 53 record | Cloud DNS record set |
Caveat. The bootstrap installs Docker through get.docker.com, which supports Debian, Ubuntu, RHEL, and Fedora. It does not support Amazon Linux 2023 or Container-Optimized OS. The adapters use Ubuntu images; if you change the image, install the container runtime with extraRuncmd.
Managed Container Platforms
Section titled “Managed Container Platforms”topology.yaml describes the deployment once; an adapter maps it onto a provider. Each adapter declares how its platform delivers secrets and how services address each other, and the core does the rest.
| Neutral concept | Azure Container Apps | AWS ECS on Fargate | Google Cloud Run |
|---|---|---|---|
| Role selection | command override | entryPoint and command | command override |
| Secret delivery | Projected file | Environment variable | Environment variable |
| Secret reference | Key Vault URL with a managed identity | Secrets Manager ARN with a task role | Secret Manager version with a service account |
| Registry auth | Managed identity with AcrPull | Task execution role | Runtime service account |
| Internal address | https://<app>.internal.<envDomain> | Service Connect discovery name | Internal-ingress service URL |
| One-shot migration | Container Apps Job | Task definition run with RunTask | Cloud Run Job |
| Autoscaling | http concurrency rule | Service desired count | Concurrency and instance bounds |
| Durable spill storage | NFS Azure Files share | EFS access point | None available |
| Resource shape | Fixed vCPU-to-memory ladder, 4 vCPU ceiling | Fargate task sizes | Up to 8 vCPU and 32 GiB |
Two consequences are worth knowing before choosing a provider:
- Only Container Apps projects credentials as files. ECS cannot mount a secret at all, and Cloud Run refuses two secret volumes at one mount path, so neither can give a service the several credentials it needs as files. On both, credentials are bound to environment variables and resolved before the instance starts. They never appear in a task definition or service manifest, but a principal who can describe the running workload can read them; scope that permission accordingly.
- Cloud Run has no durable per-instance volume. STS and Gateway spill audit evidence to disk when Redis is unreachable; on Cloud Run that evidence survives only while the instance lives.
Kubernetes
Section titled “Kubernetes”The chart is cloud-neutral. Four values carry the entire provider surface:
| Value | AKS | EKS | GKE |
|---|---|---|---|
replayPersistence.storageClassName | managed-csi | gp3 | premium-rwo |
ingress.*.className | webapprouting.kubernetes.azure.com | alb | gce |
serviceAccount.annotations | azure.workload.identity/client-id | eks.amazonaws.com/role-arn | iam.gke.io/gcp-service-account |
global.podLabels | azure.workload.identity/use: "true" | not required | not required |
infra/helm/caracal/examples carries a worked overlay for each. A cloud that needs a chart change is a bug in the chart.
Database Prerequisites
Section titled “Database Prerequisites”The baseline migration creates the pgcrypto extension and six service roles, and grants CREATEDB to the role that owns the console’s auth database. Managed Postgres restricts all three, so confirm them before the first deployment on any provider. A migration job that fails here fails the whole rollout, by design.
| Requirement | Azure Database for PostgreSQL | Amazon RDS and Aurora | Cloud SQL |
|---|---|---|---|
pgcrypto | Must be added to the azure.extensions server parameter first. CREATE EXTENSION fails until it is, and the parameter change needs a server restart | Available to the master user | Available to the default user |
| Create roles | Administrative user is a member of azure_pg_admin | Master user holds rds_superuser | Default user holds cloudsqlsuperuser |
Grant CREATEDB | Permitted for the administrative user | Permitted for the master user | Permitted for the default user |
Run the migration job against the managed instance before provisioning anything else. It is the cheapest possible failure and it exercises connectivity, TLS, credentials, and privileges in one step.
Choosing
Section titled “Choosing”Use Choose a Deployment Profile to pick a model, then the workflow page for it: Docker Compose, a managed container platform, or Helm.

