[Yandex Cloud documentation](../../../index.md) > [Yandex Managed Service for Kubernetes](../../index.md) > [Tutorials](../index.md) > [Migrating to Managed Service for Kubernetes](index.md) > Migrating from a cloud provider

# Migrating from a public cloud to Managed Service for Kubernetes

This guide explains how to migrate Kubernetes workloads from a managed service of another cloud provider to Managed Service for Kubernetes.

The key strategy is to migrate step by step while keeping both the source and target clusters running in parallel. This minimizes the impact on production services and ensures a safe rollback path.

To migrate workloads to Managed Service for Kubernetes:

1. [Develop a migration plan](#inventory).
1. [Set up your Yandex Cloud infrastructure](#infrastructure).
1. [Migrate container images](#images).
1. [Migrate stateful workloads](#stateful).
1. [Migrate stateless workloads](#stateless).
1. [Configure the load balancers and update your DNS records](#dns).
1. [Complete your migration](#finalization).


## Required paid resources {#paid-resources}

* Managed Service for Kubernetes master (see [Managed Service for Kubernetes pricing](../../pricing.md)).
* Managed Service for Kubernetes cluster nodes: use of computing resources and storage (see [Yandex Compute Cloud pricing](../../../compute/pricing.md)).
* Public IP addresses for the Managed Service for Kubernetes cluster's master and nodes with public access enabled (see [Yandex Virtual Private Cloud pricing](../../../vpc/pricing.md#prices-public-ip)).
* Each active L7 load balancer, if using the Gwin controller: use of computing resources (see [Application Load Balancer pricing](../../../application-load-balancer/pricing.md)).
* Each network load balancer, if using the `LoadBalancer` service type: incoming and outgoing traffic processed by the load balancer (see [Yandex Network Load Balancer pricing](../../../network-load-balancer/pricing.md)).
* Container Registry: storage of migrated Docker images (see [Container Registry pricing](../../../container-registry/pricing.md)).
* Object Storage bucket: use of storage, data operations (see [Yandex Object Storage pricing](../../../storage/pricing.md)).
* Data Transfer transfers, if migrating managed databases (see [Yandex Data Transfer pricing](../../../data-transfer/pricing.md)).


## Getting started {#before-you-begin}

Sign up for Yandex Cloud and create a [billing account](../../../billing/concepts/billing-account.md):
1. Navigate to the [management console](https://console.yandex.cloud) and log in to Yandex Cloud or create a new account.
1. On the **[Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts)** page, make sure you have a billing account linked and it has the `ACTIVE` or `TRIAL_ACTIVE` [status](../../../billing/concepts/billing-account-statuses.md). If you do not have a billing account, [create one](../../../billing/quickstart/index.md) and [link](../../../billing/operations/pin-cloud.md) a cloud to it.

If you have an active billing account, you can create or select a [folder](../../../resource-manager/concepts/resources-hierarchy.md#folder) for your infrastructure on the [cloud page](https://console.yandex.cloud/cloud).

[Learn more about clouds and folders here](../../../resource-manager/concepts/resources-hierarchy.md).

## Develop a migration plan {#inventory}

Before the migration, make sure to inventory your workloads and assess the compatibility between the source and target clusters. This helps you estimate migration complexity, map out the order in which to migrate your services, and develop a rollback plan in case of critical issues.

### Inventory your workloads {#workloads-inventory}

Get a list of source cluster resources for all namespaces: applications, versions, dependencies, and network rules. Review the full migration plan in advance to understand in what order you need to move your resources.

Make sure that all stateful workloads, including managed databases and StatefulSets with PersistentVolumes, have up-to-date backups.

Run this command to get a full list of your source cluster resources:

```bash
for ns in $(kubectl get ns --no-headers -o custom-columns=':metadata.name'); do
  echo "=== Namespace: $ns ==="
  kubectl get deploy,sts,ds,job,cronjob,svc,ingress,pvc,cm,secret,hpa,pdb -n $ns
done
```

Inventory checklist:

#|
|| **Resource** | **Details to collect** ||
|| Deployments, StatefulSets, DaemonSets, Jobs, CronJobs | Quantity, namespace, images ||
|| PersistentVolumeClaim | Size, StorageClass, access mode (RWO/RWX) ||
|| LoadBalancer-type services | External IPs, DNS names ||
|| Ingress / HTTPRoute | Hosts, TLS, IngressClass, or GatewayClass ||
|| ConfigMap and Secret | List ||
|| CustomResourceDefinitions and Operators | List of installed CRDs and operators ||
|#

### Assess compatibility {#compatibility-assessment}

To make sure your cluster components work correctly after the migration, assess their compatibility with the target cluster in advance. Create a list of changes you need to make to the manifests and plan how to replace incompatible source cluster components with their Yandex Cloud alternatives.

The scope of changes depends on the version gap between the source and target Kubernetes clusters. The wider the gap, the more changes you need to make, as both vendor-specific CRDs and standard Kubernetes API groups may differ. For supported versions, see [Support for Kubernetes versions](../../concepts/k8s-supported-versions.md).

{% note tip %}

Run the `kubectl api-resources` command on both the source and target clusters to compare API resources, or use the [kube-no-trouble (kubent)](https://github.com/doitintl/kube-no-trouble) utility to check manifest compatibility.

{% endnote %}

Key considerations to keep in mind:

* Check for vendor-specific CRDs in the source cluster that may not be available in Yandex Cloud. Replace the components with [Yandex Cloud services](https://yandex.cloud/en/services) or [solutions from Yandex Cloud Marketplace](../../operations/applications/marketplace.md).
* Note that PodSecurityPolicy is removed in Kubernetes versions 1.25 and up. If using PodSecurityPolicy in the source cluster, [migrate to PodSecurity Admission](https://kubernetes.io/docs/tasks/configure-pod-container/migrate-from-psp).
* Replace the storage classes (`storageClassName`) in your manifests with those [supported in Managed Service for Kubernetes](../../operations/volumes/manage-storage-class.md).
* We recommend using the [Gwin controller](../../alb-ref/gwin-index.md) for L7 load balancing.

### Develop the service migration plan {#planning}

Decide on the order for migrating your services: start with the least critical ones and finish with production workloads. To redirect traffic, use a zero-downtime [blue-green deployment](https://martinfowler.com/bliki/BlueGreenDeployment.html) strategy or a phased transition with a maintenance window.

Key considerations to keep in mind:

* Perform an end-to-end migration in a staging environment before migrating production workloads.
* Develop a rollback plan for critical issues and align it with your team in advance.
* Work closely with development and support teams at all stages.
* Choose off-peak hours to perform the migration.
* Monitor metrics before, during, and after the migration using [Yandex Monitoring](../../../monitoring/index.md).

## Set up your Yandex Cloud infrastructure {#infrastructure}

Prepare the target environment in Yandex Cloud for your workloads.

### Configure access and permissions {#access-and-permissions}

[Create service accounts](../../../iam/operations/sa/create.md) to manage cluster resources and worker nodes, and [assign roles to them](../../../iam/operations/sa/assign-role-for-sa.md).

{% cut "Roles you may need" %}

To manage the cluster:

* `k8s.clusters.agent`.
* `k8s.tunnelClusters.agent` instead of `k8s.clusters.agent`, if creating the cluster in tunneling mode.

Learn more about [roles in Managed Service for Kubernetes](../../security/index.md).

To manage network resources:

* `vpc.publicAdmin`.
* `vpc.privateAdmin`.
* `vpc.user`.
* `vpc.bridgeAdmin` if the VPC resides in a different folder.

Learn more about [roles in VPC](../../../vpc/security/index.md).

To work with images:

* `container-registry.images.puller`.
* `cloud-registry.artifacts.puller` if using Cloud Registry as an alternative to Container Registry.

Learn more about [roles in Container Registry](../../../container-registry/security/index.md) and [Cloud Registry roles](../../../cloud-registry/security/index.md).

If using secret encryption:

* `kms.keys.encrypterDecrypter`

Learn more about [roles in KMS](../../../kms/security/index.md).

If using Object Storage for backups:

* `storage.editor`

Learn more about [roles in Object Storage](../../../storage/security/index.md).

{% endcut %}

### Set up the network infrastructure {#network-infrastructure}

Set up a network infrastructure for the cluster: an isolated network with security rules for all types of cluster traffic:

1. Create a [VPC](../../../vpc/operations/network-create.md) and [subnets](../../../vpc/operations/subnet-create.md) in three zones to ensure high availability.
1. Create [security groups](../../operations/connect/security-groups.md) to isolate cluster traffic, node traffic, and inbound connections. You must create [five groups](../../operations/connect/security-groups.md#apply) in total.

### Create a Managed Service for Kubernetes cluster {#cluster}

1. [Create](../../operations/kubernetes-cluster/kubernetes-cluster-create.md) a Managed Service for Kubernetes cluster. Use the same Kubernetes version as in your source cluster or higher.
1. [Create a node group](../../operations/node-group/node-group-create.md) in each availability zone.

## Migrate container images {#images}

[Move container images](../../../container-registry/operations/docker-image/docker-image-push.md) to Yandex Container Registry one by one, keeping their tags and metadata.

You can also use [Yandex Cloud Registry](../../../cloud-registry/index.md) as an alternative storage for images. Unlike Yandex Container Registry, Cloud Registry supports not only Docker images but other artifact types as well.

## Migrate stateful workloads {#stateful}

Migrating stateful workloads, such as managed databases and StatefulSets with PersistentVolumes, is the most complex step of the migration. They store data and cannot be recreated with zero data loss.

{% note warning %}

Make sure that all stateful workloads, including managed databases and StatefulSets with PersistentVolumes, have up-to-date backups.

{% endnote %}

### Migrate managed databases {#managed-databases}

Use [Yandex Data Transfer](../../../data-transfer/index.md) to migrate managed databases. [Yandex Data Transfer](../../../data-transfer/index.md) allows you to migrate data while keeping your source online and minimizing the downtime of applications using the source.

Use the [transfer matrix](../../../data-transfer/transfer-matrix.md) to check that the [**Snapshot and increment**](../../../data-transfer/concepts/transfer-lifecycle.md#copy-and-replication) transfer type is supported for your source and target, then refer to [your database guide](../../../data-transfer/tutorials/index.md#migration) to complete the migration.

{% note info %}

Make sure that Data Transfer has network access to the source database. For the current Data Transfer IP address ranges, see the [relevant guide](../../../data-transfer/concepts/network.md#source-external).

{% endnote %}

If Data Transfer does not support your source or you need more control, refer to your target database guides.

### Migrate StatefulSets with PersistentVolumes {#statefulsets-persistent-volumes}

To migrate StatefulSets with PersistentVolumes, use [Velero](https://velero.io/) with file system backups via `node-agent` (formerly kopia). This method works with any PVCs regardless of your CSI provider.

{% note tip %}

If you have less than 50 GB of data or cannot use Velero, you can migrate data manually via `rsync`. This requires direct network connectivity between your clusters.

{% endnote %}

Proceed as follows:

1. Create a bucket in [Yandex Object Storage](../../../storage/index.md) to store backups.

1. Create a file named `credentials-velero` containing the [static access key data](../../../iam/operations/authentication/manage-access-keys.md#create-access-key) for the [service account](../../../iam/operations/sa/create.md) that has access to the bucket:

   ```
   [default]
   aws_access_key_id = <key_ID>
   aws_secret_access_key = <secret_key>
   ```
   
1. [Install the Velero CLI](https://velero.io/docs/main/basic-install/) on the machine you will use to perform the migration. It must have `kubectl` access to the source and target clusters.

   {% note tip %}

   The `velero-plugin-for-aws` plugin version in the commands below may be outdated. For the latest version, refer to [this Velero article](https://velero.io/docs/main/supported-providers/).

   {% endnote %}

1. Install Velero in the source cluster:

   1. Make sure the source cluster context is active:

      ```bash
      kubectl config current-context
      ```

   1. Create a namespace for Velero:

      ```bash
      kubectl create namespace velero
      ```

   1. Install Velero:

      ```bash
      velero install \
        --provider aws \
        --plugins velero/velero-plugin-for-aws:v1.14.0 \
        --bucket <bucket_name> \
        --secret-file ./credentials-velero \
        --backup-location-config \
          region=ru-central1,s3ForcePathStyle=true,s3Url=https://storage.yandexcloud.net \
        --use-volume-snapshots=false \
        --use-node-agent \
        --uploader-type=kopia
      ```

      Where:

      * `--provider aws`: Uses an AWS plugin compatible with Object Storage.
      * `--use-node-agent`: Enables DaemonSet to perform file system backups.
      * `--uploader-type=kopia`: Recommended uploader, works faster than restic.
      * `--use-volume-snapshots=false`: Disables CSI snapshots to transfer data via kopia.

   1. Check component status:

      ```bash
      kubectl get pods -n velero
      kubectl get backupstoragelocation -n velero
      velero backup-location get
      ```

      `BackupStorageLocation` must switch to `Available`.

1. Create a backup of the required namespaces:

   ```bash
   velero backup create migration-backup \
     --include-namespaces <namespace> \
     --default-volumes-to-fs-backup \
     --wait
   ```

   You can check the status and logs using the following commands:

   ```bash
   velero backup describe migration-backup --details
   velero backup logs migration-backup
   ```

1. Install Velero in the target Managed Service for Kubernetes cluster:

   1. Switch to the target cluster context:

      ```bash
      kubectl config use-context <target_cluster_context>
      ```

   1. Create a namespace for Velero:

      ```bash
      kubectl create namespace velero
      ```

   1. Install Velero with the same parameters as in the source cluster, specifying the same bucket:

      ```bash
      velero install \
        --provider aws \
        --plugins velero/velero-plugin-for-aws:v1.14.0 \
        --bucket <bucket_name> \
        --secret-file ./credentials-velero \
        --backup-location-config \
          region=ru-central1,s3ForcePathStyle=true,s3Url=https://storage.yandexcloud.net \
        --use-volume-snapshots=false \
        --use-node-agent \
        --uploader-type=kopia
      ```

   1. Confirm that the backup from the source cluster is visible in the target cluster:

      ```bash
      kubectl get pods -n velero
      velero backup-location get
      velero backup get
      ```

      `BackupStorageLocation` must switch to `Available`, and the `migration-backup`, to `Completed`.

1. Restore data from the backup:

   ```bash
   velero restore create \
     --from-backup migration-backup \
     --wait
   ```

   You can check the status and logs using the following commands:

   ```bash
   velero restore describe migration-backup --details
   velero restore logs migration-backup
   ```

   {% note tip %}

   If the StorageClass names in the source cluster and Managed Service for Kubernetes cluster do not match, create a ConfigMap with the StorageClass mapping before initiating recovery:

   ```yaml
   apiVersion: v1
   kind: ConfigMap
   metadata:
     name: change-storage-class-config
     namespace: velero
     labels:
       velero.io/plugin-config: ""
       velero.io/change-storage-class: RestoreItemAction
   data:
     <source_storage_class>: yc-network-ssd
   ```

   {% endnote %}

## Migrate stateless workloads {#stateless}

To migrate stateless workloads, export your source cluster manifests, update them for Yandex Cloud, and apply to the target cluster.

Checklist for updating manifests:

* Replace vendor-specific CRDs with [Yandex Cloud services](https://yandex.cloud/en/services) or [solutions from Yandex Cloud Marketplace](../../operations/applications/marketplace.md).
* For any deprecated `apiVersion`, update the version to make it compatible with the target Kubernetes version.
* Use the [Gwin controller](../../alb-ref/gwin-index.md) (`gwin-default`) in `ingressClassName` and `gatewayClassName`.
* Replace resource annotations used for configuring the load balancer with [Yandex Cloud annotations](../../alb-ref/index.md).
* Make sure image links lead to Yandex Container Registry (`cr.yandex/<id>/...`).

You can use [kubectl-neat](https://github.com/itaysk/kubectl-neat) to clean up manifests.

## Configure the load balancers and update your DNS records {#dns}

Reroute traffic to the new cluster.

Managed Service for Kubernetes supports two load balancing methods:

* [Gwin](../../alb-ref/gwin-index.md).
* Network Load Balancer: Created automatically for a service of the `LoadBalancer` type.

Steps to switch traffic:

1. Deploy Gateway or Ingress resources in the Managed Service for Kubernetes cluster.
1. Get the external IP addresses of the new load balancers.
1. Test your services using temporary DNS records.
1. Reduce the TTL of production DNS records in advance, then update them incrementally.
1. Monitor DNS propagation and TLS certificate updates.

{% note tip %}

If you face critical issues after updating DNS records, go back to using the old IP addresses. The source cluster must remain operational until all TTLs expire and you confirm a successful migration.

{% endnote %}

## Complete your migration {#finalization}

Take final steps and optimize your configuration:

1. Make sure all services work correctly in Managed Service for Kubernetes.
1. Check metrics and performance in [Yandex Monitoring](../../../monitoring/index.md).
1. Disable your source cloud resources after confirming stable operation.
1. Optimize the cluster configuration to match your actual workload.
1. Delete temporary resources: the Velero bucket, Data Transfer pipelines, VPN tunnels, and temporary login credentials.