Skip to content

Migration of Shoot controlplane to another Seed

Overall info

Currently moving the control plane of a Shoot cluster can only be done manually and requires deep knowledge of how exactly to transfer the resources and state from one Seed to another.

Note

  • Source Seed is the Seed which currently hosts the control plane of a Shoot Cluster
  • Destination Seed is the Seed to which the control plane is being migrated

Migration at the end is making backup on source Seed and restore it on target Seed. In other words it is redeploying the same Shoot object with restored ETCD database.

Beside ETCD database needs to be also some secrets migrated:

- ca
- ca-front-proxy
- static-token
- ca-kubelet
- ca-metrics-server
- etcd-encryption-secret
- kube-aggregator
- kube-apiserver-basic-auth
- kube-apiserver
- service-account-key
- ssh-keypair

Other secrets can be regenerated from them.

Gardenlet deploys custom resources in the Source Seed cluster during Shoot reconciliation which are reconciled by extension controllers. The state of these controllers and any additional resources they create is independent of the gardenlet and must also be migrated to the Destination Seed. Following is a list of custom resources, and the state which is generated by them that has to be migrated.

  • BackupBucket: nothing relevant for migration
  • BackupEntry: nothing relevant for migration
  • ControlPlane: nothing relevant for migration
  • DNSProvider/DNSEntry: nothing relevant for migration
  • Extensions: migration of state needs to be handled individually
  • Infrastructure: terraform state
  • Network: nothing relevant for migration
  • OperatingSystemConfig: nothing relevant for migration
  • Worker: Machine-Controller-Manager related objects: machineclasses, machinedeployments, machinesets, machines

This list depends on the currently installed extensions and can change in the future

Migration workflow

  • Starting migration
    • Migration can only be started after a Shoot cluster has been successfully created so that the status.seed field in the Shoot resource has been set
    • The Shoot resource's field `spec.seedName="new-seed" is edited to hold the name of the Destination Seed and reconciliation is automatically triggered
    • The Garden Controller Manager checks if the equality between spec.seedName and status.seed, detects that they are different and triggers migration.
  • The Garden Controller Manager waits for the Destination Seed to be ready
  • Shoot's API server is stopped
  • Backup the Shoot's ETCD.
  • Extension resources in the Source Seed are annotated with gardener.cloud/operation=migrate
  • Scale Down the Shoot's control plane in the Source Seed.
  • The gardenlet in the Destination Seed fetches the state of extension resources from the ShootState resource in the Garden cluster.
  • Normal reconciliation flow is resumed in the Destination Seed. Extension resources are annotated with gardener.cloud/operation=restore to instruct the extension controllers to reconstruct their state.
  • The Shoot's namespace in Source Seed is deleted.

Migration of shoot by editing shoot manifest manualy

Shoot name: sts-01
Gardener project name: dev
Name of seed namespace for Shoot: Shoot--dev--sts-01
Name of source seed cluster: fsd2-0
Name of destination seed cluster: fsd2-1
Name of Garden cluster: fgd2

Migration could be initiated through the editing Shoot object from gardener cluster

kubectl edit Shoot/mcm1 -n garden-dev --kubeconfig <kubeconfig of fgd2 garden cluster>

apiVersion: core.gardener.cloud/v1beta1
kind: Shoot
metadata:
  name: sts-01
  ...
spec:
 seedName: fsd2-0 --> fsd2-1
  ...

Migration of shoot via Gardener dashboard

Second option how to modify Shoot object is through the Gardener dashboard (needed admin permission for Gardener cluster)

Migration Specification and Progress

Let's assume that some prerequisites are done and start with migration process:

Prerequisites:

  • target seed already exists
  • secret specified in yaml of the shoot field secretBindingName exists on target seed
  • seed persists on the same Gardener cluster

shoot hosted on old seed fsd2-1

Select proper destination seed and confirm action by writing shoot name in confirmation dialog.

new seed dialog

After pressing SAVE button, redeployment / migration of shoot start.

migration shoot progress 1

migrations shoot process 22

migration shoot process 29

migration shoot process 46

migration shoot process 81

migration shoot process 82

migration shoot process 98

migration shoot process 98

After migration of shoot, we can see and check shoot specification for shoot. Shoot was successfully migrated.

migration shoot done

Validation and further checks after migration of shoot

During the deployment of the shoot, various objects have been created by deployer also on api cluster, therefore after migration of the shoot, from source to target seed, we need to validate some objects which can be related to the old shoot and were not recreated, or stayed with wrong naming logic (objects are namespaced in kubernetes).

Findings:

NOTE: fsd2-1 - source seed, fsd2-0 - target seed

  • namespace - during the initial deployment of seed, new namespaces are not created automatically on api cluster, therefore are not deleted automatically also.
  • machines - still in old namespace
    • before migration:

migration shoot machine before

  • after migration:

migration shoot machine after

  • secrets - not deleted or recreated. Secrets (see below) created during initial deployment of shoot, were created in shoot namespace on api cluster, but during the migration of shoot were not deleted or recreated in new namespace.

migration shoot secret after

migration shoot secret after

  • shoot yaml

After the migration of shoot between seeds, some information are not updated in shoot yaml.

  secretBindingName: fsd2-1-creds
  seedName: fsd2-0
  seedSelector:
    matchLabels:
      purpose: dev-fsd2-1

It is not recommended to have fields seedName and seedSelector in one shoot yaml file, because this can change internal logic of kubernetes actions during shoot reconciliation process. From observations, we can see that seeName field has higher precedence as seedSelector.

  • check OIDC kubeconfigs after migration