Skip to content

Использование Object Storage для работы с файлами состояния

После создания ресурсов Terraform создает файл с расширением .tfstate, в котором текущее состояние ресурсов описано в формате JSON. Он называется файлом состояния (англ. state file).

Если вы измените описание ресурсов, а затем выполните команду terraform plan, Terraform перечитает этот файл, сравнит желаемое состояние ресурсов с фактическим и выведет список нужных изменений. При выполнении команды terraform apply ресурсы, у которых желаемое состояние отличается от фактического, будут изменены. Ресурсы, которые фактически существуют в проекте, но отсутствуют в описании, будут удалены.

Чтобы организовать совместную работу, избежать конфликтов при изменении ресурсов и обеспечить интеграцию с CI/CD, файлы состояния рекомендуется помещать в удаленные хранилища. Файлы состояния можно получать из удаленного хранилища и выполнять на их основе операции с ресурсами.

Чтобы настроить хранение файлов состояний в Object Storage и выполнять с их помощью операции с ресурсами:

1. Подготовьте окружение

  1. В веб-консоли выберите нужный проект или создайте новый.

  2. Создайте бакет для хранения файлов состояния Terraform в сервисе Object Storage.

  3. Создайте сервисный аккаунт и назначьте ему роль editor или выше на проект.

  4. Создайте директорию для хранения конфигурационных файлов Terraform. Например, terraform-config:

    bash
    mkdir terraform-config

2. Получите аутентификационные данные

  1. Создайте авторизованный ключ для сервисного аккаунта.
  2. Скачайте и сохраните файл с авторизованным ключом.

3. Настройте провайдер

  1. Создайте файл ~/.terraformrc и укажите в нем параметры для установки провайдера:

    hcl
    provider_installation {
      network_mirror {
        url = "https://storage.mwsapis.ru/mws-terraform/",
        include = ["registry.terraform.io/mws-cloud/*"]
      }
    
      direct {
        exclude = ["registry.terraform.io/mws-cloud/*"]
      }
    }
  2. Создайте файл provider.tf и добавьте в него блок с настройками провайдера:

    hcl
    terraform {
      required_providers {
        mws = {
          source = "mws-cloud/mws"
        }
      }
      required_version = ">= 1.11"
    }
    
    provider "mws" {
      service_account_authorized_key_path = "<путь к файлу с авторизованным ключом>"  
      project = "my-project"     # имя проекта
      zone    = "ru-central1-a"  # зона доступности
    }

4. Настройте бэкенд

  1. Создайте HMAC-ключ для сервисного аккаунта, который будет использоваться для работы с Terraform.

  2. Создайте файл backend.hcl и добавьте в него обе части HMAC-ключа — Access key и Secret key:

    hcl
    access_key = "<Access key из HMAC-ключа>"
    secret_key = "<Secret key из HMAC-ключа>"
  3. Создайте файл backend.tf и добавьте в него блок с настройками бэкенда:

    hcl
    terraform {
      backend "s3" {
        bucket = "<имя бакета для хранения файлов состояния>"
        key    = "<имя файла состояния>"
        region = "ru-central1"
    
        endpoints = {
          s3 = "https://storage.mwsapis.ru"
        }
    
        skip_region_validation      = true
        skip_credentials_validation = true
        skip_metadata_api_check     = true
        skip_requesting_account_id  = true
        use_path_style              = true
    
        use_dualstack_endpoint       = false
        use_fips_endpoint            = false
      }
    }
  4. Инициализируйте Terraform:

    bash
    terraform init -backend-config=backend.hcl

    Эта команда загрузит провайдер и установит соединение с Object Storage, где будут храниться файлы состояния.

5. Подготовьте план инфраструктуры

После инициализации Terraform нужно описать характеристики ресурсов, которые будут созданы с его помощью. В примере показан конфигурационный файл Terraform, на основе которого будут созданы:

  • сеть с именем example-network;
  • подсеть с именем example-subnet и CIDR 192.168.0.0/16;
  • виртуальная машина с именем example-vm, с двумя ядрами vCPU, 4ГБ RAM, диском размером в 10 ГБ и ОС Ubuntu 24.04. Она получит внутренний IP-адрес из подсети example-subnet.

