Google Cloud
OSO self-manages its core data infrastructure on Google Cloud rather than
relying on managed equivalents. All of our GCP resources — the GKE cluster,
its node pools, the Dagster GCS bucket, archive nodes, and more — are defined
as code with Terraform and applied as OpenTofu
(tofu), a drop-in, open-source fork of Terraform that reads and writes the
same state format. Nothing is clicked together in the console.
Applying changes: GitOps, not a CI pipeline
There is no CI job that runs tofu apply. Instead, changes are applied the
same way Flux applies Kubernetes manifests: a controller running inside the
cluster continuously reconciles infrastructure toward what's declared in Git.
tofu-controller runs in the
tofu-system namespace on the production GKE cluster (installed via the
tofu-controller Flux Kustomization, ops/k8s-operators/gke/tofu-controller).
Each piece of infrastructure it manages is represented by a Terraform custom
resource, whose spec.sourceRef points at a Flux GitRepository (or
OCIRepository) and spec.path at a module under ops/tf-modules/. The
controller watches that source, runs tofu plan/apply against the module
in-cluster, and writes the result back to the CR's status — no local
tofu apply, and no separate GCP service account key: on GKE the
tofu-system/tofu-controller KSA authenticates directly via Workload Identity
Federation and is granted GCP IAM roles as itself.
The GitOps wiring for the warehouse cluster's own infrastructure (its node
pools and the Dagster bucket) lives in ops/core-infrastructure/: a common/
directory holding the Terraform CRs, and a gke/ overlay that re-points
each CR's sourceRef at the cluster's own GitRepository. This is the
GitOps replacement for what used to be a single, standalone tofu apply run
by hand against the monolithic warehouse-cluster module.
Modules (ops/tf-modules/)
Each module owns one narrow slice of infrastructure so it can be reconciled (and, if needed, destroyed) independently:
warehouse-cluster-core— the VPC, the GKE control plane, thewarehouse-nodeservice account, and a 0-node placeholder pool (GKE's cluster module requires at least one inline pool, so this one exists purely to satisfy that and runs no real workloads).warehouse-node-pool— a single, fully-parameterized node pool. Every real pool (standard, spot, preemptible, Trino coordinator/worker, consumer-Trino coordinator/worker, MCS scheduler/worker, and the default pool) is one instance of this module, reconciled as its ownTerraformCR.warehouse-dagster-bucket— the GCS bucket Dagster uses for intermediate storage, plus IAM bindings for whichever principals need to read/write it.warehouse-cluster— the original, monolithic module that used to provision the cluster and all of its node pools together. Deprecated in favor of the three modules above; kept functional only for consumers that haven't migrated yet.warehouse— the data warehouse's own GCP resources: BigQuery, CloudSQL, and GCS.archive-nodes— GCE VMs and disks for blockchain archive nodes.vector-search— a Vertex AI Vector Search index and endpoint.k3d-ci-node/k3d-ci-image-build— an ephemeral, Spot-VM-backed k3d cluster for CI, and the Packer pipeline that bakes its base image. See the k3d-ci-node README for how to exercise a module end-to-end against a local k3d cluster before it ever touches production.gce-dev-vm/test-project— developer sandbox VMs and projects.
State
Each module gets its own OpenTofu state, stored as a GCS object in the
oso-private-tf-us bucket (one prefix per resource, e.g.
oso/production/warehouse-nodepool-default). This is a deliberate move away
from one shared state file per environment: a bug or a stuck lock in one
resource's state can no longer block reconciliation of every other resource.
The migration off the original monolithic state moved each resource's state
entry with zero underlying resource churn (nothing in GKE or GCS was destroyed
or recreated). It was a one-time job, and the tooling that drove it has since
been removed. To bring an existing GCP resource under a new module's state
today, declare it in an import {} block and let the CR's plan adopt it — see
ops/clusters/warehouse-bootstrap/DR.md
for the procedure.
Local testing
You can exercise a module end-to-end with tofu-controller on a local k3d cluster instead of the production GKE cluster:
oso ops k3d-setup --with-tofu-controller
This is opt-in (a bare oso ops k3d-setup skips it) since it requires a GCP
service account key Secret. See the
k3d-ci-node README
for the full walkthrough, including how to inspect the resulting Terraform
CR and tear it down again.
What runs on top
The infrastructure above is only the substrate. What actually runs on the
GKE cluster — Trino, Nessie, Dagster, the backend API, the scheduler, and
everything else in ops/k8s-apps/ — is deployed separately, as plain
Kubernetes manifests reconciled by Flux rather than as Terraform. See the
Ops Overview for how that half fits together, and the
Dagster Playbook for day-to-day tasks like restating
SQLMesh models and managing the Nessie consumer tag.