[Yandex Cloud documentation](../../../index.md) > [Yandex Compute Cloud](../../index.md) > [Tutorials](../index.md) > [Working with an instance group with autoscaling](index.md) > Terraform

# Working with an instance group with autoscaling using Terraform


To create an infrastructure for an [instance group with autoscaling](index.md) using Terraform:

1. [Get your cloud ready](#before-begin).
1. [Create your infrastructure](#deploy).
1. [Test your instance group and network load balancer](#check-service).

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

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

1. If you do not have the Yandex Cloud CLI yet, [install it](../../../cli/quickstart.md#install).

1. To make sure the scripts from the step-by-step guide run correctly, download and install [jq](https://stedolan.github.io/jq/download/).

1. To check autoscaling, install [wrk](https://github.com/wg/wrk).

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

The infrastructure cost includes:
* Fee for continuously running [VMs](../../concepts/vm.md) (see [Compute Cloud pricing](../../pricing.md)).
* Fee for [network load balancers](../../../network-load-balancer/concepts/index.md) and traffic balancing (see [Network Load Balancer pricing](../../../network-load-balancer/pricing.md)).

## Create your 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).

To create an autoscaling instance group 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-with-autoscale.git
        ```

     1. Navigate to the repository directory. Make sure it now contains the following files:
        * `vm-autoscale.tf`: New infrastructure configuration.
        * `declaration.yaml`: Description of the Docker container with a web server that will simulate the VM load.
        * `config.tpl`: VM user description.
        * `vm-autoscale.auto.tfvars`: User data.

   - Manually {#manual}

     1. Create a directory for configuration files.
     1. In the directory, create:
        1. `vm-autoscale.tf` configuration file:

           {% cut "vm-autoscale.tf" %}

           ```hcl
           # Declaring variables for confidential parameters
           
           variable "folder_id" {
             type = string
           }
           
           variable "vm_user" {
             type = string
           }
           
           variable "ssh_key" {
             type      = string
             sensitive = true
           }
           
           # Configuring a provider
           
           terraform {
             required_providers {
               yandex = {
                 source = "yandex-cloud/yandex"
                 version = ">= 0.47.0"
               }
             }
           }
           
           provider "yandex" {
             zone = "ru-central1-a"
           }
           
           # Creating a service account and assigning roles to it
           
           resource "yandex_iam_service_account" "for-autoscale" {
             name = "for-autoscale"
           }
           
           resource "yandex_resourcemanager_folder_iam_member" "vm-autoscale-sa-role-compute" {
             folder_id = var.folder_id
             role      = "editor"
             member    = "serviceAccount:${yandex_iam_service_account.for-autoscale.id}"
           }
           
           # Creating a cloud network and subnets
           
           resource "yandex_vpc_network" "vm-autoscale-network" {
             name = "vm-autoscale-network"
           }
           
           resource "yandex_vpc_subnet" "vm-autoscale-subnet-a" {
             name           = "vm-autoscale-subnet-a"
             zone           = "ru-central1-a"
             v4_cidr_blocks = ["192.168.1.0/24"]
             network_id     = yandex_vpc_network.vm-autoscale-network.id
           }
           
           resource "yandex_vpc_subnet" "vm-autoscale-subnet-b" {
             name           = "vm-autoscale-subnet-b"
             zone           = "ru-central1-b"
             v4_cidr_blocks = ["192.168.2.0/24"]
             network_id     = yandex_vpc_network.vm-autoscale-network.id
           }
           
           # Creating a security group
           
           resource "yandex_vpc_security_group" "sg-1" {
             name                = "sg-autoscale"
             network_id          = yandex_vpc_network.vm-autoscale-network.id
             egress {
               protocol          = "ANY"
               description       = "any"
               v4_cidr_blocks    = ["0.0.0.0/0"]
             }
             ingress {
               protocol          = "TCP"
               description       = "ext-http"
               v4_cidr_blocks    = ["0.0.0.0/0"]
               port              = 80
             }
             ingress {
               protocol          = "TCP"
               description       = "healthchecks"
               predefined_target = "loadbalancer_healthchecks"
               port              = 80
             }
           }
           
           # Specifying a prebuilt VM image
           
           data "yandex_compute_image" "autoscale-image" {
             family = "container-optimized-image"
           }
           
           # Creating an instance group
           
           resource "yandex_compute_instance_group" "autoscale-group" {
             name                = "autoscale-vm-ig"
             folder_id           = var.folder_id
             service_account_id  = yandex_iam_service_account.for-autoscale.id
             instance_template {
           
               platform_id = "standard-v3"
               resources {
                 memory = 2
                 cores  = 2
               }
             
               boot_disk {
                 mode = "READ_WRITE"
                 initialize_params {
                   image_id = data.yandex_compute_image.autoscale-image.id
                   size     = 30
                 }
               }
           
               network_interface {
                 network_id = yandex_vpc_network.vm-autoscale-network.id
                 subnet_ids = [
                   yandex_vpc_subnet.vm-autoscale-subnet-a.id,
                   yandex_vpc_subnet.vm-autoscale-subnet-b.id
                 ]
                 security_group_ids = [ yandex_vpc_security_group.sg-1.id ]
                 nat                = true
               }
           
               metadata = {
                 user-data = templatefile("config.tpl", {
                   VM_USER = var.vm_user
                   SSH_KEY = var.ssh_key
                 })
                 docker-container-declaration = file("declaration.yaml")
               }
             }
           
             scale_policy {
               auto_scale {
                 initial_size           = 2
                 measurement_duration   = 60
                 cpu_utilization_target = 40
                 min_zone_size          = 1
                 max_size               = 6
                 warmup_duration        = 120
               }
             }
           
             allocation_policy {
               zones = [
                 "ru-central1-a",
                 "ru-central1-b"
               ]
             }
           
             deploy_policy {
               max_unavailable = 1
               max_expansion   = 0
             }
           
             load_balancer {
               target_group_name        = "auto-group-tg"
               target_group_description = "load balancer target group"
             }
           }
           
           # Creating a network load balancer
           
           resource "yandex_lb_network_load_balancer" "balancer" {
             name = "group-balancer"
           
             listener {
               name        = "http"
               port        = 80
               target_port = 80
             }
           
             attached_target_group {
               target_group_id = yandex_compute_instance_group.autoscale-group.load_balancer[0].target_group_id
               healthcheck {
                 name = "tcp"
                 tcp_options {
                   port = 80
                 }
               }
             }
           }
           ```

           {% endcut %}

        1. `declaration.yaml` file with a description of the Docker container with a web server that will simulate the VM load:

           {% cut "declaration.yaml" %}

           ```yaml
           spec:
           containers:
           - image: cr.yandex/yc/demo/web-app:v1
             securityContext:
               privileged: false
             tty: false
             stdin: false
           ```

           {% endcut %}

        1. `config.tpl` VM user description file:

           {% cut "config.tpl" %}

           ```yaml
           users:
             - name: "${VM_USER}"
               groups: sudo
               shell: /bin/bash
               sudo: 'ALL=(ALL) NOPASSWD:ALL'
               ssh_authorized_keys:
                 - "${SSH_KEY}"
           ```

           {% endcut %}

        1. `vm-autoscale.auto.tfvars` user data file:

           {% cut "vm-autoscale.auto.tfvars" %}

           ```hcl
           folder_id = "<folder_ID>"
           vm_user   = "<VM_username>"
           ssh_key   = "<public_SSH_key_contents>"
           ```

           {% endcut %}

   {% endlist %}

   Learn more about the properties of Terraform resources in the relevant Terraform articles:

   * [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).
   * [Security group](../../../vpc/concepts/security-groups.md): [yandex_vpc_security_group](../../../terraform/resources/vpc_security_group.md).
   * [Instance group](../../concepts/instance-groups/index.md): [yandex_compute_instance_group](../../../terraform/resources/compute_instance_group.md).
   * [Network load balancer](../../../network-load-balancer/concepts/index.md): [yandex_lb_network_load_balancer](../../../terraform/resources/lb_network_load_balancer.md).

1. In the `vm-autoscale.auto.tfvars` file, set the following user-defined properties:
   * `folder_id`: [Folder ID](../../../resource-manager/operations/folder/get-id.md).
   * `vm_user`: VM user name.
   * `ssh_key`: Public SSH key file contents required to authenticate the user on the VM. For more information, see [Creating an SSH key pair](../../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 and network load balancer](#check-service).

## Test your instance group and network load balancer {#check-service}

1. Create a load on an instance.

   To do this, save the script named `request.sh` to the home directory. The script will send a request to one of the VMs through the `group-balancer` load balancer. The request will utilize 100% CPU for 30 seconds.

   ```bash
   EXTERNAL_IP=$(yc load-balancer network-load-balancer get group-balancer --format=json | jq -r .listeners[0].address)

   curl "http://$EXTERNAL_IP/burn-cpu?time=30000&load=100"
   ```

1. Run the script:

   {% list tabs group=instructions %}

   - CLI {#cli}

     ```bash
     sh request.sh
     ```

     Result:

     ```text
     projects/b0g12ga82bcv********/zones/ru-central1-b
     ```

   {% endlist %}

1. View the instance utilization:

   {% list tabs group=instructions %}

   - Management console {#console}

     1. In the [management console](https://console.yandex.cloud), select the folder where you created the instance group.
     1. Navigate to **Compute Cloud**.
     1. In the left-hand panel, click ![image](../../../_assets/console-icons/layers-3-diagonal.svg) **Instance groups**.
     1. Select `auto-group`.
     1. Navigate to the **Monitoring** tab.

        The load balancer sent the request to an instance in the group. In the availability zone this instance belongs to, the average CPU utilization is higher than in other zones (see the **Average CPU utilization in zone** chart).

   {% endlist %}

### Autoscaling test {#check-highload}

To test autoscaling for your instance group, increase the CPU utilization of each instance. In the `specification.yaml` file, the `scale_policy.auto_scale.cpu_utilization_rule.utilization_target` parameter is set to `40`: it means that the target utilization level is 40% CPU. If you exceed the target utilization, the number of VMs in the group will increase.
1. Increase the utilization for the instance group.

   To do this, save the script named `load.sh` to the home directory. The script sends requests to the instance group through 12 threads for 10 minutes. Each VM instance utilizes 20% CPU on each core that processes the request. The instance group utilization is 240% CPU at any given time. To be sure that requests are evenly distributed across the instances in the group, the script executes multiple parallel requests utilizing 20% CPU rather than one request utilizing 240% CPU.

   ```bash
   EXTERNAL_IP=$(yc load-balancer network-load-balancer get group-balancer --format=json | jq -r .listeners[0].address)

   wrk -H "Connection: close" -t12 -c12 -d10m "http://$EXTERNAL_IP/burn-cpu?time=5000&load=20"
   ```

1. Run the script:

   {% list tabs group=instructions %}

   - CLI {#cli}

     ```bash
     sh load.sh
     ```

     Result:

     ```text
     Running 10m test @ http://130.193.56.111/burn-cpu?time=5000&load=20
       12 threads and 12 connections
       Thread Stats   Avg      Stdev     Max   +/- Stdev
     ...
     Requests/sec: 15.04
     Transfer/sec: 3.20KB
     ```

   {% endlist %}

1. View the utilization levels:

   {% list tabs group=instructions %}

   - Management console {#console}

     1. In the [management console](https://console.yandex.cloud), select the folder where you created the `auto-group` instance group.
     1. Navigate to **Compute Cloud**.
     1. In the left-hand panel, click ![image](../../../_assets/console-icons/layers-3-diagonal.svg) **Instance groups**.
     1. Select `auto-group`.
     1. Navigate to the **Monitoring** tab.
        The chart **Number of instances in zone** shows how the number of instances changed in each availability zone. The chart **Average CPU utilization in zone** shows average CPU utilization in each availability zone.
     1. Navigate to the **Logs** tab.
        The page displays messages relating to the instance group autoscaling.

     The total utilization of 240% CPU was evenly distributed between two instances in two availability zones and exceeded the target utilization of 40% CPU. [Yandex Compute Cloud](../../index.md) created one instance more in each availability zone to result in four instances in the group. When the script stopped utilizing the CPU, Compute Cloud automatically decreased the number of instances in the group to two.

   {% endlist %}

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

To stop paying for the resources you created:

1. Open the `vm-autoscale.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}

* [Running an autoscaling instance group using the management console, CLI, and API](console.md)