Spec-Zone.ru › OpenTofu 1.11

Настройка провайдеров

Провайдеры позволяют OpenTofu взаимодействовать с облачными провайдерами, SaaS-провайдерами и другими API.

Некоторые провайдеры требуют настройки URL конечных точек, облачных регионов или других параметров, прежде чем OpenTofu сможет их использовать. На этой странице описана настройка параметров провайдеров.

Кроме того, во всех конфигурациях OpenTofu необходимо объявить требуемые провайдеры, чтобы OpenTofu мог их установить и использовать. На странице Требования к провайдерам описано, как объявлять провайдеры, чтобы OpenTofu мог их установить.

Настройка провайдеров​

Настройки провайдеров задаются в корневом модуле конфигурации OpenTofu. (Дочерние модули получают настройки провайдеров из корневого модуля; дополнительную информацию см. в разделах Метааргумент providers и Разработка модулей: провайдеры внутри модулей.)

Настройка провайдера задаётся блоком provider:

Блок кода
provider "google" {
  project = "acme-app"
  region  = "us-central1"
}

Имя, указанное в заголовке блока ("google" в этом примере), — это локальное имя настраиваемого провайдера. У каждого модуля есть собственное пространство имён локальных имён провайдеров, определяемых в блоке required_providers.

Тело блока (между { и }) содержит аргументы конфигурации провайдера. Большинство аргументов в этом разделе определяются самим провайдером; в этом примере и project, и region относятся именно к провайдеру google.

В значениях этих аргументов конфигурации можно использовать выражения, но ссылаться можно только на значения, известные до применения конфигурации. Это значит, что можно безопасно ссылаться на входные переменные, но не на атрибуты, экспортируемые ресурсами, за исключением случаев, когда они заданы непосредственно в конфигурации или в документации указано, что они доступны на этапе планирования.

Для настройки провайдера можно использовать эфемерные значения. Они могут поступать из разных источников, например переменных, выходных значений или эфемерных ресурсов. Пример настройки провайдера приведён в документации по эфемерным значениям.

В документации провайдера должны быть перечислены ожидаемые аргументы конфигурации. Для провайдеров, распространяемых через публичный реестр OpenTofu, документация для конкретной версии доступна на странице каждого провайдера по ссылке «Документация» в заголовке страницы.

Некоторые провайдеры могут использовать переменные окружения оболочки (или другие альтернативные источники, например профили экземпляров виртуальных машин) в качестве значений некоторых аргументов. Если такая возможность доступна, мы рекомендуем использовать её, чтобы не хранить учётные данные в коде OpenTofu, отслеживаемом системой контроля версий.

Кроме того, существуют два «метааргумента», определяемых самим OpenTofu и доступных во всех блоках provider:

  • alias — для определения дополнительных конфигураций одного и того же провайдера
  • for_each — для определения нескольких динамических экземпляров конфигурации провайдера
  • version — больше не рекомендуется (вместо него используйте требования к провайдерам)

В отличие от многих других объектов языка OpenTofu, блок provider можно опустить, если в противном случае он был бы пустым. OpenTofu предполагает пустую конфигурацию по умолчанию для любого провайдера, который явно не настроен.

alias: несколько конфигураций провайдера​

При необходимости можно определить несколько конфигураций одного и того же провайдера и выбирать нужную для каждого ресурса или модуля. Обычно это требуется для поддержки нескольких регионов облачной платформы; другие примеры — работа с несколькими хостами Docker, несколькими хостами Consul и т. д.

Чтобы создать несколько конфигураций одного провайдера, добавьте несколько блоков provider с одним и тем же именем провайдера. Для каждой дополнительной конфигурации, отличной от конфигурации по умолчанию, используйте метааргумент alias, чтобы указать дополнительную часть имени. Конфигурация провайдера с псевдонимом называется альтернативной конфигурацией провайдера. Например:

Блок кода
# The default provider configuration; resources that begin with `aws_` will use
# it as the default, and it can be referenced as `aws`.
provider "aws" {
  region = "us-east-1"
}

# Alternate provider configuration for west coast region; resources can
# reference this as `aws.west`.
provider "aws" {
  alias  = "west"
  region = "us-west-2"
}

Чтобы объявить псевдоним конфигурации внутри модуля и получить альтернативную конфигурацию провайдера от родительского модуля, добавьте аргумент configuration_aliases в запись required_providers этого провайдера. В следующем примере в содержащем модуле объявлены имена конфигураций провайдера mycloud и mycloud.alternate:

