Skip to content

The three-cloud demo

llms.txtlists every page for an agent

One small website runs in three clouds: ECS on Fargate behind a load balancer in AWS, a Container App in Azure, and a Cloud Run service in GCP. Route 53 sits in front with one latency record per cloud, and each record is guarded by a health check on that cloud’s endpoint. All of it runs on the floci emulators in Docker, so no cloud account is involved.

The demo answers one question: turn Azure off, and where does traffic go?

Terminal window
npx @intentius/behold demo three-cloud

That copies example-three-cloud to ./behold-demos/three-cloud, boots floci, floci-az and floci-gcp, and serves the workspace with the local environment picked. It needs Docker and pulls three emulator images the first time.

The estate is a chant workspace of four members, drawn as four boxes:

member what it declares
dns the hosted zone, three health checks, three latency CNAMEs, and an A record naming the GCP load balancer
aws a VPC (VpcDefault: public and private subnets in two zones, internet and NAT gateways) and the FargateAlb composite: the service, its task, the load balancer
azure a Log Analytics workspace, a VNet with a subnet for the Container Apps environment, the environment, a user-assigned identity, and the app with external ingress
gcp a custom VPC and a subnet for Cloud Run’s egress, and the Cloud Run service (public, running as its own service account) behind a global external Application Load Balancer: address, forwarding rule, HTTP proxy, URL map, backend service, serverless NEG

Each cloud publishes its endpoint with output() (awsEndpoint, azureEndpoint, gcpEndpoint), and dns declares a parameter of the same name. That shared name is the edge behold draws from each record’s endpoint to the cloud that answers it. Config Connector YAML has no outputs, so chant build warns that the gcp member’s output is not written; the edge is still drawn, and the Op below reads the load balancer’s IP from the emulator and hands it to dns.

The front-door Op, in dns/ops/front-door.op.ts, rebuilds the whole picture:

  1. Apply gcp, azure, aws and dns to the emulators, then wait until the Azure health check reads healthy.
  2. Deactivate the Azure app’s active revision, so its endpoint answers 503.
  3. Wait until chant lifecycle health reads the Azure check unhealthy.
  4. Export the page.

Run it from the Deploy tab, or from the copy:

Terminal window
cd behold-demos/three-cloud/dns && npx chant run front-door
# or, the same steps without chant's runner, from the workspace root
npm run front-door

Afterwards the Azure check is unhealthy, the Azure record is dimmed and reads out of rotation: azureCheck unhealthy, and the AWS and GCP records stay in rotation. Route 53 answers with what is left. The marks are the ones Health and rotation describes.

The emulators’ checkers run inside floci’s container, where a floci-az or floci-gcp hostname resolves to nothing. The Op therefore gives each deployed health check the emulator container’s address and port, and the checkers send the endpoint as the Host header, as Route 53 does for a check with an IPAddress. The source declares the checks as they would be on AWS, without either field.

floci runs each load balancer listener on the listener’s own port in its container, so the AWS check is given port 80 rather than floci’s API port.

The Op’s last step is a static export into export/:

Terminal window
behold export . --open-env local --open-zoom logical \
--note "Azure was switched off: its app answers 503, Route 53's check on it fails, and AWS and GCP take the traffic. Run this yourself: \`npx @intentius/behold demo three-cloud\`" --out export

It opens on the local environment at the logical zoom, which draws each record, the service it fronts and whether it is in rotation, and ends with the line that brings a reader back here. To rebuild the page from nothing, boot the emulators and run the Op:

Terminal window
npm run emulators && npm run front-door

Stopping behold demo stops the three emulators. floci-gcp leaves the Cloud Run container it started behind; docker ps -a --filter name=floci-gcp-cloudrun lists it.

behold