This document describes how to manually deploy a Gardenlet into a Kubernetes cluster and how to automatically register this cluster as a Seed.
- When deploying the first Gardenlet into a Gardener installation (this is done automatically by garden-setup)
- To register a Kubernetes cluster as a
Seed
cluster that is in a "fenced" environment, such as a private datacenter or behind a firewall.
Elaborating on the latter, the Gardenlet only requires network connectivity from the Gardenlet to the Garden cluster (not the other way round), so it can be used to register Kubernetes clusters with no public endpoint. When registering a Seed cluster in such a "fenced" environment, the automatic Gardenlet deployment into Shooted Seed clusters cannot be used (see self-deployment).
Additionally, the Gardenlet can automatically register a Kubernetes cluster as a Seed cluster with the Gardener based on a pre-defined Seed specification (see automatically register as a Seed cluster).
The Gardenlet can automatically deploy itself into Shoot clusters and register this cluster as a Seed
(these clusters are called Shooted Seeds
in the Gardener terminology).
This is the preferred way to add additional Seed clusters as Shoots already come with production-grade qualities that are also demanded for seeds.
This works by registering an initial cluster as a Seed cluster (you can use the Garden cluster itself!) - that has a Gardenlet already installed (e.g by following this guide).
This initial cluster can be used as the Seed cluster for other Shooted Seed
clusters.
Hence, the initial cluster hosts the control planes of the other Seed clusters.
The Gardenlet deployed in the initial cluster, can deploy itself into the Shooted Seed
clusters.
The advantage of this approach is, that there is only one initial Gardenlet installation required - every other Shooted Seed
has a Gardenlet deployed automatically.
Overall this allows the Gardener system to dynamically scale - also scenarios such as "Seed autoscaling" are possible.
-
Kubernetes cluster that should be registered as a Seed cluster
- Verify that the cluster has a supported Kubernetes version.
- Determine the nodes, pods and services CIDR of the Cluster. This needs to be configured in the
Seed
configuration. Gardener uses this information to check that the Shoot cluster is not created with overlapping CIDR ranges. - A current prerequisite of Kubernetes clusters that are used as Seed clusters is to have a pre-deployed Ingress controller. This is pre-installed for
Shooted Seed
clusters.
An ingress controller is required to:-
configure the
Seed
cluster resource (tells the Gardenlet which ingress domain it can use to deploy ingress resources for seed components like grafana and prometheus). -
handle ingress resources that are deployed during the Seed bootstrap by the Gardenlet.
⚠️
There should exist a DNS record*.ingress.<SEED-CLUSTER-DOMAIN>
where<SEED-CLUSTER-DOMAIN>
is the value of the.dns.ingressDomain
field of a Seed cluster resource (or the respective Gardenlet configuration).This is how it could be done for the Nginx ingress controller
Deploy nginx into the
kube-system
namespace in the Kubernetes cluster that should be registered as aSeed
.Nginx will on most cloud providers create the service with type
LoadBalancer
with an external ip.NAME TYPE CLUSTER-IP EXTERNAL-IP nginx-ingress-controller LoadBalancer 10.0.15.46 34.200.30.30
Create a wildcard
A
record (e.g *.ingress.sweet-seed.. IN A 34.200.30.30) with your DNS provider and point it to the external ip of the ingress service. This ingress domain is later required to register theSeed
cluster.
-
-
Kubeconfig for the Seed cluster
- Required to deploy the Gardenlet Helm chart to the Seed cluster.
Requires admin privileges.
The helm chart contains a service account
gardenlet
that the Gardenlet deployment uses by default to talk to the Seed API server.- If the Gardenlet is not deployed in the Seed cluster, the Gardenlet can be configured to use a kubeconfig (also need full admin rights) from a mounted directory.
This can be configured by
seedClientConnection.kubeconfig
in the Gardenlet configuration. As this document describes the Helm-based setup on the Seed cluster, this configuration option is not used in the following.
- If the Gardenlet is not deployed in the Seed cluster, the Gardenlet can be configured to use a kubeconfig (also need full admin rights) from a mounted directory.
This can be configured by
- Required to deploy the Gardenlet Helm chart to the Seed cluster.
Requires admin privileges.
The helm chart contains a service account
-
Create a bootstrap token secret in the
kube-system
namespace of the garden cluster The Gardenlet needs to talk to the Gardener Extension API server residing in the Garden cluster.The Gardenlet can either be configured with an already existing Garden cluster kubeconfig
- by specifying
gardenClientConnection.kubeconfig
in the Gardenlet configuration - or supplying the environment variable
GARDEN_KUBECONFIG
pointing to a mounted kubeconfig file)
The preferred way however, is to use the Gardenlets ability to request a signed certificate for the Garden cluster by leveraging Kubernetes Certificate Signing Requests. The Gardenlet performs a TLS bootstrapping process that is very similar to the Kubelet TLS Bootstrapping. Make sure that the API server of the Garden cluster has bootstrap token authentication enabled.
The client credentials required for the Gardenlets TLS bootstrapping process, need to be either
token
orcertificate
(e.g. OIDC is not supported) and have permissions to create a Certificate Signing Request (CSR). It is recommended to use Bootstrap tokens (also see here) due to their desirable security properties (such as a limited token lifetime).Therefore, first create a Bootstrap token secret for the Garden cluster:
apiVersion: v1 kind: Secret metadata: # Name MUST be of form "bootstrap-token-<token id>" name: bootstrap-token-sweetseed namespace: kube-system # Type MUST be 'bootstrap.kubernetes.io/token' type: bootstrap.kubernetes.io/token stringData: # Human readable description. Optional. description: "Token to be used by the Gardenlet for Seed `sweet-seed`." # Token ID and secret. Required. token-id: 07401b # 6 characters token-secret: f395accd246ae52d # 16 characters # Expiration. Optional. # expiration: 2017-03-10T03:22:11Z # Allowed usages. usage-bootstrap-authentication: "true" usage-bootstrap-signing: "true"
- by specifying
In a later step a kubeconfig based on this token will be made accessible to the Gardenlet upon deployment.
-
Create RBAC roles for the Gardenlet to allow bootstrapping in the garden cluster
This step is only required if this is the first Gardenlet in the Gardener installation. Additionally, when using the controlplane chart, the following resources are already contained in the Helm chart, i.e., if you use it you can skip these steps as the needed RBAC roles should already exist.
The Gardenlet uses the configured bootstrap kubeconfig in
gardenClientConnection.bootstrapKubeconfig
to request a signed certificate for the usergardener.cloud:system:seed:<seed-name>
in the groupgardener.cloud:system:seeds
.Create a
ClusterRole
andClusterRoleBinding
that grant full admin permissions to authenticated Gardenlets.
There is already an issue open to improve the scope of these permissions.Create the following resources in the Garden cluster:
--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: gardener.cloud:system:seeds rules: - apiGroups: - '*' resources: - '*' verbs: - '*' --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: gardener.cloud:system:seeds roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: gardener.cloud:system:seeds subjects: - kind: Group name: gardener.cloud:system:seeds apiGroup: rbac.authorization.k8s.io
This only describes the minimal configuration. For more configuration options please take a look at the configuration values.
-
Create a
gardenlet-values.yaml
based on this template. -
Create a bootstrap kubeconfig based on the bootstrap token created in the Garden cluster.
The should be substituted with
token-id.token-secret
(from our example above:07401b.f395accd246ae52d
) from the bootstrap token secret.apiVersion: v1 kind: Config current-context: gardenlet-bootstrap@default clusters: - cluster: certificate-authority-data: <ca-of-garden-cluster> server: https://<endpoint-of-garden-cluster> name: default contexts: - context: cluster: default user: gardenlet-bootstrap name: gardenlet-bootstrap@default users: - name: gardenlet-bootstrap user: token: <bootstrap-token>
-
Provide this bootstrap kubeconfig together with a desired name and namespace to the Gardenlet Helm chart values here:
gardenClientConnection: bootstrapKubeconfig: name: gardenlet-kubeconfig-bootstrap namespace: garden kubeconfig: | <bootstrap-kubeconfig> # will be base64 encoded by helm
The bootstrap kubeconfig will be stored in the specified secret.
-
Define a name and namespace where the Gardenlet shall store the real kubeconfig it creates during the bootstrap process here:
This secret will be created by the Gardenlet in case it does not exist.
gardenClientConnection: kubeconfigSecret: name: gardenlet-kubeconfig namespace: garden
A Seed cluster can either be registered by manually creating the Seed
resource or automatically by the Gardenlet.
This functionality is particularly useful for Shooted Seed
clusters, as the Gardenlet in the Garden cluster deploys a copy of itself into the cluster with automatic registration of the Seed
configured.
However, it can also be used to have a streamlined Seed registration process when manually deploying the Gardenlet.
Please note that this document does not describe all the possible configurations for the Seed
resource. For more information take a look at the example Seed resource and the configurable Seed settings.
Adjust the Gardenlet component configuration
Next, supply the Seed
resource in the Gardenlet configuration (seedConfig
).
Note that with the seedConfig
supplied, the Gardenlet is only responsible to create and reconcile this one configured seed (in the example above: sweet-seed
).
The Gardenlet can also be configured to reconcile (but not create!) multiple Seeds based on a label selector, but this is only recommended for a development setup.
Add the seedConfig
to the helm chart gardenlet-values.yaml
.
The field seedConfig.spec.provider.type
specifies the infrastructure provider type (e.g. aws
) of the Seed cluster.
For all supported infrastructure providers please take a look here.
....
seedConfig:
metadata:
name: sweet-seed
spec:
dns:
ingressDomain: ingress.sweet-seed.<my-domain> # see prerequisites
networks: # see prerequisites
nodes: 10.240.0.0/16
pods: 100.244.0.0/16
services: 100.32.0.0/13
shootDefaults: # optional: non-overlapping default CIDRs for Shoot clusters of that Seed
pods: 100.96.0.0/11
services: 100.64.0.0/13
provider:
region: eu-west-1
type: <provider>
The Seed cluster can be setup with backup and restore for the main etcds of Shoot clusters. For more information please see the documentation.
Gardener uses etcd-backup-restore that integrates with different storage providers to store the Shoots' main etcd backups. Make sure to obtain client credentials that have sufficient permissions with the chosen storage provider.
Create a secret in the garden cluster with client credentials for the storage provider. The format of the secret is cloud provider specific and can be found in the repository of the respective Gardener extension. For example, the secret for AWS S3 can be found in the AWS provider extension here.
apiVersion: v1
kind: Secret
metadata:
name: sweet-seed-backup
namespace: garden
type: Opaque
data:
# client credentials format is provider specific
Configure the Seed
resource in the Gardenlet configuration (seedConfig
) to use backup and restore:
...
seedConfig:
metadata:
name: sweet-seed
spec:
backup:
provider: <provider>
secretRef:
name: sweet-seed-backup
namespace: garden
The Gardenlet does not have to run in the same Kubernetes cluster as the Seed it is registering and reconciling, but it is in most cases advantageous to use in-cluster communication to talk to the Seed API server. Running a Gardenlet outside of the cluster is mostly used for local development.
For your reference, the gardenlet-values.yaml
should look something like this (with automatic Seed registration and backup for Shoot clusters enabled):
global:
# Gardenlet configuration values
gardenlet:
enabled: true
...
<default config>
...
config:
gardenClientConnection:
...
bootstrapKubeconfig:
name: gardenlet-bootstrap-kubeconfig
namespace: garden
kubeconfig: |
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: <dummy>
server: <my-garden-cluster-endpoint>
name: my-kubernetes-cluster
....
kubeconfigSecret:
name: gardenlet-kubeconfig
namespace: garden
...
<default config>
...
seedConfig:
metadata:
name: sweet-seed
spec:
dns:
ingressDomain: ingress.sweet-seed.<my-domain>
networks:
nodes: 10.240.0.0/16
pods: 100.244.0.0/16
services: 100.32.0.0/13
shootDefaults:
pods: 100.96.0.0/11
services: 100.64.0.0/13
provider:
region: eu-west-1
type: <provider>
backup:
provider: <provider>
secretRef:
name: sweet-seed-backup
namespace: garden
Deploy the Gardenlet Helm chart to the Kubernetes cluster.
helm install gardenlet charts/gardener/gardenlet \
--namespace garden \
-f gardenlet-values.yaml \
--wait
This will create most importantly
- A service account
gardenlet
that the Gardenlet can use to talk to the Seed API server. - RBAC roles for the service account (full admin rights at the moment).
- The secret (
garden
/gardenlet-bootstrap-kubeconfig
) containing the bootstrap kubeconfig. - The gardenlet deployment in the
garden
namespace.
-
Check that the Gardenlets certificate bootstrap was successful
The secret
gardenlet-kubeconfig
in the namespacegarden
in the Seed cluster should be created and contain a kubeconfig with a valid certificate.Get the kubeconfig from the created secret.
$ kubectl -n garden get secret gardenlet-kubeconfig -o json | jq -r .data.kubeconfig | base64 -d
Possibly test against the Garden cluster and verify it is working.
Extract the
client-certificate-data
from the usergardenlet
.View the certificate:
$ openssl x509 -in ./gardenlet-cert -noout -text
Make sure that the certificate is valid for one year.
-
Make sure the bootstrap secret has been deleted from the Seed cluster
Check that the secret
gardenlet-bootstrap-kubeconfig
in the namespacegarden
has been deleted. -
Check that the Seed is registered and
READY
in the Garden clusterCheck that the Seed
sweet-seed
exists and all conditions indicate availability. This indicates that the Gardenlet is sending regular heartbeats and the Seed bootstrapping was successful.The conditions on the
Seed
resource should include the following:$ kubectl get seed sweet-seed -o json | jq .status.conditions [ { "lastTransitionTime": "2020-07-17T09:17:29Z", "lastUpdateTime": "2020-07-17T09:17:29Z", "message": "Gardenlet is posting ready status.", "reason": "GardenletReady", "status": "True", "type": "GardenletReady" }, { "lastTransitionTime": "2020-07-17T09:17:49Z", "lastUpdateTime": "2020-07-17T09:53:17Z", "message": "Seed cluster has been bootstrapped successfully.", "reason": "BootstrappingSucceeded", "status": "True", "type": "Bootstrapped" } ]