Uploading Terraform states to Object Storage

These instructions describe the steps to upload a Terraform state to Yandex Object Storage.

A Terraform state describes the current deployed infrastructure and is stored in files with the .tfstate extension. The state file is created after the infrastructure is deployed and can be immediately uploaded to Object Storage. The uploaded state file is updated as the infrastructure you created changes.

In this example, the saved state lets other users get the ID of one of the created subnets to connect a new VM to it.

To configure Terraform state storage in Object Storage and use it to create new resources:

  1. Before you start.
  2. Required paid resources.
  3. Install Terraform.
  4. Create a Terraform configuration file.
  5. Configure a provider.
  6. Create a service account and static access key.
  7. Create a bucket.
  8. Configure the backend.
  9. Deploy the configuration.
  10. Check the saved state.
  11. Retrieve the backend state.

If you no longer need the created resources, delete them.

Before you start

To deploy an infrastructure using Terraform, sign in to Yandex.Cloud and create a billing account:

  1. Go to the management console. Then log in to Yandex.Cloud or sign up if don't already have an account.
  2. On the billing page, make sure you linked a billing account, and it has the ACTIVE or TRIAL_ACTIVE status. If you don't have a billing account, create one.

Learn more about clouds and folders.

Warning

You're charged for all resources created using Terraform. Please, make sure to check the configurations you are creating now.

In this scenario, you create three VMs with public IP addresses, a virtual network, and two subnets.

The cost of supporting this infrastructure includes:

Install Terraform

Install Terraform:

Download the Terraform distribution and install it according to the instructions.

Install Terraform using the Homebrew package manager:

$ brew install terraform

Create a Terraform configuration file

  1. Create a directory with any name, for example, yandex-cloud-terraform. It will store the Terraform configuration files.
  2. Create a configuration file with the .tf extension in this directory, for example, example.tf.

Configure a provider

  1. At the beginning of the configuration file, specify the provider settings.

    provider "yandex" {
      token = "<OAuth or static key of service account>"
      folder_id = "<folder ID>"
      zone      = "ru-central1-a"
    }
    
    • provider: The provider name.
    • token: OAuth token to access Yandex.Cloud.
    • folder_id: ID of the folder where Terraform will create cloud resources.
    • zone: The availability zone where all cloud resources will be created by default.
  2. Execute the command terraform init in the folder with the configuration file. This command initializes the providers specified in the configuration files and allows you to work with the provider resources and data sources.

Create a service account and static access key

  1. Create a service account with the editor role for the folder specified in the provider settings.
  2. Get a static access key. Save the key ID and secret key: you need them in the next steps.

Create a bucket

Create a bucket with any name, for example, terraform-object-storage-tutorial. It stores the Terraform state file.

Configure the backend

To save a Terraform state in Object Storage, specify the provider and backend settings:

provider "yandex" {
  token = "<OAuth or static key of service account>"
  folder_id = "<folder ID>"
  zone      = "ru-central1-a"
}

terraform {
  backend "s3" {
    endpoint   = "storage.yandexcloud.net"
    bucket   = "<bucket name>"
    region     = "us-east-1"
    key = "<path to the state file in the bucket>/<state file name>.tfstate"
    access_key = "<static key identifier>"
    secret_key = "<secret key>"

    skip_region_validation      = true
    skip_credentials_validation = true
  }
}

To read more about the state storage backend, see the Terraform website.

Deploy the configuration

In this example, two VMs are created: terraform1 and terraform2. They are connected to the subnet subnet-1 in the availability zone ru-central1-a. The subnet belongs to the network-1 cloud network.

