Skip to content

multi-cloud-deploy

The same WASM tasklet runs on AWS, GCP, and Azure cells unchanged. The fabric is the abstraction; provider choice is a deploy-time flag, not a code change. This recipe walks through deploying one tasklet to all three clouds and reading back the cell context each one ran on, so you can compare cost / latency / region for the same workload.

Source

cookbook/multi-cloud-deploy/ in the source tree. 6 unit tests, all green.

The tasklet takes a JSON input describing where it expects to run, plus an optional echo blob, and returns the same context plus the echo length so the caller can verify the response came from the cell they targeted.

pub fn compute(input_bytes: &[u8]) -> Result<IdentifyOutput, &'static str> {
let input: IdentifyInput = serde_json::from_slice(input_bytes).map_err(|_| "invalid_input")?;
if input.provider.is_empty() { return Err("missing_provider"); }
Ok(IdentifyOutput {
ran_on: WhereItRan { provider: input.provider, cell_id: input.cell_id, region: input.region },
echo_len: input.echo.len(),
module_version: MODULE_VERSION,
})
}

Deploy to all three clouds

The tasklet WASM is byte-identical across providers. Only the --provider flag changes:

Terminal window
grafos tasklet build
grafos validate
grafos deploy run --provider aws --tasklet identify --mem 32768 --json
grafos deploy run --provider gcp --tasklet identify --mem 32768 --json
grafos deploy run --provider azure --tasklet identify --mem 32768 --json

Each command returns a run_id and a cell_id for the cell that admitted the deploy. Pull the artifacts to verify which cell actually ran the work:

Terminal window
grafos artifacts <run_id_aws>
grafos artifacts <run_id_gcp>
grafos artifacts <run_id_azure>

response.json includes the cell-context echo so you can prove the AWS deploy ran on an AWS cell, the GCP one on a GCP cell, and so on.

Two cell patterns: standalone vs registered

Worth knowing before you ship to production:

  • AWS uses the standalone-cell pattern. Each AWS cell is a self-contained mini-fabric — its own fabricbiosd + grafos-scheduler, its own scheduler URL. You bring up an AWS cell with grafos cloud provision aws; deploys go directly to that cell’s scheduler URL via mTLS. The cell does NOT register with a public scheduler.
  • GCP uses the registered-cell pattern. A GCP cell runs grafos cloud cell-agent which registers outbound with scheduler.grafos.tenura.systems. The hosted scheduler is the orchestrator; deploys go through it and the orchestrator routes to whichever GCP cell is healthy.
  • Azure is currently registered-pattern as well (same shape as GCP).

For most multi-cloud workloads this means: when you write --provider gcp or --provider azure, the deploy goes through the Tenura-hosted scheduler. When you write --provider aws, the CLI looks at your local .grafos/cloud/aws-cells.json to find a standalone AWS cell to deploy to. The wire path differs; the developer experience is identical.

What’s interesting

  1. Same WASM, byte-identical. The module_sha256 printed by grafos tasklet build is the same regardless of where you’ll deploy it. The provider abstraction is at the scheduler layer, not the bytecode.
  2. Capability tokens are scope-bound to the issuing cell. A token from your AWS cell can’t talk to GCP and vice versa. If your program needs to span clouds, each cloud’s tasklet holds its own lease + token.
  3. Lease costs differ per cloud. grafos runs show <run_id> --json returns a cost field. AWS t4g.medium, GCP e2-medium, and Azure B-series have different per-hour rates; the same workload comes back with different cents_per_run numbers. With Phase 211 in place you can see all three on https://api.tenura.systems/admin/stats#infrastructure.
  4. Tenant budget is global. A single tenant’s budget cap is the sum of spend across providers. Run grafos runs ls --json | jq '[.runs[].cost.cents_per_run] | add' to see total across providers; grafos admin set-tenant-budget --tenant <name> --cents <N> to top up.

Production drop-in

In a real workload you’d:

  1. Decide per-environment which provider to use. Dev → local-dev. Staging → AWS. Prod → GCP. Make that choice via env var or grafos.toml’s [runnable_targets] block; the program code stays the same.
  2. Set up at least one cell on each provider you intend to deploy to. AWS via grafos cloud provision aws; GCP via grafos cloud provision gcp (registered, joins the hosted fleet); Azure via grafos cloud provision azure.
  3. Use the tenant budget gate. Tenura-hosted accounts come with a 2000-cent ($20.00) starting budget that’s enforced cluster-wide. Top it up before a multi-cloud burst.
  4. Tear down standalone cells when done to stop accruing spend: grafos cloud teardown aws --cell-id <id>.

Where to next