[Документация Yandex Cloud](../../index.md) > [Практические руководства](../index.md) > [Базовая инфраструктура](../infrastructure/index.md) > Инструменты > Управление ресурсами Kubernetes с помощью провайдера Terraform

# Управление ресурсами Kubernetes в кластере Yandex Managed Service for Kubernetes с помощью провайдера Terraform

# Управление ресурсами Kubernetes в кластере Yandex Managed Service for Kubernetes с помощью провайдера Terraform

Вы можете создать ресурсы Kubernetes с помощью манифестов Terraform. Для этого подключите Terraform-провайдер `kubernetes`. Он поддерживает Terraform-ресурсы, которые соответствуют конфигурационным файлам YAML для различных Kubernetes-ресурсов.

Использовать Terraform для создания Kubernetes-ресурсов удобно, если через Terraform вы поддерживаете инфраструктуру для [кластера Yandex Managed Service for Kubernetes](../../managed-kubernetes/concepts/index.md#kubernetes-cluster). Так вы можете описывать все ресурсы на одном языке разметки.

Кроме того, Terraform отслеживает зависимости между ресурсами и предотвращает создание, изменение или удаление ресурса, если для него не готовы зависимости. Допустим, вы создаете ресурс `PersistentVolumeClaim`. Ему нужно определенное пространство в хранилище для ресурса `PersistentVolume`, но места не хватает. Terraform отследит нехватку места и не позволит создать ресурс `PersistentVolumeClaim`.

Ниже рассматривается пример, как создать стандартные ресурсы Kubernetes с помощью Terraform.

Чтобы с помощью Terraform создать ресурсы Kubernetes:

1. [Подготовьте инфраструктуру](#prepare-kubernetes-infrastructure).
1. [Подключите провайдер](#apply-kubernetes-provider) `kubernetes`.
1. [Создайте ресурсы Kubernetes](#create-standard-resources).
1. [Убедитесь, что приложение кластера доступно из интернета](#verify-setup).

Если созданные ресурсы вам больше не нужны, [удалите их](#clear-out).


## Необходимые платные ресурсы {#paid-resources}

В стоимость поддержки описываемого решения входят:

* Плата за кластер Managed Service for Kubernetes: использование мастера и исходящий трафик ([тарифы Managed Service for Kubernetes](../../managed-kubernetes/pricing.md)).
* Плата за узлы кластера (ВМ): использование вычислительных ресурсов, операционной системы и хранилища ([тарифы Compute Cloud](../../compute/pricing.md)).
* Плата за сетевой балансировщик нагрузки ([тарифы Network Load Balancer](../../network-load-balancer/pricing.md)).
* Плата за использование публичных IP-адресов для ВМ и сетевого балансировщика нагрузки ([тарифы Virtual Private Cloud](../../vpc/pricing.md)).


## Подготовьте инфраструктуру для Managed Service for Kubernetes {#prepare-kubernetes-infrastructure}

1. Если у вас еще нет Terraform, [установите его](terraform-quickstart.md#install-terraform).
1. [Получите данные для аутентификации](terraform-quickstart.md#get-credentials). Вы можете добавить их в переменные окружения или указать далее в файле с настройками провайдера.
1. [Настройте и инициализируйте провайдер](terraform-quickstart.md#configure-provider). Чтобы не создавать конфигурационный файл с настройками провайдера вручную, [скачайте его](https://github.com/yandex-cloud-examples/yc-terraform-provider-settings/blob/main/provider.tf).

   На этом шаге файл не должен содержать настройки провайдера `kubernetes`. Они будут добавлены [позднее](#apply-kubernetes-provider).

1. Поместите конфигурационный файл в отдельную рабочую директорию и [укажите значения параметров](terraform-quickstart.md#configure-provider). Если данные для аутентификации не были добавлены в переменные окружения, укажите их в конфигурационном файле.
1. Скачайте в ту же рабочую директорию файл конфигурации [k8s-cluster.tf](https://github.com/yandex-cloud-examples/yc-mk8s-cluster-infrastructure/blob/main/k8s-cluster.tf).

   В этом файле описаны:

   * сеть;
   * подсеть;
   * две группы безопасности — для кластера и группы узлов;
   * облачный сервисный аккаунт с ролями `k8s.clusters.agent`, `k8s.tunnelClusters.agent`, `vpc.publicAdmin`, `load-balancer.admin` и `container-registry.images.puller`;
   * кластер Managed Service for Kubernetes;
   * группа узлов Kubernetes.

1. Укажите значения переменных в файле `k8s-cluster.tf`.
1. Проверьте корректность файлов конфигурации Terraform с помощью команды:

   ```bash
   terraform validate
   ```

   Если в файлах конфигурации есть ошибки, Terraform на них укажет.

1. Создайте инфраструктуру:

   1. Выполните команду для просмотра планируемых изменений:
   
      ```bash
      terraform plan
      ```
   
      Если конфигурации ресурсов описаны верно, в терминале отобразится список изменяемых ресурсов и их параметров. Это проверочный этап: ресурсы не будут изменены.
   
   1. Если вас устраивают планируемые изменения, внесите их:
      1. Выполните команду:
   
         ```bash
         terraform apply
         ```
   
      1. Подтвердите изменение ресурсов.
      1. Дождитесь завершения операции.

   В указанном каталоге будут созданы все требуемые ресурсы. Проверить появление ресурсов и их настройки можно в [консоли управления](https://kz.console.yandex.cloud).

1. [Установите kubectl](https://kubernetes.io/ru/docs/tasks/tools/install-kubectl) и [настройте его на работу с созданным кластером](../../managed-kubernetes/operations/connect/index.md#kubectl-connect).

## Подключите провайдер kubernetes {#apply-kubernetes-provider}

1. В рабочей директории откройте файл с настройками провайдера `yandex`. У него должна быть следующая структура:

    ```hcl
    terraform {
      required_providers {
        yandex = {
          source = "yandex-cloud/yandex"
        }
      }
      required_version = ">= 0.13"
    }

    provider "yandex" {
      cloud_id  = "<идентификатор_облака>"
      folder_id = "<идентификатор_каталога>"
      zone      = "<зона_доступности_по_умолчанию>"
    }
    ```

1. Укажите в файле параметры, необходимые для работы провайдера `kubernetes`:

    1. В блок `required_providers` добавьте:

        ```hcl
        kubernetes = {
          source = "hashicorp/kubernetes"
        }
        ```

    1. В блоке `required_providers` измените значение `required_version` на `">= 0.14.8"`.

    1. В конце файла разместите новый блок:

        ```hcl
        data "yandex_client_config" "client" {}

        provider "kubernetes" {
          host                   = yandex_kubernetes_cluster.k8s-cluster.master[0].external_v4_endpoint
          cluster_ca_certificate = yandex_kubernetes_cluster.k8s-cluster.master[0].cluster_ca_certificate
          token                  = data.yandex_client_config.client.iam_token
        }
        ```

1. Убедитесь, что в результате файл выглядит так:

    ```hcl
    terraform {
      required_providers {
        yandex = {
          source = "yandex-cloud/yandex"
        }
        kubernetes = {
          source = "hashicorp/kubernetes"
        }
      }
      required_version = ">= 0.14.8"
    }

    provider "yandex" {
      cloud_id  = "<идентификатор_облака>"
      folder_id = "<идентификатор_каталога>"
      zone      = "<зона_доступности_по_умолчанию>"
    }

    data "yandex_client_config" "client" {}

    provider "kubernetes" {
      host                   = yandex_kubernetes_cluster.k8s-cluster.master[0].external_v4_endpoint
      cluster_ca_certificate = yandex_kubernetes_cluster.k8s-cluster.master[0].cluster_ca_certificate
      token                  = data.yandex_client_config.client.iam_token
    }
    ```

1. Инициализируйте провайдер `kubernetes`:

    ```bash
    terraform init
    ```

## Создайте ресурсы Kubernetes {#create-standard-resources}

Создайте тестовое приложение и сервис типа `LoadBalancer`:

1. В рабочей директории создайте файл `deployment.tf`, описывающий ресурс `Deployment`:

    ```hcl
    resource "kubernetes_deployment" "demo-app-deployment" {
      metadata {
        name = "hello"
        labels = {
          app = "hello"
          version = "v1"
        }
      }
      spec {
        replicas = 2
        selector {
          match_labels = {
            app = "hello"
          }
        }
        template {
          metadata {
            labels = {
              app = "hello"
              version = "v1"
            }
          }
          spec {
            container {
              name  = "hello-app"
              image = "cr.yandexcloud.kz/crpjd37scfv653nl11i9/hello:1.1"
            }
          }
        }
      }
    }
    ```

1. В рабочей директории создайте файл `service.tf`, описывающий ресурс `Service`:

    ```hcl
    resource "kubernetes_service" "demo-lb-service" {
      metadata {
        name = "hello"
      }
      spec {
        selector = {
          app = kubernetes_deployment.demo-app-deployment.spec.0.template.0.metadata[0].labels.app
        }
        type = "LoadBalancer"
        port {
          port = 80
          target_port = 8080
        }
      }
    }
    ```

1. Создайте ресурсы Kubernetes:

   1. Посмотрите планируемые изменения:
   
      ```bash
      terraform plan
      ```
   
   1. Если изменения устраивают, примените их:
   
      ```bash
      terraform apply
      ```

   После команды `terraform apply` может возникнуть ошибка:

   ```text
   Error: Waiting for rollout to finish: 2 replicas wanted; 0 replicas Ready
   │ 
   │   with kubernetes_deployment.demo-app-deployment,
   │   on deployment.tf line 1, in resource "kubernetes_deployment" "demo-app-deployment":
   │   1: resource "kubernetes_deployment" "demo-app-deployment" {
   │ 
   ```

   Она означает, что ресурсы `Deployment` еще не готовы. Проверьте их готовность с помощью команды `kubectl get deployment`, она вернет результат:

   ```text
   NAME         READY   UP-TO-DATE   AVAILABLE   AGE
   hello        0/2     2            0           12m
   ```

   Когда в столбце `READY` будет указано значение `2/2`, выполните команду `terraform apply` снова.

Вы также можете создавать другие стандартные ресурсы Kubernetes с помощью манифестов Terraform. В качестве основы используйте конфигурацию YAML для нужного ресурса ([пример для пода](https://kubernetes.io/docs/concepts/workloads/pods/#using-pods)). Из конфигурации заимствуйте структуру и параметры и примените разметку Terraform. Например, параметр `containerPort` в YAML замените на параметр `container_port` в Terraform. Полный список Terraform-ресурсов для Kubernetes приведен в [документации провайдера](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs).

О создании [пользовательских ресурсов](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) с помощью Terraform читайте в [документации Terraform](https://developer.hashicorp.com/terraform/tutorials/kubernetes/kubernetes-provider?variants=kubernetes%3Akind#managing-custom-resources).

## Убедитесь, что приложение кластера доступно из интернета {#verify-setup}

1. Посмотрите информацию о созданном балансировщике нагрузки:

     ```bash
     kubectl describe service hello
     ```

     Результат:

     ```bash
      Name:                     hello
      Namespace:                default
      Labels:                   <none>
      Annotations:              <none>
      Selector:                 app=hello
      Type:                     LoadBalancer
      IP Family Policy:         SingleStack
      IP Families:              IPv4
      IP:                       10.96.228.81
      IPs:                      10.96.228.81
      LoadBalancer Ingress:     84.201.148.8
      Port:                     <unset>  80/TCP
      TargetPort:               8080/TCP
      NodePort:                 <unset>  32532/TCP
      Endpoints:                10.112.128.7:8080,10.112.128.8:8080
      Session Affinity:         None
      External Traffic Policy:  Cluster
      Internal Traffic Policy:  Cluster
      Events:
        Type    Reason                Age    From                Message
        ----    ------                ----   ----                -------
        Normal  EnsuringLoadBalancer  5m32s  service-controller  Ensuring load balancer
        Normal  EnsuredLoadBalancer   5m25s  service-controller  Ensured load balancer
     ```

1. Скопируйте IP-адрес из поля `LoadBalancer Ingress`.  

1. Откройте в браузере URL приложения:

    ```http
    http://<скопированный_IP_адрес>
    ```

    Результат:

    ```text
    Hello, world!
    Running in 'hello-5c46b*****-nc**'
    ```

    {% note info %}
    
    Если ресурс недоступен по указанному URL, то [убедитесь](../../managed-kubernetes/operations/connect/security-groups.md), что группы безопасности для кластера Managed Service for Kubernetes и его групп узлов настроены корректно. Если отсутствует какое-либо из правил — [добавьте его](../../vpc/operations/security-group-add-rule.md).
    
    {% endnote %}

## Удалите созданные ресурсы {#clear-out}

1. В терминале перейдите в директорию с планом инфраструктуры.

1. Выполните команду:

   ```bash
   terraform destroy
   ```

   Terraform удалит все ресурсы, созданные в текущей конфигурации.

## Пример подготовки постоянного тома с помощью Terraform {#example}

Подготовьте для кластера Managed Service for Kubernetes [постоянный том](../../managed-kubernetes/concepts/volume.md#persistent-volume). Используйте для этого конфигурационный файл:

{% cut "pv-pvc.tf" %}

```hcl
resource "yandex_compute_disk" "pv_disk" {
  name = "pv-disk"
  zone = "ru-central1-a"
  size = 10
  type = "network-ssd"
}

resource "kubernetes_storage_class" "pv_sc" {
  metadata {
    name = "pv-sc"
  }
  storage_provisioner = "disk-csi-driver.mks.ycloud.io"

  parameters = {
    "csi.storage.k8s.io/fstype" = "ext4"
  }

  reclaim_policy      = "Retain"
  volume_binding_mode = "WaitForFirstConsumer"
}

resource "kubernetes_persistent_volume" "my_pv" {
  metadata {
    name = "my-pv"
  }
  spec {
    capacity = {
      storage = "10Gi"
    }
    access_modes       = ["ReadWriteOnce"]
    storage_class_name = "pv-sc"
    persistent_volume_source {
      csi {
        driver        = "disk-csi-driver.mks.ycloud.io"
        volume_handle = yandex_compute_disk.pv_disk.id
      }
    }
  }
}

resource "kubernetes_persistent_volume_claim" "my_pvc" {
  metadata {
    name = "my-pvc"
  }
  spec {
    access_modes = ["ReadWriteOnce"]
    resources {
      requests = {
        storage = "5Gi"
      }
    }
    storage_class_name = "pv-sc"
    volume_name        = "my-pv"
  }
}
```

{% endcut %}

В файле `pv-pvc.tf` описаны:

* [Диск](../../compute/concepts/disk.md) Compute Cloud, который используется как хранилище для `PersistentVolume`:
  
    * Имя — `pv-disk`.
    * Зона доступности — `ru-central1-a`.
    * Размер диска — 10 ГБ.
    * Тип диска — `network-ssd`.

* Пользовательский [класс хранилища (StorageClass)](../../managed-kubernetes/operations/volumes/manage-storage-class.md):

    * Имя — `pv-sc`.
    * Поставщик хранилища — `disk-csi-driver.mks.ycloud.io`.
    * Тип файловой системы — `ext4`.
    * Политика переиспользования — `Retain`. Объект `PersistentVolume` не будет удален после удаления связанного с ним объекта `PersistentVolumeClaim`.
    * Режим присоединения тома — `WaitForFirstConsumer`. `PersistentVolume` и `PersistentVolumeClaim` будут связаны только тогда, когда под запросит том.

    [Подробнее о параметрах класса хранилища](https://kubernetes.io/docs/concepts/storage/storage-classes/).

* Объект `PersistentVolume`:

    * Имя — `my-pv`.
    * Размер — 10 ГБ.
    * Режим доступа — `ReadWriteOnce`. Читать и записывать данные в этот объект `PersistentVolume` могут только поды, расположенные на одном и том же узле. Поды на других узлах не смогут получить доступ к этому объекту.
    * Класс хранилища — `pv-sc`. Если не указать, будет использоваться класс хранилища по умолчанию.
    * Источник данных — диск `pv-disk`.

    [Подробнее о параметрах PersistentVolume](https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-v1/).

* Объект `PersistentVolumeClaim`:

    * Имя — `my-pvc`.
    * Режим доступа — `ReadWriteOnce`. Читать и записывать данные в этот объект `PersistentVolume` могут только поды, расположенные на одном и том же узле. Поды на других узлах не смогут получить доступ к этому объекту.
    * Запрашиваемый размер хранилища — 5 ГБ.
    * Класс хранилища — `pv-sc`. Если не указать, будет использоваться класс хранилища по умолчанию.
    * Имя тома — объект `PersistentVolume`, с которым будет связан объект `PersistentVolumeClaim`.

  [Подробнее о параметрах PersistentVolumeClaim](https://kubernetes.io/docs/reference/kubernetes-api/config-and-storage-resources/persistent-volume-claim-v1/).  

#### Полезные ссылки {#see-also}

* [Документация Terraform по созданию ресурсов Kubernetes](https://developer.hashicorp.com/terraform/tutorials/kubernetes/kubernetes-provider)
* [Документация провайдера](https://registry.terraform.io/providers/hashicorp/kubernetes/latest/docs)