Migrating Kubernetes resources to a different availability zone
In a Managed Service for Kubernetes cluster, you can migrate a node group and pod workload from one availability zone to another.
Getting started
If you do not have the Yandex Cloud CLI installed yet, install and initialize it.
By default, the CLI uses the folder specified when creating the profile. To change the default folder, use the yc config set folder-id <folder_ID> command. You can also set a different folder for any specific command using the --folder-name or --folder-id parameter.
If you have already installed the CLI, update to its latest version:
yc components update
Migrate the node group and pod workload to a different availability zone
Set up the node group and proceed with migration using one of the following methods:
-
Migrating a node group directly to the new availability zone. It depends on the type of workload in the pods:
-
Stateless workload: Application functioning in pods during migration depends on how workload is distributed between cluster nodes. If the pods reside both in the node group you are migrating and the groups for which the availability zone remains unchanged, the applications keep running. If the pods only reside in the group you are migrating, both the pods and the applications in them must be briefly stopped.
Stateless workload examples include the web server, Yandex Application Load Balancer ingress controller, and REST API apps.
-
Stateful workloads: Pods and applications must be briefly stopped, regardless of how workload is distributed between cluster nodes.
Stateful workload examples include databases and storages.
-
-
Gradually migrating stateless and stateful workloads to a new node group: It involves creating a new node group in the new availability zone and gradually discontinuing the old nodes. This enables you to manage workload transfer.
Getting started
-
Check if the
nodeSelector,affinity, ortopology spread constraintsstrategies are used to assign the pods to the group's nodes. For more information on strategies, see this Kubernetes article and High availability and fault tolerance. To check a pod's assignment to nodes and remove it:Management console-
In the management console
, select the folder with your Managed Service for Kubernetes cluster. -
In the list of services, select Managed Service for Kubernetes.
-
Open the cluster page and navigate to Workload.
-
On the Pods tab, open the pod page.
-
Navigate to the YAML tab.
-
Check if the pod manifest contains the following parameters and Kubernetes labels in them:
-
Parameters:
spec.nodeSelectorspec.affinityspec.topologySpreadConstraints
-
Kubernetes labels set in the parameters:
failure-domain.beta.kubernetes.io/zone:<availability_zone>topology.kubernetes.io/zone:<availability_zone>
When the configuration includes at least one of these parameters containing at least one of the listed Kubernetes labels, node group and workload migration will not proceed.
-
-
Check the pod manifest for dependencies on the following entities:
- Availability zone you are migrating your resources from.
- Specific nodes within the group.
-
If you find any of the parameters, assignments, or dependencies listed above, remove them from the pod configuration:
-
Copy the YAML configuration from the management console.
-
Create a local YAML file and paste the copied configuration into it.
-
Remove any availability zone assignments from the configuration. For example, if the
spec.affinityparameter includes thefailure-domain.beta.kubernetes.io/zoneKubernetes label, remove it. -
Apply the new configuration:
kubectl apply -f <YAML_file_path> -
Make sure the pod status changed to
Running:kubectl get pods
-
-
Repeat these steps for each pod to check and update its configuration.
-
-
Transfer persistent data, such as databases, message queues, monitoring servers, and log servers, to the new availability zone.
Migrating stateless workloads
-
Create a subnet in the new availability zone and migrate the node group:
CLITerraform-
Create a subnet:
yc vpc subnet create \ --name <subnet_name> \ --zone <availability_zone> \ --network-id <network_ID> \ --range <subnet_CIDR>Where:
--name: Subnet name.--zone: Availability zone (ru-central1-a,ru-central1-b, orru-central1-d).--network-id: ID of the network the new subnet belongs to.--range: List of IPv4 addresses for outgoing and incoming traffic, e.g.,10.0.0.0/22or192.168.0.0/16. Make sure the addresses are unique within the network. The minimum subnet size is/28, the maximum subnet size is/16. Only IPv4 is supported.
-
Move the node group to the new availability zone. The example below shows a command for moving a group residing in a single zone:
yc managed-kubernetes node-group update \ --id <node_group_ID> \ --location zone=<availability_zone>,subnet-id=<subnet_ID> \ --network-interface subnets=<subnet_ID>,` `ipv4-address=nat,` `security-group-ids=[<security_group_IDs>]Where:
id: ID of the node group to move to a different availability zone.zone: Availability zone you want to move your node group to (ru-central1-a,ru-central1-b, orru-central1-d).subnet-idandsubnets: ID of the new subnet you created earlier.ipv4-address: Method of assigning an IPv4 address. Thenatvalue allows assigning public and internal IP addresses to nodes.security-group-ids: List of security group IDs.
Warning
If you want to keep the values of other network parameters for the node group, specify them in the
network-interfaceparameter as well. Otherwise, the group can be recreated with default values. For more information, see Updating a Managed Service for Kubernetes node group.It is important to provide the
ipv4-addressandsecurity-group-idsparameters in the command: this will assign public IP addresses to the node group and keep security groups within it.This command recreates the nodes within their group in the specified availability zone and subnet. When recreating, the deployment settings are considered: the maximum number of nodes by which you can increase or decrease the group size versus the original node count.
How to move a node group residing in different availability zones
In this case, use the following command:
yc managed-kubernetes node-group update \ --id <node_group_ID> \ --location zone=<availability_zone>,subnet-id=<subnet_ID> \ ... --location zone=<availability_zone>,subnet-id=<subnet_ID> \ --network-interface subnets=[<subnet_IDs>],` `ipv4-address=nat,` `security-group-ids=[<security_group_IDs>]Where:
id: ID of the node group to move to a different availability zone.zone: Availability zone (ru-central1-a,ru-central1-b, orru-central1-d). Specify thelocationparameters for each availability zone that will host the node group.subnet-idandsubnets: IDs of the subnets for the specified availability zones.ipv4-address: Method of assigning an IPv4 address. Thenatvalue allows assigning public and internal IP addresses to nodes.security-group-ids: List of security group IDs.
Alert
To make sure your node group is not recreated (unless it is your intention to do so), analyze the output of the
terraform planandterraform applycommands before applying the configuration.You can migrate a node group to a different availability zone without recreating it only if the configuration file contains the
allocation_policysection.-
Make the following changes to the configuration file:
- Add a new subnet manifest (
yandex_vpc_subnetresource) in the availability zone to which you want to move the node group. - Change the node group location parameters (
yandex_kubernetes_node_groupresource):allocation_policy.location.subnet_id: Remove this parameter if it is in the manifest.allocation_policy.location.zone: Specify the availability zone you want to move the node group to.instance_template.network_interface.subnet_ids: Specify the new subnet ID. Add this parameter if it is not in the manifest.
resource "yandex_vpc_subnet" "my-new-subnet" { name = "<subnet_name>" zone = "<availability_zone>" network_id = "<network_ID>" v4_cidr_blocks = ["<subnet_CIDR>"] } ... resource "yandex_kubernetes_node_group" "k8s-node-group" { allocation_policy { location { zone = "<availability_zone>" } } ... instance_template { network_interface { subnet_ids = [yandex_vpc_subnet.my-new-subnet.id] ... } ... } ... }Where:
name: Subnet name.zone: Availability zone you want to move your node group to (ru-central1-a,ru-central1-b, orru-central1-d).network_id: ID of the network the new subnet belongs to.v4_cidr_blocks: List of IPv4 addresses to deal with outgoing and incoming traffic, e.g.,10.0.0.0/22or192.168.0.0/16. Make sure the addresses are unique within the network. The minimum subnet size is/28, the maximum subnet size is/16. Only IPv4 is supported.subnet_ids: ID of the new subnet.
- Add a new subnet manifest (
-
Check that the configuration file is correct.
-
In the command line, navigate to the directory that contains the current Terraform configuration files defining the infrastructure.
-
Run this command:
terraform validateTerraform will show any errors found in your configuration files.
-
-
Confirm updating the resources.
-
Run this command to view the planned changes:
terraform planIf you described the configuration correctly, the terminal will display a list of the resources to update and their parameters. This is a verification step that does not apply changes to your resources.
-
If everything looks correct, apply the changes:
-
Run this command:
terraform apply -
Confirm updating the resources.
-
Wait for the operation to complete.
-
-
The group nodes will be recreated in the specified availability zone and subnet. When recreating, the deployment settings are considered: the maximum number of nodes by which you can increase or decrease the group size versus the original node count.
-
-
Make sure the pods are running in the migrated node group:
kubectl get po --output wideThe output of this command shows the nodes on which your pods are currently running.
Migrating stateful workloads
The migration is based on scaling the StatefulSet controller. To migrate stateful workloads:
-
Get a list of
StatefulSetcontrollers to find the name of the one you need:kubectl get statefulsets -
Get the number of pods managed by the controller:
kubectl get statefulsets <controller_name> \ -n default -o=jsonpath='{.status.replicas}'Save this value. You will need it to scale the
StatefulSetcontroller once the migration of your stateful workloads is complete. -
Reduce the number of pods to zero:
kubectl scale statefulset <controller_name> --replicas=0This will stop the pods that are using disks, while retaining the PersistentVolumeClaim Kubernetes API object (PVC).
-
For the PersistentVolume object (PV) associated with
PersistentVolumeClaim, change thepersistentVolumeReclaimPolicyvalue fromDeletetoRetainto prevent accidental data loss.-
Get the name of the
PersistentVolumeobject:kubectl get pv -
Edit the
PersistentVolumeobject:kubectl edit pv <PV_name>
-
-
Check if the
PersistentVolumeobject manifest contains thespec.nodeAffinityparameter:kubectl get pv <PV_name> --output='yaml'If the manifest contains the
spec.nodeAffinityparameter with an availability zone specified in it, save this parameter. You will need to specify it in a newPersistentVolumeobject. -
Create a
PersistentVolumesnapshot. For more information about snapshots, see this Kubernetes article .-
Get the name of the
PersistentVolumeClaimobject:kubectl get pvc -
Create the
snapshot.yamlwith the snapshot manifest and specify thePersistentVolumeClaimname in it:apiVersion: snapshot.storage.k8s.io/v1 kind: VolumeSnapshot metadata: name: new-snapshot-test-<number> spec: volumeSnapshotClassName: yc-csi-snapclass source: persistentVolumeClaimName: <PVC_name>If you are creating several snapshots for different
PersistentVolumeClaimobjects, specify the<number>(consecutive) to make sure each snapshot gets a uniquemetadata.namevalue. -
Create a snapshot:
kubectl apply -f snapshot.yaml -
Make sure the snapshot was created:
kubectl get volumesnapshots.snapshot.storage.k8s.io -
Make sure the VolumeSnapshotContent
Kubernetes API object was created:kubectl get volumesnapshotcontents.snapshot.storage.k8s.io
-
-
Get the snapshot ID:
yc compute snapshot list -
Create a VM disk from the snapshot:
yc compute disk create \ --source-snapshot-id <snapshot_ID> \ --zone <availability_zone>In the command, specify the availability zone to which you are migrating your Managed Service for Kubernetes node group.
Save the following parameters from the command output:
- Disk ID from the
idfield. - Disk type from the
type_idfield. - Disk size from the
sizefield.
- Disk ID from the
-
Create a
PersistentVolumeKubernetes API object from the new disk:-
Create the
persistent-volume.yamlfile with thePersistentVolumemanifest:apiVersion: v1 kind: PersistentVolume metadata: name: new-pv-test-<number> spec: capacity: storage: <PersistentVolume_size> accessModes: - ReadWriteOnce csi: driver: disk-csi-driver.mks.ycloud.io fsType: ext4 volumeHandle: <disk_ID> storageClassName: <disk_type>In the file, specify the parameters of the disk created from the snapshot:
-
spec.capacity.storage: Disk size. -
spec.csi.volumeHandle: Disk ID. -
spec.storageClassName: Disk type. Specify it in accordance with the following table:Snapshot-based disk type Disk type for the YAML file network-ssdyc-network-ssdnetwork-ssd-nonreplicatedyc-network-ssd-nonreplicatednetwork-nvmeyc-network-nvmenetwork-hddyc-network-hdd
If you are creating several
PersistentVolumeobjects, specify the<number>(consecutive) to make sure each gets a uniquemetadata.namevalue.Add the previously saved
spec.nodeAffinityparameter to the manifest and specify the availability zone to which you are migrating your Managed Service for Kubernetes node group. If you skip it, the workload may run in a different availability zone wherePersistentVolumeis not available, causing an error.Here is an example of the
spec.nodeAffinityparameter:spec: ... nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: failure-domain.beta.kubernetes.io/zone operator: In values: - ru-central1-d -
-
Create a
PersistentVolumeobject:kubectl apply -f persistent-volume.yaml -
Make sure
PersistentVolumewas created:kubectl get pvThe command output will display the
new-pv-test<number>object. -
If you specified the
spec.nodeAffinityparameter in the manifest, make sure to apply it for thePersistentVolumeobject:Management console- In the management console
, select the folder with your Managed Service for Kubernetes cluster. - In the list of services, select Managed Service for Kubernetes.
- Open the cluster page and navigate to Storage.
- On the Persistent Volumes tab, find the
new-pv-test-<number>object and check the Availability zone field value. It should specify an availability zone. A dash means there is no assignment to an availability zone.
- In the management console
-
If you skipped the
spec.nodeAffinityparameter in the manifest, you can add it by editing thePersistentVolumeobject:kubectl edit pv new-pv-test-<number>
-
-
Create a
PersistentVolumeClaimobject from the newPersistentVolume:-
Create the
persistent-volume-claim.yamlfile with thePersistentVolumeClaimmanifest:apiVersion: v1 kind: PersistentVolumeClaim metadata: name: <PVC_name> spec: accessModes: - ReadWriteOnce resources: requests: storage: <PV_size> storageClassName: <disk_type> volumeName: new-pv-test-<number>In the file, set the following parameters:
metadata.name: Name of thePersistentVolumeClaimobject you used to create the snapshot. You can get this name by running thekubectl get pvccommand.spec.resources.requests.storage:PersistentVolumesize, which matches the size of the created disk.spec.storageClassName:PersistentVolumedisk type, which matches the disk type of the newPersistentVolume.spec.volumeName: Name of thePersistentVolumeobject to basePersistentVolumeClaimon. You can get this name by running thekubectl get pvcommand.
-
Delete the original
PersistentVolumeClaimso you can replace it:kubectl delete pvc <PVC_name> -
Create a
PersistentVolumeClaimobject:kubectl apply -f persistent-volume-claim.yaml -
Make sure
PersistentVolumeClaimwas created:kubectl get pvcThe command output will return the
PersistentVolumeClaimsize you specified in the YAML file.
-
-
Create a subnet in the new availability zone and migrate the node group:
CLITerraform-
Create a subnet:
yc vpc subnet create \ --name <subnet_name> \ --zone <availability_zone> \ --network-id <network_ID> \ --range <subnet_CIDR>Where:
--name: Subnet name.--zone: Availability zone (ru-central1-a,ru-central1-b, orru-central1-d).--network-id: ID of the network the new subnet belongs to.--range: List of IPv4 addresses for outgoing and incoming traffic, e.g.,10.0.0.0/22or192.168.0.0/16. Make sure the addresses are unique within the network. The minimum subnet size is/28, the maximum subnet size is/16. Only IPv4 is supported.
-
Move the node group to the new availability zone. The example below shows a command for moving a group residing in a single zone:
yc managed-kubernetes node-group update \ --id <node_group_ID> \ --location zone=<availability_zone>,subnet-id=<subnet_ID> \ --network-interface subnets=<subnet_ID>,` `ipv4-address=nat,` `security-group-ids=[<security_group_IDs>]Where:
id: ID of the node group to move to a different availability zone.zone: Availability zone you want to move your node group to (ru-central1-a,ru-central1-b, orru-central1-d).subnet-idandsubnets: ID of the new subnet you created earlier.ipv4-address: Method of assigning an IPv4 address. Thenatvalue allows assigning public and internal IP addresses to nodes.security-group-ids: List of security group IDs.
Warning
If you want to keep the values of other network parameters for the node group, specify them in the
network-interfaceparameter as well. Otherwise, the group can be recreated with default values. For more information, see Updating a Managed Service for Kubernetes node group.It is important to provide the
ipv4-addressandsecurity-group-idsparameters in the command: this will assign public IP addresses to the node group and keep security groups within it.This command recreates the nodes within their group in the specified availability zone and subnet. When recreating, the deployment settings are considered: the maximum number of nodes by which you can increase or decrease the group size versus the original node count.
How to move a node group residing in different availability zones
In this case, use the following command:
yc managed-kubernetes node-group update \ --id <node_group_ID> \ --location zone=<availability_zone>,subnet-id=<subnet_ID> \ ... --location zone=<availability_zone>,subnet-id=<subnet_ID> \ --network-interface subnets=[<subnet_IDs>],` `ipv4-address=nat,` `security-group-ids=[<security_group_IDs>]Where:
id: ID of the node group to move to a different availability zone.zone: Availability zone (ru-central1-a,ru-central1-b, orru-central1-d). Specify thelocationparameters for each availability zone that will host the node group.subnet-idandsubnets: IDs of the subnets for the specified availability zones.ipv4-address: Method of assigning an IPv4 address. Thenatvalue allows assigning public and internal IP addresses to nodes.security-group-ids: List of security group IDs.
Alert
To make sure your node group is not recreated (unless it is your intention to do so), analyze the output of the
terraform planandterraform applycommands before applying the configuration.You can migrate a node group to a different availability zone without recreating it only if the configuration file contains the
allocation_policysection.-
Make the following changes to the configuration file:
- Add a new subnet manifest (
yandex_vpc_subnetresource) in the availability zone to which you want to move the node group. - Change the node group location parameters (
yandex_kubernetes_node_groupresource):allocation_policy.location.subnet_id: Remove this parameter if it is in the manifest.allocation_policy.location.zone: Specify the availability zone you want to move the node group to.instance_template.network_interface.subnet_ids: Specify the new subnet ID. Add this parameter if it is not in the manifest.
resource "yandex_vpc_subnet" "my-new-subnet" { name = "<subnet_name>" zone = "<availability_zone>" network_id = "<network_ID>" v4_cidr_blocks = ["<subnet_CIDR>"] } ... resource "yandex_kubernetes_node_group" "k8s-node-group" { allocation_policy { location { zone = "<availability_zone>" } } ... instance_template { network_interface { subnet_ids = [yandex_vpc_subnet.my-new-subnet.id] ... } ... } ... }Where:
name: Subnet name.zone: Availability zone you want to move your node group to (ru-central1-a,ru-central1-b, orru-central1-d).network_id: ID of the network the new subnet belongs to.v4_cidr_blocks: List of IPv4 addresses to deal with outgoing and incoming traffic, e.g.,10.0.0.0/22or192.168.0.0/16. Make sure the addresses are unique within the network. The minimum subnet size is/28, the maximum subnet size is/16. Only IPv4 is supported.subnet_ids: ID of the new subnet.
- Add a new subnet manifest (
-
Check that the configuration file is correct.
-
In the command line, navigate to the directory that contains the current Terraform configuration files defining the infrastructure.
-
Run this command:
terraform validateTerraform will show any errors found in your configuration files.
-
-
Confirm updating the resources.
-
Run this command to view the planned changes:
terraform planIf you described the configuration correctly, the terminal will display a list of the resources to update and their parameters. This is a verification step that does not apply changes to your resources.
-
If everything looks correct, apply the changes:
-
Run this command:
terraform apply -
Confirm updating the resources.
-
Wait for the operation to complete.
-
-
The group nodes will be recreated in the specified availability zone and subnet. When recreating, the deployment settings are considered: the maximum number of nodes by which you can increase or decrease the group size versus the original node count.
-
-
Restore the original number of pods managed by the
StatefulSetcontroller:kubectl scale statefulset <controller_name> --replicas=<number_of_pods>This will start the pods in the migrated node group.
In the command, specify the following parameters:
- Name of the
StatefulSetcontroller. You can get it by running thekubectl get statefulsetscommand. - Number of pods prior to scaling down the controller.
- Name of the
-
Make sure the pods are running in the migrated node group:
kubectl get po --output wideThe output of this command shows the nodes on which your pods are currently running.
-
Delete the unused
PersistentVolumeobject, i.e., the one with theReleasedstatus.-
Get the name of the
PersistentVolumeobject:kubectl get pv -
Delete the
PersistentVolumeobject:kubectl delete pv <PV_name>
-
Gradually migrating stateless and stateful workloads
See below how to gradually migrate workloads from the old node group to the new one. For PersistentVolume and PersistentVolumeClaim migration steps, see Migrating stateful workloads.
-
Create a new Managed Service for Kubernetes node group in the new availability zone.
-
Disable running new pods in the old node group:
kubectl cordon -l yandex.cloud/node-group-id=<old_node_group_ID> -
For each node in the old node group, run the following command:
kubectl drain <node_name> --ignore-daemonsets --delete-emptydir-dataThe pods will gradually move to the new node group.
-
Make sure the pods are running in the new node group:
kubectl get po --output wide