Чтобы создать виртуальную машину:

  1. Добавьте в файл main.tf содержимое из примера ниже.

    Пример конфигурационного файла
    hcl
    resource "mws_vpc_network" "network" {
      network = "example-network"  
      internet_access = true
       mtu             = 1500
    }
    
    resource "mws_vpc_subnet" "subnet" {
      subnet     = "example-subnet"
      network    = mws_vpc_network.network.network
      cidr       = "192.168.0.0/16"
    }
    
    data "mws_compute_image" "image" {
      image   = "mws-ubuntu-2404-lts-v20250529"
      project = "mws-ubuntu"
    }
    
    resource "mws_vpc_address" "vm_primary_network_interface_address" {
      network = mws_vpc_network.network.network
      subnet  = mws_vpc_subnet.subnet.metadata.id
      address = "example-vm-primary-network-interface-address"
    }
    
    resource "mws_vpc_external_address" "vm_external_address" {
      external_address = "example-vm-external-address"
    }
    
    resource "mws_compute_disk" "disk" {
      disk      = "example-disk"
      disk_type = "diskTypes/nbs-pl2"
      iops      = 1000
      size      = "10GB"
      source = {
        image = data.mws_compute_image.image.metadata.id
      }
    }
    
    resource "mws_compute_virtual_machine" "vm" {
      virtual_machine = "example-vm"
      vm_type         = "vmTypes/gen-2-8"
    
      hardware = {
        power                     = "ON"
        graceful_shutdown_timeout = "1m 30s"
      }
    
      os = {
        hostname     = "example"
        local_domain = "vm"
    
        metadata = {
          attributes = {
            user-data = <cкрипт cloud-init>
    
          }
        }
      }
    
      storage = {
        disks = [
          {
            name = "boot"
            boot = true
            disk = {
              ref = mws_compute_disk.disk.metadata.id
            }
          }
        ]
      }
    
      network = {
        network_interfaces = [
          {
            name    = "example-vm-network-interface-primary"
            primary = true
            addresses = [
              {
                address = {
                  ref = mws_vpc_address.vm_primary_network_interface_address.metadata.id
                }
                one_to_one_nat = {
                  external = {
                    address = {
                      ref = mws_vpc_external_address.vm_external_address.metadata.id
                    }
                  }
                }
              }
            ]
          }
        ]
      }
    }
    
    output "network_id" {
      value       = mws_vpc_network.network.network
      description = "Network ID"
    }
    
    output "subnet_id" {
      value       = mws_vpc_subnet.subnet.id
      description = "Subnet ID"
    }
    
    output "internal_ip_id" {
      value       = mws_vpc_address.vm_primary_network_interface_address.id
      description = "Internal IP address ID"
    }
    
    output "external_ip_id" {
      value       = mws_vpc_external_address.vm_external_address.id
      description = "External IP address ID"
    }
  2. Проверьте файл main.tf на наличие синтаксических ошибок:

    bash
      terraform validate

    Если ошибок нет, вы получите следующее сообщение:

    bash
    Success! The configuration is valid.
  3. Выполните команду:

    bash
    terraform plan

    Terraform проверит конфигурационные файлы, сопоставит описание желаемого состояния облачной инфраструктуры с фактическим и укажет, какие операции с ресурсами будут выполнены.

6. Создайте ресурсы

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

    bash
    terraform apply
  2. Подтвердите выполнение операций: введите слово yes и нажмите Enter.

    Во время создания ресурсов Terraform будет выводить краткие сообщения о выполняемых операциях. Проверить, что ресурсы созданы и настроены корректно, можно в веб-консоли.

7. Проверьте сохраненное состояние

  1. В веб-консоли в списке сервисов выберите Object Storage.
  2. Нажмите на имя бакета, который вы создали ранее для хранения файлов состояния Terraform.
  3. Убедитесь, что в бакете появился файл с расширением *.tfstate.

8. Получите состояние из бэкенда

Файлы состояния можно запрашивать из бэкенда и использовать при создании ресурсов. В примере ниже показано, как запросить состояние и создать еще одну виртуальную машину в подсети, созданной на предыдущем шаге.

