Clusters
A cluster is a managed Kubernetes cluster owned by your organization. It hosts one or more projects and the plugins installed on it. Clusters are managed by Gardener on top of bare-metal infrastructure provisioned with metal-stack; see Infrastructure for the layers underneath.
Creating a cluster
Section titled “Creating a cluster”Clusters → Add cluster starts a three-step wizard.
How many clusters your organization may have is a quota set by the platform operator; a new organization may have one.
Step 1: Cluster
Section titled “Step 1: Cluster”| Field | Notes |
|---|---|
| Name | Lowercase letters, digits, - and .; must start and end with a letter or digit. Maximum 253 characters. Must be unique within the organization. |
| Region | Picked from the region catalog offered by the installation. The region determines which Kubernetes versions and machine types you can choose. |
| Kubernetes version | The versions offered by the chosen region. |
Step 2: Nodes
Section titled “Step 2: Nodes”Define one or more node pools. A node pool is a group of identical machines; the machine types on offer come from the region you picked in step 1. Use separate pools when you need different machine sizes or want to isolate workloads onto their own hardware.
Step 3: Summary
Section titled “Step 3: Summary”Review everything and confirm. Provisioning is asynchronous: the cluster appears in the cluster list and moves through its states while the platform builds it.
Regions and availability zones
Section titled “Regions and availability zones”Regions group the physical locations an installation offers. Within a region, availability zones give failure isolation for workloads that need it. The platform’s position on availability zones is recorded in ADR 0009.
Node pools
Section titled “Node pools”Node pools can be viewed and changed from the cluster’s Nodes tab after creation. A pool has a name, a machine type and an autoscaler range:
| Field | Notes |
|---|---|
| Name | Unique within the cluster. Fixed after creation. |
| Machine type | Must be offered by the cluster’s region. Fixed after creation. |
| Minimum nodes | Lower bound of the autoscaler. May be 0. |
| Maximum nodes | Upper bound of the autoscaler. Must be greater than or equal to the minimum. |
Resizing
Section titled “Resizing”Editing a pool means changing its minimum and maximum. Save changes applies the whole form at once: pools you added are created, pools you removed are deleted, and pools whose bounds you changed are updated. Because name and machine type are fixed, moving a workload to different hardware means adding a pool with the new machine type and removing the old one. The platform does not convert a pool in place.
Autoscaling
Section titled “Autoscaling”The minimum and maximum are the bounds of the Kubernetes cluster autoscaler: nodes are added when pods cannot be scheduled and removed when they are no longer needed, within that range. The Nodes tab shows each pool’s current node count alongside its bounds. There is no manual “set the node count to N” operation; set the minimum instead.
A cluster runs only the node pools you give it. A new cluster starts once its first node pool is added; until then it waits, and its status and events say so (“Creating cluster: waiting for a node pool”). A cluster’s last node pool cannot be removed on its own: replace it in one step instead, which the console’s node pools sheet and the OpenTofu provider do by saving the new set of pools (the old pool goes and the new one comes in the same change, so it fits within your quota). At least one pool must have a maximum above 0, so a cluster always has somewhere to run its nodes.
Applying changes
Section titled “Applying changes”Node pool changes are asynchronous, like cluster creation: the console saves them and the platform reconciles the cluster’s worker pools with Gardener in the background. Nodes are replaced rather than modified: adding, removing or shrinking a pool takes the nodes involved out of service, so drain-sensitive workloads should have a PodDisruptionBudget.
Quotas
Section titled “Quotas”The platform operator sets, per organization, how many clusters it may have and how many nodes of each machine type it may have in a region. Both are enforced when something new is made, never against what already runs:
- Clusters. Adding a cluster beyond the quota fails with a message saying so. A new organization may have one cluster. A deleted cluster counts until the platform has torn it down, so the room it took comes back a little after the delete.
- Nodes. Per region and machine type, the maximum size of every node pool with that machine type counts, across all the organization’s clusters, whether or not the autoscaler ever reaches it. A new organization has no node quota at all, so its first node pool needs the operator first: without a quota the refusal says so. With one, creating a pool, or raising a pool’s maximum, that would take the sum over the quota is refused with a message naming the sum and the quota. Pools on a deleted cluster count until the cluster is torn down.
A quota lowered below what you already run changes nothing about it: your clusters and pools keep running, and a pool may still be shrunk. It only stops the next cluster, or the next new or larger pool, until there is room again.
Organization → Quotas shows every quota next to what counts against it: the clusters you have, and per region and machine type the sum of your pools’ maximum sizes. It is read-only. To request an increase in quotas, contact a Fundament operator; the funops page says what they run.
Defaults
Section titled “Defaults”The Defaults block sets the resource requests and limits containers on this
cluster get for each request or limit they leave unset. Every namespace
Fundament manages on the cluster inherits them (one created straight on the
cluster with kubectl gets nothing), and a project may narrow them but never
widen them. See
Defaults.
Namespaces
Section titled “Namespaces”Each cluster’s Namespaces tab lists the namespaces on that cluster and which project owns them. See Namespaces.
Plugins
Section titled “Plugins”Each cluster’s Plugins tab shows what is installed and lets cluster admins install more from the catalog. Plugins are per cluster: two clusters in the same organization can run a different set, at different versions.
Networking
Section titled “Networking”Each cluster has its own private network and its own firewall. Services get
their addresses automatically: one that only works inside the cluster by
default, and a public one for a Service of type LoadBalancer or a Gateway.
See Service IP addresses for where those addresses
come from and how long you keep them.
Cluster access
Section titled “Cluster access”Access to a cluster’s Kubernetes API goes through a kubeconfig you download per cluster. There is no separate kubeconfig per namespace: one kubeconfig covers the whole cluster, and what you may actually do in it is decided per request (see What the kubeconfig grants below).
Getting a kubeconfig
Section titled “Getting a kubeconfig”From the console: open the cluster and use Download kubeconfig in the header of the cluster page. From the command line:
functl cluster kubeconfig <CLUSTER_ID> > ~/.kube/fundament.yamlBoth require view access on the cluster, which every member of the owning organization has: organization admins and members alike. The kubeconfig is available as soon as the cluster is created. While the cluster is still being provisioned, kubectl answers with an explanation instead of a result, for example:
Error from server (ServiceUnavailable): getting your credentials for this cluster failed: Gardener has no shoot for this cluster yetAccess works shortly after the cluster’s API server is up, which is before the cluster is ready: the worker nodes may still be joining. In the seconds between, while your access is being set up, kubectl says so and asks you to try again.
Using it
Section titled “Using it”The kubeconfig contains no long-lived credential. It points at the platform’s Kubernetes API proxy and delegates authentication to an exec credential plugin:
users:- name: <organization>-<cluster> user: exec: apiVersion: client.authentication.k8s.io/v1 command: functl args: [cluster, token, <cluster-id>]The cluster, context and user entries are named after the organization and
the cluster (for example acme-corp--production), which is the name kubectl,
k9s, Lens and Headlamp show. Cluster names are reduced to lowercase letters,
digits and dashes; a name that had to be changed gets a short suffix to stay
unique. Rename the context locally if you prefer another name
(kubectl config rename-context).
So functl must be installed, on your PATH and logged in
(functl auth login) for the kubeconfig to work, including on machines that
only ever run kubectl. kubectl calls functl cluster token whenever it
needs a fresh token; you never handle the token yourself.
What the kubeconfig grants
Section titled “What the kubeconfig grants”Every request goes to the API proxy rather than straight to the cluster. The
proxy checks that you may view the cluster, then swaps your platform token for
your personal ServiceAccount on that cluster (fundament-<user-id> in the
fundament-system namespace) and forwards the request. What that
ServiceAccount may do depends on your role:
| Your role | Cluster-side result |
|---|---|
| Organization admin | The ServiceAccount is bound to the cluster-admin role: full access to the cluster. |
| Project admin | In every namespace of the project, the ServiceAccount is bound to the built-in admin role: manage workloads, services, config and access within those namespaces. |
| Project viewer | In every namespace of the project, the ServiceAccount is bound to the built-in view role: read-only access, without Secrets. |
| Neither | No ServiceAccount is created, and requests are refused. |
The bindings are named fundament:project:<user-id> and follow project
membership: adding, promoting or removing a member, or creating a namespace,
updates them in the background.
Listing namespaces (kubectl get namespaces) is answered by the proxy itself,
because Kubernetes can only grant that cluster-wide. Organization admins see
every namespace; everyone else sees the namespaces of the projects they are a
member of, and nothing else. kubectl auth can-i list namespaces answers yes
accordingly.
Consequences worth knowing:
- The proxy forwards only the
/api,/apis,/openapiand/versionpaths and the/healthz,/livezand/readyzprobes. Other endpoints return 404 regardless of your permissions. - ServiceAccounts and bindings are synced in the background after a membership change, so immediately after being granted access a request can return 503 with “your access to this cluster is still being set up”, or 403. Retry shortly. After losing your last role on the cluster, requests can still succeed for a few seconds, and return that 503 for up to half a minute, before they are refused.
- Listing namespaced resources across all namespaces
(
kubectl get pods --all-namespaces) is refused for project members. Work per namespace instead.
GUI tools
Section titled “GUI tools”Tools that talk to the Kubernetes API, such as k9s, Headlamp and Freelens, work with the same kubeconfig: their namespace view lists the namespaces you can see, and from there you can open pods, follow logs and describe resources within your role. Things to keep in mind:
- The kubeconfig runs
functl cluster token, sofunctlmust be on thePATHof the tool, not just of your shell. Desktop apps started from a launcher may not inherit your shell’sPATH. - The kubeconfig sets no default namespace. Pick one of your namespaces in the
tool (in k9s:
:namespace, then select), or pass it on the command line (k9s -n <namespace>). - “All namespaces” views depend on the tool. Headlamp falls back to loading your namespaces one by one. k9s shows an access error; pick a namespace instead. Freelens (and Lens) show an empty list with a warning until you enter your namespaces as the cluster’s accessible namespaces in its cluster settings; after that its “All namespaces” view loads them one by one.
Lifecycle
Section titled “Lifecycle”Cluster lifecycle management (creation, upgrades, and deletion) follows the model described in ADR 0006. In line with the platform’s soft-delete policy, deleting a cluster in the console removes it from your view rather than erasing its record.
Lost clusters
Section titled “Lost clusters”A cluster can disappear from the underlying infrastructure without anyone deleting it in the platform, for instance after an operator error or the loss of the machines that ran its control plane. Its workloads and data are gone with it. If the platform had already seen the cluster in the infrastructure, it then shows the cluster as Lost, records a “Cluster lost” event, and offers no kubeconfig. A cluster that disappears before the platform first saw it stays Provisioning, without an event to show for it.
A lost cluster is not rebuilt by itself. Any change to the cluster, such as resizing a node pool, creates it again under the same name. The new cluster is empty: restore its workloads and data from your own sources. If you no longer need the cluster, delete it instead.