The VMs have a different number of cores and amount of RAM: 1 core and 2 GB of RAM for terraform1 and 2 cores and 4 GB of RAM for terraform2. The machines automatically gets public IP addresses and private IP addresses from the range 192.168.10.0/24 in subnet-1. The Ubuntu OS will be installed on the VMs and the public part of the key used to access the VMs via SSH will be stored on them.

  1. Save the following configuration to example.tf:

    provider "yandex" {
    token = "<OAuth or static key of service account>"
    folder_id = "<folder ID>"
    zone      = "ru-central1-a"
    }
    
    terraform {
      backend "s3" {
        endpoint   = "storage.yandexcloud.net"
        bucket   = "<bucket name>"
        region     = "us-east-1"
        key = "<path to the state file in the bucket>/<state file name>.tfstate"
        access_key = "<static key identifier>"
        secret_key = "<secret key>"
    
        skip_region_validation      = true
        skip_credentials_validation = true
      }
    }
    
    resource "yandex_compute_instance" "vm-1" {
      name = "terraform1"
    
      resources {
        cores  = 1
        memory = 2
      }
    
      boot_disk {
        initialize_params {
          image_id = "fd87va5cc00gaq2f5qfb"
        }
      }
    
      network_interface {
        subnet_id = "${yandex_vpc_subnet.subnet-1.id}"
        nat       = true
      }
    
      metadata = {
        ssh-keys = "ubuntu:${file("~/.ssh/id_rsa.pub")}"
      }
    }
    
    resource "yandex_compute_instance" "vm-2" {
      name = "terraform2"
    
      resources {
        cores  = 2
        memory = 4
      }
    
      boot_disk {
        initialize_params {
          image_id = "fd87va5cc00gaq2f5qfb"
        }
      }
    
      network_interface {
        subnet_id = "${yandex_vpc_subnet.subnet-1.id}"
        nat       = true
      }
    
      metadata = {
        ssh-keys = "ubuntu:${file("~/.ssh/id_rsa.pub")}"
      }
    }
    
    resource "yandex_vpc_network" "network-1" {
      name = "network1"
    }
    
    resource "yandex_vpc_subnet" "subnet-1" {
      name           = "subnet1"
      zone           = "ru-central1-a"
      network_id     = "${yandex_vpc_network.network-1.id}"
      v4_cidr_blocks = ["192.168.10.0/24"]
    }
    
    output "internal_ip_address_vm_1" {
      value = "${yandex_compute_instance.vm-1.network_interface.0.ip_address}"
    }
    
    output "internal_ip_address_vm_2" {
      value = "${yandex_compute_instance.vm-2.network_interface.0.ip_address}"
    }
    
    
    output "external_ip_address_vm_1" {
      value = "${yandex_compute_instance.vm-1.network_interface.0.nat_ip_address}"
    }
    
    output "external_ip_address_vm_2" {
      value = "${yandex_compute_instance.vm-2.network_interface.0.nat_ip_address}"
    }
    
    output "subnet-1" {
      value = "${yandex_vpc_subnet.subnet-1.id}"
    }
    
  2. Check the configuration using the command terraform plan.

  3. Expand the configuration using the command terraform apply.

Check the saved state

Make sure that the state file is uploaded to Object Storage:

  1. Open the management console and select the folder with the bucket created.
  2. Select Object Storage.
  3. From the bucket list, select the bucket you saved the Terraform state to.
  4. Make sure that the state file is in the bucket.

Get the state from the backend

You can request the Terraform state saved in Object Storage from another configuration to expand the infrastructure you created.

Create another configuration and use the saved state to create another VM in one of the existing subnets:

  1. Create the remote-state directory.

  2. Go to the created directory and create the configuration file remote-state.tf:

    provider "yandex" {
      token = "<OAuth or static key of service account>"
      cloud_id  = "cloud-id"
      folder_id = "folder-id"
      zone      = "ru-central1-a"
    }
    
    data "terraform_remote_state" "vpc" {
      backend = "s3"
      config = {
        endpoint   = "storage.yandexcloud.net"
        bucket   = "<bucket name>"
        region     = "us-east-1"
        key = "<path to the state file in the bucket>/<state file name>.tfstate"
        access_key = "<static key identifier>"
        secret_key = "<secret key>"
    
        skip_region_validation      = true
        skip_credentials_validation = true
      }
    }
    
    resource "yandex_compute_instance" "vm-3" {
      name = "terraform3"
    
      resources {
        cores  = 1
        memory = 2
      }
    
      boot_disk {
        initialize_params {
          image_id = "fd87va5cc00gaq2f5qfb"
        }
      }
    
      network_interface {
        subnet_id = data.terraform_remote_state.vpc.outputs.subnet-1
        nat       = true
      }
    
      metadata = {
        ssh-keys = "ubuntu:${file("~/.ssh/id_rsa.pub")}"
      }
    }
    
  3. Run the command terraform init.

  4. Run the command terraform plan. The terminal displays the plan for creating the VM.

  5. Run the command terraform apply.

  6. Go to the management console and make sure you can see the virtual machine vm-3 in the Compute Cloud section.

Delete the created resources

To destroy the resources you created, run the command terraform destroy: start with the second configuration, and then proceed to the first.