Tags: Substrate · Automation · Self-host Substrate: bare Terraform + GitLab CI
The GitLab CI sibling to the
GitHub Actions one-file-per-tenant demo.
Same scenario, same pattern — each tenant is one file under tenants/, Terraform iterates with
for_each — for a SaaS operator on GitLab running plan-on-MR and apply-on-merge.
GitLab's MR support is on the roadmap, so today this demo uses the pipeline-dispatch path.
OnboardTenant runs least-loaded placement, creates a Tenant entity in provisioning, then a
webhook trigger POSTs to the GitLab pipeline trigger API with TENANT_* and
TERRANTULA_CALLBACK_* variables embedded. The pipeline:
prepare-tenant writes tenants/acme.tfvars.json and publishes it as a pipeline artifact.terraform:validate, terraform:plan, and terraform:apply run in sequence, each pulling
the artifact via needs: so Terraform sees the new tenant file.after_script commits the tenant file to the
default branch (for persistence) and POSTs the outcome to the callback URL.active (or failed).The customer's review workflow, state file, and AWS credentials are unchanged. The GitLab
pipeline applies; Terrantula never runs terraform apply.
Setup takes under 30 minutes:
Add the CI/CD variables (AWS_* and a GITLAB_COMMIT_TOKEN) in your GitLab project, seed the
cluster fleet, then fire an onboard:
You can validate the pipeline YAML locally without a live runner:
| File | What it is |
|---|---|
blueprint.yaml | The Terrantula schema + OnboardTenant action (self-contained). |
terraform/main.tf | The TF module that iterates over tenants/. |
tenants/.gitkeep | The directory tenant config files land in. |
.gitlab-ci.yml | The reference pipeline — drop into your repo root or include: it. |