Перейти к содержимому

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

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

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

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

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

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

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

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

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

    bash
    mkdir terraform-config
  1. Создайте авторизованный ключ для сервисного аккаунта.
  2. Скачайте и сохраните файл с авторизованным ключом.
  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" # зона доступности
    }
  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, где будут храниться файлы состояния.

После инициализации 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 проверит конфигурационные файлы, сопоставит описание желаемого состояния облачной инфраструктуры с фактическим и укажет, какие операции с ресурсами будут выполнены.

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

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

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

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

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

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

  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.