Configure a cluster
A cluster is one main.tf, in a directory of its own, that calls the socle’s
root for its cloud.
Before you start: your cloud’s prerequisites are met. AWS is the only cloud with a root today.
1. One directory per cluster
Section titled “1. One directory per cluster”clusters/ dev/main.tf prod/main.tfEach has its own state key, so a plan on dev never touches prod. Commit the
.terraform.lock.hcl tofu init writes next to it.
2. Write its main.tf
Section titled “2. Write its main.tf”terraform { backend "s3" { bucket = "acme-tofu-state" key = "socle/aws/acme-prod.tfstate" region = "eu-west-3" use_lockfile = true }}
locals { socle_version = "0.1.0" # x-release-please-version}
module "socle" { source = "oci://ghcr.io/do-now-io/socle/opentofu-modules//opentofu/clusters/aws?tag=${local.socle_version}"
socle_version = local.socle_version
aws = { region = "eu-west-3" cluster_name = "acme-prod" owner = "platform" environment = "prod" kubernetes_version = "1.34" availability_zones = ["eu-west-3a", "eu-west-3b", "eu-west-3c"] cluster_endpoint_public_access_cidrs = ["203.0.113.0/24"] gateway_certificate = { domain = "acme.example" } }
kube = { argocd = { domain = "argocd.acme.example" } kyverno = { enabled = true } }}| Block | What it holds |
|---|---|
socle_version | A released version, never latest or main; the only line an upgrade touches, source included. |
aws | The foundations’ variables. Keys without a default, kubernetes_version among them, are required. Every option: prod.tfvars.example, written as tfvars; the same keys go in the module block. |
kube | Only what differs from the catalog’s defaults, in snake_case. Defaults: Inputs; modules: catalog. |
3. Pass chart values
Section titled “3. Pass chart values”Every module with a chart takes values, any value of its chart. Yours win
over the socle’s defaults and over the module’s named attributes:
kube = { argocd = { domain = "argocd.acme.example" values = { configs = { cm = { "accounts.alice" = "apiKey, login" } rbac = { "policy.csv" = "g, alice, role:admin" } } } values_secret = "argocd-values" }}values lands in the OpenTofu state, so secrets are refused there at plan.
Put them in a Secret with a values.yaml key, in the module’s namespace, and
name it in values_secret:
kubectl -n argocd create secret generic argocd-values --from-file=values.yamlkubectl -n argocd label secret argocd-values reconcile.fluxcd.io/watch=EnabledThe Secret is merged last and optional; the label applies a change at once. OpenTofu never reads it.
4. Adjust what precedes Flux, if you need to
Section titled “4. Adjust what precedes Flux, if you need to”On aws the root also takes cilium, coredns and eks_addons, every key
optional (Inputs),
beside aws and kube in the module block:
cilium = { hubble = true } coredns = { values = { replicaCount = 3 } } eks_addons = { efs_csi = true }Leave cilium.enabled at true on a real EKS: the cluster has no other
network.
5. Plan and apply
Section titled “5. Plan and apply”cd clusters/prodtofu inittofu plantofu applyA misspelt name, a wrong type, a module not offered on your cloud or a secret
in values fails the plan
(Troubleshooting). A green apply
is not convergence: check
kubectl -n flux-system get resourceset socle-root
(Enable a module).