Блок кода
terraform {
  required_providers {
    mycloud = {
      source  = "mycorp/mycloud"
      version = "~> 1.0"
      configuration_aliases = [ mycloud.alternate ]
    }
  }
}

Конфигурации провайдера по умолчанию​

Блок provider без аргумента alias является конфигурацией провайдера по умолчанию. Ресурсы, в которых не задан метааргумент provider, будут использовать конфигурацию провайдера по умолчанию, соответствующую первому слову в имени типа ресурса. (Например, ресурс aws_instance использует конфигурацию провайдера aws по умолчанию, если не указано иное.)

Если блока provider, определяющего конфигурацию провайдера по умолчанию, нет, OpenTofu автоматически предполагает пустую конфигурацию провайдера по умолчанию. Если схема конфигурации провайдера содержит обязательные аргументы, пустая конфигурация будет недопустимой, поэтому требуется явно задать блок provider.

Конфигурация провайдера по умолчанию не требуется и не предполагается, если все ресурсы в модуле явно выбирают другую конфигурацию провайдера с помощью метааргумента provider в своих блоках resource или data.

for_each: несколько экземпляров конфигурации провайдера​

Иногда требуется динамически объявить несколько экземпляров провайдера на основе других данных, доступных в конфигурации, например входной переменной.

Например, конфигурация, объявляющая базовую инфраструктуру для каждого используемого организацией региона AWS, может принимать входную переменную со списком этих регионов. Однако провайдер hashicorp/aws поддерживает только один регион для каждого экземпляра провайдера, поэтому объявить инфраструктуру для динамического набора регионов, используя только статические конфигурации провайдера, невозможно.

В любую альтернативную конфигурацию провайдера (объявленную с помощью аргумента alias) можно дополнительно включить аргумент for_each, чтобы указать, что конфигурацию следует создавать в нескольких экземплярах на основе значения коллекции:

Блок кода
variable "aws_regions" {
  type = map(object({
    vpc_cidr_block = string
  }))
}

provider "aws" {
  alias    = "by_region"
  for_each = var.aws_regions

  region = each.key
}

Без аргумента for_each блок provider всегда объявляет только один экземпляр соответствующего провайдера. Конфигурация провайдера с аргументом for_each вместо этого объявляет ноль или более экземпляров провайдера, каждый из которых соответствует одному элементу коллекции for_each и настраивается по одним и тем же правилам на основе общего блока конфигурации.

У каждого экземпляра есть ключ экземпляра, однозначно идентифицирующий его среди всех экземпляров, принадлежащих одной конфигурации провайдера. Значение, присвоенное for_each, должно иметь тип map, тип object или быть набором строк. Для типов map и object ключ элемента или имя атрибута становится ключом экземпляра. Для набора строк ключом экземпляра становится само значение элемента.

Пользователь этой конфигурации должен передать входной переменной aws_regions значение типа map, где ключ каждого элемента — допустимое имя региона AWS, а значение — объект с уникальными параметрами этого региона. Например, в файле terraform.tfvars:

Блок кода
aws_regions = {
  eu-central-2 = {
    vpc_cidr_block = "10.1.0.0/16"
  }
  ap-northeast-1 = {
    vpc_cidr_block = "10.2.0.0/16"
  }
}

Аргумент for_each можно использовать только вместе с alias, поскольку конфигурация каждого провайдера по умолчанию всегда должна иметь ровно один экземпляр, чтобы OpenTofu мог автоматически выбрать его при необходимости.

Выбор альтернативных конфигураций провайдера​

Каждый ресурс в конфигурации OpenTofu должен быть связан с одной конфигурацией провайдера.

По умолчанию каждый ресурс связывается с конфигурацией провайдера по умолчанию, автоматически выбранной на основе первого сегмента имени типа ресурса. Например, блок resource "azurerm_subnet" "example" будет связан с конфигурацией по умолчанию провайдера с локальным именем «azurerm» в модуле, где объявлен ресурс.

Чтобы использовать альтернативную конфигурацию провайдера, в блок resource или data необходимо включить метааргумент provider со ссылкой на экземпляр провайдера, содержащей псевдоним выбранной конфигурации:

Блок кода
resource "aws_instance" "foo" {
  provider = aws.west

  # ...
}

Если в выбранной конфигурации используется аргумент for_each для объявления нескольких экземпляров, аргумент provider также должен содержать выражение с ключом экземпляра, чтобы выбрать по одному экземпляру конфигурации провайдера для каждого экземпляра ресурса, как описано в следующем разделе.

