[Yandex Cloud documentation](../../../index.md) > [Yandex Compute Cloud](../../index.md) > [Tutorials](../index.md) > [Scheduled instance group scaling](index.md) > Terraform

# Scheduled instance group scaling with Terraform

To set up [scheduled instance group scaling](index.md) with Terraform:

1. [Get your cloud ready](#before-begin).
1. [Create your infrastructure](#deploy).
1. [Test your instance group scaling](#test-scale).

If you no longer need the resources you created, [delete them](#clear-out).

## Get your cloud ready {#before-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).

### Required paid resources {#paid-resources}

The infrastructure support costs include:
* Fee for [disks](../../concepts/disk.md) and continuously running [VMs](../../concepts/vm.md) (see [Compute Cloud pricing](../../pricing.md)).
* [Function calls](../../../functions/concepts/function.md), computing resources allocated to executing the function, and outgoing traffic (see [Cloud Functions pricing](../../../functions/pricing.md)).

## Create an infrastructure {#deploy}

With [Terraform](https://www.terraform.io/), you can quickly create a cloud infrastructure in Yandex Cloud and manage it using configuration files. These files store the infrastructure description written in HashiCorp Configuration Language (HCL). If you change the configuration files, Terraform automatically detects which part of your configuration is already deployed, and what should be added or removed.

Terraform is distributed under the [Business Source License](https://github.com/hashicorp/terraform/blob/main/LICENSE). The [Yandex Cloud provider for Terraform](https://github.com/yandex-cloud/terraform-provider-yandex) is distributed under the [MPL-2.0](https://www.mozilla.org/en-US/MPL/2.0/) license.

For more information about the provider resources, see the relevant documentation on the [Terraform](https://www.terraform.io/docs/providers/yandex/index.html) website or [its mirror](../../../terraform/index.md).

Create an infrastructure with Terraform:

1. [Install Terraform](../../../tutorials/infrastructure-management/terraform-quickstart.md#install-terraform) and specify the Yandex Cloud provider installation source (see [Configure your provider](../../../tutorials/infrastructure-management/terraform-quickstart.md#configure-provider), step 1).
1. Prepare your infrastructure description files:

   {% list tabs group=infrastructure_description %}

   - Ready-made configuration {#ready}

     1. Clone the repository with configuration files.

        ```bash
        git clone https://github.com/yandex-cloud-examples/yc-vm-group-scheduled-scaling
        ```

     1. Navigate to the repository directory. Make sure it contains the following files:
        * `vm-scale-scheduled.tf`: New infrastructure configuration.
        * `vm-scale-scheduled.auto.tfvars`: User data file.
        * `vm-scale-scheduled-function.zip`: Cloud Functions function code archive.


   - Manually {#manual}

     1. Create a folder.
     1. In this folder, create:
        * `vm-scale-scheduled.tf`: New infrastructure configuration file:

          {% cut "vm-scale-scheduled.tf" %}

          ```hcl
          # Declaring variables for confidential parameters
          
          variable "folder_id" {
            type = string
          }
          
          variable "username" {
            type = string
          }
          
          variable "ssh_key_path" {
            type = string
          }
          
          # Configuring a provider
          
          terraform {
            required_providers {
              yandex = {
                source  = "yandex-cloud/yandex"
                version = ">= 0.47.0"
              }
            }
          }
          
          provider "yandex" {
            folder_id = var.folder_id
          }
          
          # Creating a service account and assigning roles to it
          
          resource "yandex_iam_service_account" "vm-scale-scheduled-sa" {
            name      = "vm-scale-scheduled-sa"
          }
          
          resource "yandex_resourcemanager_folder_iam_member" "vm-scale-scheduled-sa-role-compute" {
            folder_id = var.folder_id
            role      = "compute.editor"
            member    = "serviceAccount:${yandex_iam_service_account.vm-scale-scheduled-sa.id}"
          }
          
          resource "yandex_resourcemanager_folder_iam_member" "vm-scale-scheduled-sa-role-iam" {
            folder_id = var.folder_id
            role      = "iam.serviceAccounts.user"
            member    = "serviceAccount:${yandex_iam_service_account.vm-scale-scheduled-sa.id}"
          }
          
          resource "yandex_resourcemanager_folder_iam_member" "vm-scale-scheduled-sa-role-functions" {
            folder_id = var.folder_id
            role      = "functions.functionInvoker"
            member    = "serviceAccount:${yandex_iam_service_account.vm-scale-scheduled-sa.id}"
          }
          
          # Creating a cloud network and subnets
          
          resource "yandex_vpc_network" "vm-scale-scheduled-network" {
            name = "vm-scale-scheduled-network"
          }
          
          resource "yandex_vpc_subnet" "vm-scale-scheduled-subnet-a" {
            name           = "vm-scale-scheduled-subnet-a"
            zone           = "ru-central1-a"
            v4_cidr_blocks = ["192.168.1.0/24"]
            network_id     = yandex_vpc_network.vm-scale-scheduled-network.id
          }
          
          resource "yandex_vpc_subnet" "vm-scale-scheduled-subnet-b" {
            name           = "vm-scale-scheduled-subnet-b"
            zone           = "ru-central1-b"
            v4_cidr_blocks = ["192.168.2.0/24"]
            network_id     = yandex_vpc_network.vm-scale-scheduled-network.id
          }
          
          # Creating an image
          
          resource "yandex_compute_image" "vm-scale-scheduled-image" {
            source_family = "ubuntu-2004-lts"
          }
          
          # Creating an instance group
          
          resource "yandex_compute_instance_group" "vm-scale-scheduled-ig" {
            name               = "vm-scale-scheduled-ig"
            service_account_id = yandex_iam_service_account.vm-scale-scheduled-sa.id
          
            allocation_policy {
              zones = [
                "ru-central1-a",
                "ru-central1-b"
              ]
            }
          
            instance_template {
              boot_disk {
                mode = "READ_WRITE"
                initialize_params {
                  image_id = yandex_compute_image.vm-scale-scheduled-image.id
                  size     = 15
                }
              }
          
              platform_id = "standard-v3"
              resources {
                cores         = 2
                core_fraction = 20
                memory        = 2
              }
          
              network_interface {
                network_id = yandex_vpc_network.vm-scale-scheduled-network.id
                subnet_ids = [
                  yandex_vpc_subnet.vm-scale-scheduled-subnet-a.id,
                  yandex_vpc_subnet.vm-scale-scheduled-subnet-b.id
                ]
              }
          
              metadata = {
                user-data = "#cloud-config\nusers:\n  - name: ${var.username}\n    groups: sudo\n    shell: /bin/bash\n    sudo: 'ALL=(ALL) NOPASSWD:ALL'\n    ssh_authorized_keys:\n      - ${file("${var.ssh_key_path}")}"
              }
            }
          
            scale_policy {
              fixed_scale {
                size = 2
              }
            }
          
            deploy_policy {
              max_unavailable = 2
              max_creating    = 2
              max_expansion   = 2
              max_deleting    = 2
            }
          
            depends_on = [
              yandex_resourcemanager_folder_iam_member.vm-scale-scheduled-sa-role-compute,
              yandex_resourcemanager_folder_iam_member.vm-scale-scheduled-sa-role-iam
            ]
          }
          
          # Creating a function
          
          resource "yandex_function" "vm-scale-scheduled-function" {
            name               = "vm-scale-scheduled-function"
            runtime            = "bash"
          
            user_hash          = "function-v1"
            entrypoint         = "handler.sh"
            content {
              zip_filename = "vm-scale-scheduled-function.zip"
            }
          
            execution_timeout  = "60"
            memory             = "128"
            service_account_id = yandex_iam_service_account.vm-scale-scheduled-sa.id
          
            environment = {
              IG_NAME      = yandex_compute_instance_group.vm-scale-scheduled-ig.name
              IG_BASE_SIZE = "2"
              FOLDER_ID    = var.folder_id
            }
          
            depends_on = [
              yandex_resourcemanager_folder_iam_member.vm-scale-scheduled-sa-role-functions
            ]
          }
          
          # Creating a trigger
          
          resource "yandex_function_trigger" "vm-scale-scheduled-trigger" {
            name = "vm-scale-scheduled-trigger"
            timer {
              cron_expression = "*/2 * * * ? *"
            }
            function {
              id                 = yandex_function.vm-scale-scheduled-function.id
              tag                = "$latest"
              service_account_id = yandex_iam_service_account.vm-scale-scheduled-sa.id
            }
          
            depends_on = [
              yandex_resourcemanager_folder_iam_member.vm-scale-scheduled-sa-role-functions
            ]
          }
          ```

          {% endcut %}

        * `vm-scale-scheduled.auto.tfvars`: User data file:

          {% cut "vm-scale-scheduled.auto.tfvars" %}

          ```hcl
          folder_id    = "<folder_ID>"
          username     = "<VM_username>"
          ssh_key_path = "<path_to_public_SSH_key>"
          ```

          {% endcut %}

        * `handler.sh` file with the Cloud Functions function code:

          {% cut "handler.sh" %}

          {% note warning %}
          
          If you are creating a file in Windows, make sure that newline characters are in `\n` Unix format rather than `\r\n`. You can replace line breaks in a text editor, such as [Notepad++](https://notepad-plus-plus.org/), or with such tools as [dos2unix](https://waterlan.home.xs4all.nl/dos2unix.html) or [Tofrodos](https://www.thefreecountry.com/tofrodos/).
          
          {% endnote %}

          ```bash
          # Get ID and current size of the instance group
          IG_SPEC=$(yc compute instance-group get --name $IG_NAME --folder-id $FOLDER_ID --format json)
          IG_ID=$(jq -r ".id" <<< $IG_SPEC)
          IG_SIZE=$(jq -r ".scale_policy.fixed_scale.size" <<< $IG_SPEC)
          
          # Calculate new size for the instance group
          if [ $IG_SIZE = $IG_BASE_SIZE ]; then
              IG_SIZE="$(($IG_BASE_SIZE + 1))"
          else
              IG_SIZE=$IG_BASE_SIZE
          fi
          
          # Update the instance group
          yc compute instance-group update --id $IG_ID --scale-policy-fixed-scale-size $IG_SIZE
          ```

          {% endcut %}

     1. In the same folder, create the `vm-scale-scheduled-function.zip` archive with `handler.sh`.

   {% endlist %}

   For more information about the properties of Terraform resources, see the relevant Terraform guides:

   * [Service account](../../../iam/concepts/users/service-accounts.md): [yandex_iam_service_account](../../../terraform/resources/iam_service_account.md).
   * [Network](../../../vpc/concepts/network.md#network): [yandex_vpc_network](../../../terraform/resources/vpc_network.md).
   * [Subnets](../../../vpc/concepts/network.md#subnet): [yandex_vpc_subnet](../../../terraform/resources/vpc_subnet.md).
   * [VM image](../../concepts/image.md): [yandex_compute_image](../../../terraform/resources/compute_image.md).
   * [VM group](../../concepts/instance-groups/index.md): [yandex_compute_instance_group](../../../terraform/resources/compute_instance_group.md).
   * [Function](../../../functions/concepts/function.md): [yandex_function](../../../terraform/resources/function.md).
   * [Trigger](../../../functions/concepts/trigger/index.md): [yandex_function_trigger](../../../terraform/resources/function_trigger.md).

1. In the `vm-scale-scheduled.auto.tfvars` file, set the following user-defined properties:

   * `folder_id`: Resource [folder ID](../../../resource-manager/operations/folder/get-id.md).
   * `username`: VM user name.
   * `ssh_key_path`: Path to the public SSH key required to authenticate the user on the VM. You can create a key pair by following [this guide](../../operations/vm-connect/ssh.md#creating-ssh-keys).

1. Create the resources:

   1. In the terminal, navigate to the configuration file directory.
   1. Make sure the configuration is correct using this command:
   
      ```bash
      terraform validate
      ```
   
      If the configuration is valid, you will get this message:
   
      ```bash
      Success! The configuration is valid.
      ```
   
   1. Run this command:
   
      ```bash
      terraform plan
      ```
   
      You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
   1. Apply the configuration changes:
   
      ```bash
      terraform apply
      ```
   
   1. Type `yes` and press **Enter** to confirm the changes.

Once you created the infrastructure, [test your instance group scaling](#test-scale).

## Test instance group scaling {#test-scale}

{% list tabs group=instructions %}

- Management console {#console}

  1. In the [management console](https://console.yandex.cloud), select `example-folder`.
  1. Navigate to **Compute Cloud**.
  1. In the left-hand panel, select ![image](../../../_assets/console-icons/layers-3-diagonal.svg) **Instance groups**.
  1. Select `vm-scale-scheduled-ig`.
  1. Under **Virtual machines**, make sure the number of instances changes every two minutes: increases from 2 to 3, then decreases from 3 to 2, etc. You can also check if the instance group has been updated by opening the ![image](../../../_assets/console-icons/list-check.svg) **Operations** tab.

- CLI {#cli}

  Run the following command several times:

  ```bash
  yc compute instance-group get vm-scale-scheduled-ig \
    --folder-name example-folder
  ```

  Result:

  ```yaml
  id: cl1l0ljqbmkp********
  folder_id: b1g9hv2loamq********
  created_at: "2022-03-28T13:24:20.693Z"
  ...
  managed_instances_state:
    target_size: "2"
    running_actual_count: "2"
  ...
  ```

  The value of the `target_size` field for the group should change from `2` to `3` and back.

- API {#api}

  Get information about the `vm-scale-scheduled-ig` instance group multiple times using the [get](../../instancegroup/api-ref/InstanceGroup/get.md) REST API method for the [InstanceGroup](../../instancegroup/api-ref/InstanceGroup/index.md) resource or the [InstanceGroupService/Get](../../instancegroup/api-ref/grpc/InstanceGroup/get.md) gRPC API call. The value of the `target_size` field for the group should change from `2` to `3` and back.

{% endlist %}

## How to delete the resources you created {#clear-out}

To stop paying for the resources you created:

1. Open the `vm-scale-scheduled.tf` configuration file and delete your infrastructure description from it.
1. Apply the changes:

    1. In the terminal, navigate to the configuration file directory.
    1. Make sure the configuration is correct using this command:
    
       ```bash
       terraform validate
       ```
    
       If the configuration is valid, you will get this message:
    
       ```bash
       Success! The configuration is valid.
       ```
    
    1. Run this command:
    
       ```bash
       terraform plan
       ```
    
       You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
    1. Apply the configuration changes:
    
       ```bash
       terraform apply
       ```
    
    1. Type `yes` and press **Enter** to confirm the changes.

#### See also {#see-also}

* [Instance group scheduled scaling with the management console, CLI, and API](console.md)