Чтобы получить состояние и создать еще одну виртуальную машину:

  1. Создайте новую директорию для конфигураций и перейдите в нее:

    bash
    mkdir remote-state
    cd remote-state
  2. Скопируйте в нее файл provider.tf из директории terraform-config, созданной ранее:

    bash
    cp ../terraform-config/provider.tf $(pwd)
  3. Инициализируйте Terraform:

    bash
    terraform init
  4. Создайте файл example.tf и добавьте конфигурацию из примера ниже. На базе этой конфигурации Terraform выполнит следующие действия:

    • получит файл состояния из Object Storage;

    • получит из файла состояния информацию о сети и подсети, где нужно создать виртуальную машину;

    • создаст виртуальную машину с именем example-vm2, с двумя ядрами vCPU, 4ГБ RAM, диском размером в 10 ГБ и ОС Ubuntu 24.04. Она получит внутренний IP-адрес из подсети example-subnet.

      Пример конфигурации
      hcl
      data "terraform_remote_state" "vpc" {
        backend = "s3"
      
        config = {
          bucket                      = "my-terraform-states"
          key                         = "terraform.tfstate"
          region                      = "ru-central1"
          
          endpoints = {
            s3 = "https://storage.mwsapis.ru"
          }
          access_key = "<Access key из HMAC-ключа>"
          secret_key = "<Secret key из HMAC-ключа>"
          skip_region_validation      = true
          skip_credentials_validation = true
          skip_metadata_api_check     = true
          skip_requesting_account_id  = true
          
          use_path_style            = true
        }
      }
      
      data "mws_compute_image" "image" {
        image   = "mws-ubuntu-2204-lts-v20250529"
        project = "mws-ubuntu"
      }
      
      resource "mws_vpc_address" "vm2_primary_network_interface_address" {
        # Получаем значения из remote state
        network = data.terraform_remote_state.vpc.outputs.network_id
        subnet  = data.terraform_remote_state.vpc.outputs.subnet_id
        address = "example-vm2-primary-network-interface-address"
      }
      
      resource "mws_vpc_external_address" "vm2_external_address" {
        external_address = "example-vm2-external-address"
      }
      
      resource "mws_compute_disk" "disk2" {
        disk      = "example-disk2"
        disk_type = "diskTypes/nbs-pl2"
        iops      = 1000
        size      = "10GB"
        source = {
          image = data.mws_compute_image.image.metadata.id
        }
      }
      
      resource "mws_compute_virtual_machine" "vm2" {
        virtual_machine = "example-vm2"
        vm_type         = "vmTypes/gen-2-8"
      
        hardware = {
          power                     = "ON"
          graceful_shutdown_timeout = "1m 30s"
        }
      
        os = {
          hostname     = "example2"
          local_domain = "vm"
      
          metadata = {
            attributes = {
              user-data = "<скрипт cloud-init>"
            }
          }
        }
      
        storage = {
          disks = [
            {
              name = "boot"
              boot = true
              disk = {
                ref = mws_compute_disk.disk2.metadata.id
              }
            }
          ]
        }
      
        network = {
          network_interfaces = [
            {
              name    = "example-vm2-network-interface-primary"
              primary = true
              addresses = [
                {
                  address = {
                    ref = mws_vpc_address.vm2_primary_network_interface_address.metadata.id
                  }
                  one_to_one_nat = {
                    external = {
                      address = {
                        ref = mws_vpc_external_address.vm2_external_address.metadata.id
                      }
                    }
                  }
                }
              ]
            }
          ]
        }
      }
  5. Проверьте файл example.tf на наличие синтаксических ошибок:

    bash
    terraform validate

    Если ошибок нет, вы получите следующее сообщение:

    bash
    Success! The configuration is valid.
  6. Выполните команду:

    bash
    terraform plan

    Terraform проверит конфигурационные файлы, сопоставит описание желаемого состояния облачной инфраструктуры с фактическим и укажет, какие операции с ресурсами будут выполнены.

  7. Создайте вторую виртуальную машину:

    bash
    terraform apply
  8. Убедитесь, что в созданной ранее подсети появилась виртуальная машина с именем example-vm2.

Удалите созданные ресурсы

Ресурсы, созданные с помощью Terraform, могут тарифицироваться. Не забудьте удалить ресурсы, если вы создали их в тестовых целях, и они вам больше не нужны.

Чтобы удалить ресурсы:

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

    bash
    terraform destroy
  2. Подтвердите удаление: введите слово yes и нажмите Enter.