Deploy a Kubernetes Cluster¶
This guide covers two paths: provisioning a new Gardener-managed cluster and registering an existing cluster via kubeconfig. Both end with a verified connection and a running workload.
Time to complete: ~20 minutes (Gardener), ~5 minutes (generic)
Prerequisites: An organization, a project, and a bearer token with garden:create permission.
Path A — Gardener-managed cluster¶
Step 1 — Discover available options¶
The response lists available Kubernetes versions, machine types, and regions. Note the values you want for version, cloud, and machine_type.
Step 2 — Create the cluster¶
POST /k8s/clusters?project_id=<uuid>
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "prod-cluster",
"project_id": "<uuid>",
"cloud": "openstack",
"version": "1.29",
"node_pools": [
{
"name": "workers",
"machine_type": "m1.large",
"min": 2,
"max": 5
}
]
}
Returns 201 Created. Note the cluster id.
Step 3 — Wait for the cluster to be ready¶
Poll until creating: false and status.lastOperation.state is "Succeeded":
Provisioning typically takes 5–10 minutes. While it runs, creating: true and lastOperation tracks progress.
Step 4 — Download the kubeconfig¶
Once the cluster is ACTIVE, download the kubeconfig from the dashboard or through the Gardener API (available via the dashboard's Download kubeconfig button). The api_server field in the cluster show response gives you the Kubernetes API server URL.
Step 5 — Deploy a workload¶
export KUBECONFIG=~/Downloads/kubeconfig-prod-cluster.yaml
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# worker-abc123 Ready <none> 3m v1.29.4
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 2
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello
image: nginx:alpine
ports:
- containerPort: 80
EOF
kubectl rollout status deployment/hello-world
Path B — Register an existing cluster (generic)¶
Use this path to bring an existing cluster (k3s, EKS, GKE, on-prem) under platform management.
Step 1 — Register the cluster¶
POST /k8s/clusters?project_id=<uuid>
Authorization: Bearer <token>
Content-Type: application/json
{
"kind": "generic",
"name": "on-prem-k3s",
"kubeconfig": "<raw-kubeconfig-yaml-or-base64>"
}
The kubeconfig field is write-only — it is never returned in responses. The response includes has_kubeconfig: true to confirm it was stored.
Step 2 — Verify connectivity¶
The connection_status field reports reachable or unreachable based on an API server probe. If unreachable, check that the cluster's API server is publicly accessible or that you have provided a kubeconfig with the correct server URL.
Step 3 — Rotate the kubeconfig¶
When credentials expire or you rotate your cluster's service account:
PATCH /k8s/clusters/<cluster-id>?project_id=<uuid>
Authorization: Bearer <token>
Content-Type: application/json
{ "kubeconfig": "<new-kubeconfig-yaml>" }
Scale node pools (Gardener clusters only)¶
To scale an existing node pool:
PATCH /k8s/clusters/<cluster-id>?project_id=<uuid>
Authorization: Bearer <token>
Content-Type: application/json
{
"node_pools": [
{ "name": "workers", "min": 3, "max": 10 }
]
}
Gardener applies the change asynchronously. Watch lastOperation to track rollout progress.
Delete a cluster¶
For Gardener clusters, this triggers deprovisioning of the underlying cloud resources. The cluster disappears from list results once teardown is complete.
Related pages¶
- Clusters
- Node Pools
- Object Storage (S3 Operator) — provision storage for your workloads