A consolidated guide for deploying the Attic cache infrastructure from scratch or from an overlay repository.
Install the following tools before proceeding:
| Tool | Purpose | Notes |
|---|---|---|
| Nix (with flakes enabled) | Reproducible builds, container images, devShell | experimental-features = nix-command flakes in nix.conf |
| kubectl | Kubernetes cluster access | Provided by the devShell |
| OpenTofu | Infrastructure provisioning | Provided by the devShell |
| direnv | Automatic environment loading | Hooks into .envrc at repo root |
git clone https://github.com/Jesssullivan/attic-iac.git ~/git/attic-iac
cd ~/git/attic-iac
direnv allow
If you prefer not to use direnv, enter the shell manually:
nix develop
The devShell provides pinned versions of tofu, kubectl, pnpm, node, and other tooling.
organization.yaml is the single source of truth for all deployment parameters. Edit it to match your cluster and organization details:
organization:
name: your-org
environments:
dev-cluster:
cluster_context: dev-cluster
# ...
See the Customization Guide for a full breakdown of every field.
Each stack uses a GitLab HTTP backend for remote state. Initialize them one at a time:
cd tofu/stacks/attic
tofu init \
-backend-config="address=https://gitlab.com/api/v4/projects/<PROJECT_ID>/terraform/state/attic-{environment}" \
-backend-config="lock_address=https://gitlab.com/api/v4/projects/<PROJECT_ID>/terraform/state/attic-{environment}/lock" \
-backend-config="unlock_address=https://gitlab.com/api/v4/projects/<PROJECT_ID>/terraform/state/attic-{environment}/lock" \
-backend-config="username=<GITLAB_USERNAME>"
# TF_HTTP_PASSWORD env var provides the GitLab PAT for authentication
Repeat for each stack (attic, gitlab-runners, runner-dashboard), substituting the appropriate state name ({stack}-{env}).
Deploy the components in the following sequence. Each step depends on the one before it.
graph LR
A["1. Cache Platform"] --> B["2. GitLab Runners"]
B --> C["3. Runner Dashboard"]
The cache platform must be deployed first because runners reference it via the
ATTIC_SERVER environment variable. This step provisions CNPG and MinIO
operators, a PostgreSQL cluster, MinIO S3 storage, the Attic API server, GC
worker, and DNS records.
cd tofu/stacks/attic
tofu plan -var-file=../../../tfvars/attic-{environment}.tfvars
tofu apply -var-file=../../../tfvars/attic-{environment}.tfvars
Verify:
kubectl -n attic-cache-dev get pods
# Expect: atticd Running, attic-gc Running, CNPG cluster Ready, MinIO tenant Ready
cd tofu/stacks/gitlab-runners
tofu plan -var-file=../../../tfvars/runners-{environment}.tfvars
tofu apply -var-file=../../../tfvars/runners-{environment}.tfvars
Verify:
kubectl -n {org}-runners get pods
# Expect: one pod per runner type (docker, dind, rocky8, rocky9, nix)
cd tofu/stacks/runner-dashboard
tofu plan -var-file=../../../tfvars/dashboard-{environment}.tfvars
tofu apply -var-file=../../../tfvars/dashboard-{environment}.tfvars
Verify:
kubectl -n runner-dashboard get pods
# Expect: dashboard pod Running
If you are deploying from an overlay repository (for example, an organization-specific configuration layered on top of the upstream project):
git clone https://github.com/Jesssullivan/attic-iac.git ~/git/attic-iac
git clone <overlay-repo-url> ~/git/your-org-overlay
MODULE.bazel already declares a local_path_override pointing to the upstream sibling directory:local_path_override(
module_name = "attic-iac",
path = "../../attic-iac",
)
Adjust the path value if your directory layout differs.
.tf files provide the module definitions.cd ~/git/your-org-overlay
tofu -chdir=../attic-iac/tofu/stacks/attic plan \
-var-file=~/git/your-org-overlay/tfvars/attic-{environment}.tfvars \
-var cluster_context=dev-cluster \
-var k8s_config_path=$HOME/git/your-org-overlay/kubeconfig-{environment}