# Provisioning clusters

> Provision EKS, GKE, or AKS end-to-end with hardened defaults. 4–7 minutes from create to a registered deployment space.

Source: https://zop.dev/docs/zopday/provisioning/clusters

---

ZopDay provisions managed Kubernetes clusters across all three major clouds with identical hardening defaults and the same wizard. Cluster creation takes 4–7 minutes, registers the cluster as a [deployment space](https://zop.dev/docs/zopday/concepts/deployment-spaces) on success, and lands the default platform Helm components on top so the cluster is ready for deploys immediately.

![ZopDay Infrastructure graph showing eight clusters and three datastores across GCP and AWS accounts, each with instance type, live status, and monthly cost](https://storage.googleapis.com/zopdev-blog-resources/1/files/originals/20260707/6582b97f-59b3-4ec0-bcd3-dab72b4f8b00-clusters.png)

*The Infrastructure view; provisioned clusters and datastores across clouds, each registered as a deployment space with live cost.*

## What gets created

| Provider | Cluster API | Defaults applied |
|---|---|---|
| **AWS** | EKS | RBAC, Network Policies (Calico), Pod Security Standards (restricted), Cluster Autoscaler, AWS Load Balancer Controller, EBS CSI driver, IRSA OIDC provider |
| **GCP** | GKE | Workload Identity, Network Policy (Calico), Pod Security Standards (restricted), Cluster Autoscaler, GCP Load Balancer (HTTP), Persistent Disk CSI |
| **Azure** | AKS | AAD integration, Network Policy (Azure CNI), Pod Security Standards (restricted), Cluster Autoscaler, Azure Load Balancer, Azure Disk CSI |

The defaults are not optional; they are applied during the bootstrap step of every cluster create. If you need a cluster *without* these (e.g. a research sandbox), you have to provision it outside ZopDay and register it via the BYOC path. See [Cluster registration](https://zop.dev/docs/zopday/cloud-setup/cluster-registration).

## Prerequisites

- A cloud account connected with the provisioning IAM scope; see [Cloud permissions](https://zop.dev/docs/zopday/cloud-setup/permissions)
- Networking decision: provision a fresh VPC for this cluster, or use an existing one
- Region and node sizing; the wizard offers presets, you can override

## The wizard

Provisioning → **New provisioning job** → **Cluster**. The wizard has four steps.

**Cloud account + region**

  Pick the connected cloud account and the region. The wizard validates the account can reach the cluster API in that region (sometimes orgs restrict regions at the account level).

**Networking**

  Two paths:
  - **New VPC**: ZopDay provisions a VPC, two private subnets, two public subnets, NAT gateway, internet gateway, route tables, and the necessary security groups. Standard production shape.
  - **Existing VPC**: pick a VPC ZopDay can already see on the cloud account. The wizard auto-detects which subnets are public vs private and proposes a layout. You can override.

  Cluster control plane endpoints are private by default. If you want a public endpoint, toggle it explicitly. ZopDay does not enable public API by default.

**Node pool**

  Pick a preset (Small / Medium / Large) or define a custom pool: instance type, min/max replicas, autoscaling target, on-demand vs spot mix.

  Spot mix is **off by default for prod-shaped clusters** (ZopDay infers prod-shape from the cluster name and tags). For dev/staging, spot is offered as a one-click toggle that adds a separate spot node pool alongside an on-demand baseline.

**Review + create**

  The review screen shows every resource ZopDay will create, the estimated monthly cost, and the IAM role that will be created. Click **Create**. The job is queued; the detail page streams progress.

## Pipeline steps

```
stepValidate → stepCreateNetwork → stepCreateIAM → stepCreateCluster
            → stepBootstrapComponents → stepRegisterSpace → stepFinalize
```

| Step | What it does |
|---|---|
| `stepValidate` | Verifies cloud account permissions, region availability, name uniqueness |
| `stepCreateNetwork` | Provisions VPC + subnets + NAT + IGW + route tables (skipped if existing VPC) |
| `stepCreateIAM` | Creates cluster IAM role, node IAM role, OIDC provider |
| `stepCreateCluster` | Submits the EKS / GKE / AKS create call and waits for `Active` |
| `stepBootstrapComponents` | Installs default Helm components in parallel |
| `stepRegisterSpace` | Calls `POST /spaces` to register the cluster as a deployment space |
| `stepFinalize` | Writes the audit row, sets job to `completed` |

Most of the wall-clock time is in `stepCreateCluster`; the EKS / GKE / AKS create call blocks on the cloud provider provisioning the control plane and the worker pool. The rest of the steps complete in well under a minute combined.

If a step fails, the job is marked failed in the Provisioning Jobs view with the failing step and the underlying error surfaced. Fix the cause (quota, permissions, or an existing-resource conflict) and retry; the job resumes from the last successful step.

## What lands on the cluster

The bootstrap step installs the default platform Helm components from the catalog (`configs/components.yaml`). The default set covers, broadly:

| Component | Purpose |
|---|---|
| Cluster Autoscaler | Scales node groups based on pending pod pressure |
| Cloud-native ingress controller | AWS LB Controller, GKE Ingress, or Azure App Gateway Ingress |
| Cert-manager | Auto-rotated TLS certificates via Let's Encrypt or your cloud CA |
| External-DNS | Auto-creates Route 53 / Cloud DNS / Azure DNS records from Ingress resources |
| Metrics-server | Required for HPA / autoscaler decisions |
| Pod Security Standards admission controller | Enforces the restricted profile by default |
| Calico (AWS, GCP) / Azure CNI (Azure) | Network Policy enforcement |

You can install additional components later from Provisioning → Catalog. See [Components](https://zop.dev/docs/zopday/provisioning/components).

## RBAC defaults

ZopDay creates the cluster with these RBAC bindings out of the box:

- **`zopday-deployer`** ClusterRoleBinding; the kubeauth principal used by ZopDay deploys. By default scoped to `cluster-admin`; you can narrow this down post-provisioning by pointing the binding at a custom ClusterRole through your GitOps workflow or `kubectl`.
- **`cluster-autoscaler`**: necessary RBAC for the autoscaler component
- **AAD groups → Kubernetes groups** (Azure); if you provisioned with AAD integration enabled, the wizard's `adminAADGroups` list is mapped to cluster-admin

There is no shared service account or "ZopDay group"; every binding has a specific subject and a specific role.

## Existing VPC mode; what ZopDay expects

If you picked Existing VPC, ZopDay needs:

| Requirement | Why |
|---|---|
| At least 2 subnets across different AZs/zones | EKS/GKE/AKS all require multi-AZ control plane |
| At least one subnet tagged as private | Worker nodes go in private subnets |
| NAT egress configured | Worker nodes pull images via NAT |
| `kubernetes.io/cluster/{name}` tags absent (AWS) | EKS Cluster Autoscaler tag pollution check |

If any requirement is missing, the validate step fails fast with a specific error. ZopDay does **not** silently fix up VPC config in existing-VPC mode; that's customer-owned infrastructure.

## Cost estimate

The review step's cost estimate is from the pricing cache and covers:

- Control plane fees (EKS: $0.10/hr, GKE: $0.10/hr after the first cluster free, AKS: control plane free on the Free tier, paid on the Standard / Uptime-SLA tier)
- Node pool cost (instance × count × hours)
- NAT gateway data processing (estimated from average traffic; actual will vary)
- Load balancer hourly + per-LCU charges (AWS)

It's an estimate (`isEstimated: true` badge); actuals diverge based on traffic. The estimate is recomputed if you change node sizing in the wizard.

## Teardown

`DELETE /provisioning-jobs/{id}` triggers cluster teardown:

1. Helm uninstalls every component
2. Drains nodes
3. Submits the EKS/GKE/AKS delete call
4. Tears down the IAM role
5. Tears down the VPC (if ZopDay created it; existing VPCs are not touched)

Teardown takes 5–10 minutes. The detail page streams progress. If teardown is partially completed when the job is cancelled, retry resumes from the last successful step (idempotent; if EKS is already deleted, the delete call returns 404, which counts as success).

## What ZopDay does NOT provision

For clarity on the boundary:

| Out of scope | Why |
|---|---|
| Application Helm releases | That's deploy work, not provisioning. See [Pipelines](https://zop.dev/docs/zopday/pipelines). |
| Cluster-side observability stack (Prometheus / Loki / Grafana) | Available as opt-in Helm components in the catalog, but not installed by default; they're substantial infrastructure that some customers run centrally outside the cluster. |
| Custom CNI / Service Mesh (Istio, Linkerd, Cilium) | Opt-in via the component catalog. |
| Bastion / SSH access | Not configured. Use `aws ssm start-session` / `gcloud compute ssh` / Azure Bastion for cluster node access. |