Если аргумент provider не указан, это равносильно выбору конфигурации по умолчанию для провайдера, локальное имя которого совпадает с префиксом имени типа ресурса:

Блок кода
resource "aws_instance" "foo" {
  provider = aws

  # ...
}

Ссылки на экземпляры провайдера​

Для явных ссылок на конфигурации провайдера OpenTofu использует специальный синтаксис ссылок на конфигурации провайдеров вида <PROVIDER NAME>.<ALIAS>. Например, aws.west ссылается на блок provider "aws" с alias = "west".

В этом синтаксисе используются символы, похожие на символы обычной ссылки-выражения, однако ссылки на провайдеры не являются обычными выражениями и могут использоваться только в некоторых специальных местах:

  • Метааргумент provider блока resource или data
  • Метааргумент providers блока module

Для конфигурации провайдера без for_each один и тот же синтаксис ссылается и на конфигурацию, и на её единственный экземпляр провайдера, поэтому в большинстве случаев ссылку на конфигурацию провайдера можно считать эквивалентной ссылке на экземпляр провайдера.

Однако если конфигурация провайдера объявляет ноль или более динамических экземпляров с помощью for_each, синтаксис ссылки дополняется компонентом, который указывает выбираемый экземпляр с помощью ключей экземпляров конфигурации. Например, aws.by_region["eu-west-1"] ссылается на экземпляр aws.by_region с ключом экземпляра "eu-west-1".

В выражении в квадратных скобках используется обычный синтаксис выражений; как правило, ключ экземпляра выбирается динамически для каждого экземпляра ресурса, а не задаётся жёстко. Например:

Блок кода
variable "aws_regions" {
  type = map(object({
    vpc_cidr_block = string
  }))
}

provider "aws" {
  alias    = "by_region"
  for_each = var.aws_regions

  region = each.key
}

resource "aws_vpc" "private" {
  # This expression filters var.aws_regions to include only
  # the elements whose value is not null. Refer to the
  # warning in the text below for more information.
  for_each = {
    for region, config in var.aws_regions : region => config
    if config != null
  }
  provider = aws.by_region[each.key]

  cidr_block = each.value.vpc_cidr_block
}

В блоке resource "aws_vpc" "private" используется for_each, чтобы объявить по одному экземпляру ресурса для каждого ненулевого элемента var.aws_regions. Затем аргумент provider использует each.key для выбора отдельного экземпляра aws.by_region для каждого экземпляра ресурса, так что каждый из них будет объявлен в отдельном регионе.

Также можно выбрать динамический экземпляр конфигурации провайдера для всех ресурсов дочернего модуля в блоке module. Дополнительную информацию см. в разделе Экземпляры модулей с разными экземплярами провайдера.

Хотя выражение ключа экземпляра в квадратных скобках является динамическим, ссылка на конфигурацию провайдера статична. Благодаря этому OpenTofu может определить зависимости между блоками resource и provider до вычисления выражений. Затем эти зависимости позволяют OpenTofu разрешать динамические выражения в правильном порядке. Это означает, что все экземпляры конкретного ресурса должны быть связаны с экземплярами одного и того же блока конфигурации провайдера, но при этом каждый из них может быть связан с отдельным экземпляром провайдера.

Предупреждение

Выражение for_each для ресурса должно отличаться от выражения for_each для связанной с ним конфигурации провайдера.

OpenTofu использует экземпляр провайдера для планирования и применения всех действий, связанных с экземпляром ресурса, включая уничтожение экземпляра ресурса, удалённого из конфигурации.

Поэтому связанный с любым экземпляром ресурса экземпляр провайдера должен оставаться в конфигурации как минимум ещё на один цикл планирования и применения после удаления экземпляра ресурса. В противном случае OpenTofu не сможет запланировать уничтожение экземпляра ресурса.

В приведённом выше примере нулевой элемент в var.aws_regions показывает, что экземпляр провайдера необходим, но с ним не должны быть связаны экземпляры ресурсов.

Таким образом, если задать для элемента определённого региона значение null, OpenTofu предложит уничтожить экземпляр aws_vpc.private для этого региона, сохранив при этом экземпляр провайдера, необходимый для планирования и применения этого действия. После этого можно удалить элемент целиком на следующем цикле, когда все связанные с ним экземпляры ресурсов будут уничтожены.

Удаление экземпляра провайдера​

Одно из основных ограничений функции экземпляров провайдера состоит в том, что удаление экземпляра провайдера требует дополнительных циклов планирования и применения. В следующем примере показана эта проблема и способ её избежать.

Как объяснялось выше, ресурс всегда должен использовать выражение for_each, являющееся подмножеством значения for_each конфигурации провайдера. В следующей конфигурации для провайдера и ресурса используется одно и то же значение for_each:

Блок кода
variable "aws_active_regions" {
  type    = set(string)
  default = ["us-east-1", "sa-east-1"]
}

provider "aws" {
  alias    = "by_region"
  for_each = var.aws_active_regions
  region   = each.key
}

resource "aws_cloudwatch_log_group" "lambda_cloudfront" {
  name     = "/aws/lambda/${each.key}.lambda"
  provider = aws.by_region[each.key]
  for_each = var.aws_active_regions
}

Эта конфигурация вызовет следующее предупреждение:

Блок кода
╷
│ Warning: Provider configuration for_each matches resource
│
│   on main.tf line 24, in resource "aws_cloudwatch_log_group" "lambda_cloudfront":
│   24:   for_each = var.aws_regions
│
│ This provider configuration uses the same for_each expression as a
│ resource, which means that subsequent removal of elements from this
│ collection would cause a planning error.
│
│ OpenTofu relies on a provider instance to destroy resource instances
│ that are associated with it, and so the provider instance must
│ outlive all of its resource instances by at least one plan/apply
│ round. For removal of instances to succeed in future you must
│ structure the configuration so that the provider block's for_each
│ expression can produce a superset of the instances of the resources
│ associated with the provider configuration. Refer to the OpenTofu
│ documentation for specific suggestions.
│
│ To destroy this object before removing the provider configuration,
│ consider first performing a targeted destroy:
│     tofu apply -destroy -target=aws_cloudwatch_log_group.lambda_cloudfront
╵

Такой подход чреват ошибками, поскольку перед удалением самого экземпляра провайдера необходимо выполнить apply -destroy -target для всех связанных с ним ресурсов. Если попытаться удалить экземпляр провайдера, удалив ключ из aws_active_regions до уничтожения ресурсов, OpenTofu не позволит это сделать:

Блок кода
╷
│ Error: Provider instance not present
│
│ To work with aws_cloudwatch_log_group.lambda_cloudfront["sa-east-1"]
│ its original provider instance at
│ provider["registry.opentofu.org/hashicorp/aws"].by_region["sa-east-1"]
│ is required, but it has been removed. This occurs when an element is
│ removed from the provider configuration's for_each collection while
│ objects created by that the associated provider instance still exist
│ in the state. Re-add the for_each element to destroy
│ aws_cloudwatch_log_group.lambda_cloudfront["sa-east-1"], after which
│ you can remove the provider configuration again.
│
│ This is commonly caused by using the same for_each collection both
│ for a resource (or its containing module) and its associated provider
│ configuration. To successfully remove an instance of a resource it
│ must be possible to remove the corresponding element from the
│ resource's for_each collection while retaining the corresponding
│ element in the provider's for_each collection.
╵

Альтернативный подход — использовать другое подмножество для выражения for_each ресурса:

Блок кода
variable "aws_active_regions" {
  type = set(string)
  default = ["us-east-1", "sa-east-1"]
}

variable "aws_disabled_regions" {
  description = "A list of regions that should be disabled and all resources removed."
  type        = set(string)
  default     = []
}

// Superset of the provider configuration
provider "aws" {
  alias    = "by_region"
  for_each = var.aws_active_regions
  region   = each.key
}

// Resource using a subset of the provider's configuration
resource "aws_cloudwatch_log_group" "lambda_cloudfront" {
  name     = "/aws/lambda/${each.key}.lambda"
  provider = aws.by_region[each.key]
  for_each = setsubtract(var.aws_active_regions, var.aws_disabled_regions)
}

Если необходимо удалить экземпляр провайдера (например, для определённого региона AWS), добавьте этот регион в aws_disabled_regions:

Блок кода
variable "aws_disabled_regions" {
  description = "A list of regions that should be disabled and all resources removed."
  type        = set(string)
  default     = ["us-east-1"]
}

При таком подходе для отключения экземпляра провайдера и удаления всех связанных ресурсов достаточно выполнить tofu plan и tofu apply.

Передача конфигураций провайдера между модулями​

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

Дополнительную информацию см. в разделе Метааргумент providers в блоках module.

version (устарел)​

Метааргумент version задаёт ограничение версии провайдера и работает так же, как аргумент version в блоке required_providers. Ограничение версии в конфигурации провайдера используется только в том случае, если в required_providers для этого провайдера ограничение не задано.

Всегда задавайте ограничения версий провайдеров в блоке required_providers.

Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.11/language/providers/configuration/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API