Рубрики
Uncategorized

Terraform AWS — динамические подсети

Обновление — 17-окт-окт-2019 ChangeLog: Terraform выпустил новую функцию с именем CIDRSUBNET, эта функция CR … Tagged с AWS, Terraform, DevOps, Turalial.

Обновление17-окт-окт 2019 Changelog : Terraform выпустил новую функцию имени Cidrsubnets Эта функция создает список CIDR-подсетей. Эта функция отличная, и я рекомендую использовать ее. Несмотря на то, что эта функция сокращает некоторые части этого урока, вы все равно должны прочитать его, если вы хотите узнать, как использовать функции в Terraform.

  1. Создание наборов подсети динамически
  2. Выучить передовые концепции в террафоре
    • Функция переменной карты и поиска
    • Для петли и условного для петли
    • Функция индекса в контуре для
  1. Вы знакомы с подсетью (A.B.C.D/XX) — отличный онлайн-инструмент для расчета подсетей — cidr.xyz
  2. Вы используете Terraporm V0.12 +
  3. У вас есть предыдущий опыт:
  4. Вы знаете, что такое для петли
  5. Я буду использовать модуль Terraform-AWS-модули/VPC/AWS для VPC. Этот модуль требует списков подсетей (частных, база данных, общественных), что именно то, что мы собираемся создавать

Харкодирующие подсети на окружающую среду могут быть значительными накладными расходами. Делая это, вы можете в конечном итоге написать много строк с жесткозедированными сетевыми префиксами. Более того, он снимает гибкость, которую должен предложить инфраструктуру как код (IAC).

Set cidr_ab за окружающую среду

CIDR_AB к спасению! Установите начало VPC CIDR в качестве переменной карты и сопоставьте каждое значение CIDR_AB в соответствующую среду. Если вы не используете все четыре, удалите его из сопоставления.

Узор подсети (префикс): А.Б .CD/хх, так что это охватило А.Б Часть всех подсетей на окружающую среду. Например:

variable "cidr_ab" {
    type = map
    default = {
        development     = "172.22"
        qa              = "172.24"
        staging         = "172.26"
        production      = "172.28"
    }
}

Получить CIDR_AB на окружающую среду

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

Вот синтаксис Функция поиска : Просмотр (карта, ключ, по умолчанию)

Чтобы создать локальный список Private_Subnets С соответствующим CIDR_AB на окружающую среду используйте следующее:

Напоминание : Для объединения выражения и текста: «$ {Expression} Мой текст»

locals {
    private_subnets = [
        "${lookup(var.cidr_ab, var.environment)}.1.0/24",
        "${lookup(var.cidr_ab, var.environment)}.2.0/24",
        "${lookup(var.cidr_ab, var.environment)}.3.0/24"
    ]
}

Имейте в виду, что нам нужно сделать это для базы данных и общественных подсетей Assell.

Выпуск № 1: Полное решение

Предполагая, что мы хотим создать следующие подсети: частную, базу данных и публику. Вот как наш variables.tf и vpc.tf Файлы должны выглядеть как:

variables.tf

variable "cidr_ab" {
    type = map
    default = {
        development     = "172.22"
        qa              = "172.24"
        staging         = "172.26"
        production      = "172.28"
    }
}

locals {
    private_subnets         = [
        "${lookup(var.cidr_ab, var.environment)}.1.0/24",
        "${lookup(var.cidr_ab, var.environment)}.2.0/24",
        "${lookup(var.cidr_ab, var.environment)}.3.0/24"
    ]

    database_subnets        = [
        "${lookup(var.cidr_ab, var.environment)}.11.0/24",
        "${lookup(var.cidr_ab, var.environment)}.12.0/24",
        "${lookup(var.cidr_ab, var.environment)}.13.0/24"
    ]

    public_subnets          = [
        "${lookup(var.cidr_ab, var.environment)}.64.0/24",
        "${lookup(var.cidr_ab, var.environment)}.65.0/24",
        "${lookup(var.cidr_ab, var.environment)}.66.0/24"
    ]
}

variable "environment" {
    type = string
    description = "Options: development, qa, staging, production"
}

vpc.tf

module "vpc" {
    source = "terraform-aws-modules/vpc/aws"
    version = "~>2.0"
    name                 = "my-vpc"
    cidr                 = "${lookup(var.cidr_ab, var.environment)}.0.0/16"
    private_subnets      = local.private_subnets
    database_subnets     = local.database_subnets
    public_subnets       = local.public_subnets

    azs                  = ["us-west-2a", "us-west-2b", "us-west-2c"]

    # omitted arguments for brevity

}

В номере # 1 мы решили подсети на окружающую среду, но зоны наличия (AZS) были жесткозедированы.

Можно подумать; «Давайте просто создадим переменную карты для региона, а затем используйте имя региона, а затем« A »,« B »,« C ». Например:

variable "region" {
    type = map(string)
    default = {
        "development" = "us-west-2"
        "qa"          = "us-east-2"
        "staging"     = "us-east-1"
        "production"  = "ca-central-1"
    }
}

module "vpc" {

    # omitted arguments for brevity

    azs = [
        "${lookup(var.region, var.environment)}a",
        "${lookup(var.region, var.environment)}b",
        "${lookup(var.region, var.environment)}c",
    ]
}

Если все регионы, которые вы используете, имеют одинаковое количество зон доступности — тогда вышеуказанное решение идеально. К сожалению, это не правда, когда дело доходит до CA-Central-1 (Canada Central), которая имеет только две зоны доступности. Другой пример будет US-East-1 (Вирджиния), которая имеет шесть зон доступности.

Примечание : Используйте AWS Глобальная инфраструктура Чтобы узнать количество зон доступности в регионе. И Регионы и зоны доступности Чтобы выяснить код региона (например, ЕС-Запад-1)

Данные aws_availability_zones.

Мы можем получить зоны доступности региона, которое в настоящее время происходит, используя Данные «Доступность_ZONES» Отказ

Вот как мы это делаем:

data "aws_availability_zones" "available" {
    state = "available"
}

Некоторые объяснения относительно кода выше:

  1. данные — Получите существующие данные/ресурсы, доступные на вашем аккаунте
  2. aws_availability_zones — Получает список зон доступности в текущем регионе
  3. Доступно — имя для этих данных, важно выбрать имя, которое отражает значение данных
  4. Государство — фильтрует зоны доступности, которые в настоящее время испытывают отходы

Давайте сохраним данные в локальном значении. Вам может быть интересно: «Почему мы используем локальные значения? Мы также сделали это с подсетью, почему о, почему? »

Правило большого пальца — если есть какие-либо шансы, что вы собираетесь манипулировать переменной/значением, используйте локальное значение. Этот трюк обеспечивает гранулярность для управления local.var_name Отказ Лучше всего управлять переменными за кулисами, не касаясь кода инфраструктуры (VPC.TF, RDS.TF, S3.TF файлов). Худший сценарий — мы использовали местное значение, даже если мы не манипулировали.

Сохранение зон доступности имена Список в локальном значении:

locals {
    availability_zones = data.aws_availability_zones.available.names
}

variables.tf

variable "cidr_ab" {
    type = map
    default = {
        development     = "172.22"
        qa              = "172.24"
        staging         = "172.26"
        production      = "172.28"
    }
}

locals {
    private_subnets         = [
        "${lookup(var.cidr_ab, var.environment)}.1.0/24",
        "${lookup(var.cidr_ab, var.environment)}.2.0/24",
        "${lookup(var.cidr_ab, var.environment)}.3.0/24"
    ]

    database_subnets        = [
        "${lookup(var.cidr_ab, var.environment)}.11.0/24",
        "${lookup(var.cidr_ab, var.environment)}.12.0/24",
        "${lookup(var.cidr_ab, var.environment)}.13.0/24"
    ]

    public_subnets          = [
        "${lookup(var.cidr_ab, var.environment)}.64.0/24",
        "${lookup(var.cidr_ab, var.environment)}.65.0/24",
        "${lookup(var.cidr_ab, var.environment)}.66.0/24"
    ]
}

data "aws_availability_zones" "available" {
    state = "available"
}

locals {
    availability_zones = data.aws_availability_zones.available.names
}

variable "environment" {
    type = string
    description = "Options: development, qa, staging, production"
}

vpc.tf

module "vpc" {
   source = "terraform-aws-modules/vpc/aws"
    version = "~>2.0"
    name                 = "my-vpc"
    cidr                 = "${lookup(var.cidr_ab, var.environment)}.0.0/16"
    private_subnets      = local.private_subnets
    database_subnets     = local.database_subnets
    public_subnets       = local.public_subnets

    azs                  = local.availability_zones

    # omitted arguments for brevity

}

Это часть, где я жадный, и я хочу заполнить CIDR_C. Согласно количеству зон доступности. До сих пор мы покрывали А.Б .c.d/xx, теперь мы охватим эту часть A.B. c .D/XX.

Например (псевдокод):

# define cidr_c per subnet
cidr_c_private_subnets =  1
cidr_c_database_subnets = 11
cidr_c_public_subnets = 64

number_of_azs = 2

# dynamically populate lists of subnets
private_subnets  = ["a.b.1.d/xx", "a.b.2.d/xx"]
database_subnets = ["a.b.11.d/xx", "a.b.12.d/xx"]
public_subnets   = ["a.b.64.d/xx", "a.b.65.d/xx"]

для петли

Динамически заполняющие звуки, как петля, а в террафоре мы получили для петли Отказ

Терраформ для цикла напоминает мне о Понимание списка Python , что означает — создать новый список с A для цикла.

Синтаксис оператора LOOP: [Для элемента в списке: do_something_on (item)]

Псевдокод петли, который нам нужен:

for availability_zone in local.availability_zones:
  "${lookup(var.cidr_ab, var.environment)}.${local.cidr_c_private_subnets + index_of_availability_zone}.0/24"

Некоторые объяснения относительно кода выше:

  1. Доступность_Zone — Я выбрал имя итератора, это также может быть аризона или любое другое имя
  2. index_of Доступность_Zone.
    • Первый индекс списка равен нулю (0)
    • Предполагая $ {lookup (var.cidr_ab, var.environment) равна одному (1) для Private_Subnets
    • Добавление текущего индекса зоны доступности в $ {lookup (var.cidr_ab, var.environment) , результат в:

      • 1 + 0
      • 1 + 1
      • 1 + 2

Получить индекс зоны доступности

Функция индекса в помощь!

Синтаксис функции индекса: Индекс (list_to_search_in, value_to_search_for)

Список, в котором мы ищем local.wailability_zones и значение, которое мы ищем, это итератор петли, Доступность_Zone в нашем случае.

Замена index_of_availability_zone . с Индекс (local.wailability_zones, AZ) результат в:

locals {
    private_subnets = [
        for az in local.availability_zones:
          "${lookup(var.cidr_ab, var.environment)}.${local.cidr_c_private_subnets + index(local.availability_zones, az)}.0/24"
    ]
}

Имя итератора в каждом петле — аризона Я выбрал более короткое имя, чем Доступность_Zone сделать его более читаемым. Так как мы используем локальные значения, нам нужно только изменить variables.tf Файл, не нужно касаться vpc.tf файл

variables.tf

variable "cidr_ab" {
    type = map
    default = {
        development     = "172.22"
        qa              = "172.24"
        staging         = "172.26"
        production      = "172.28"
    }
}

locals {
    cidr_c_private_subnets  = 1
    cidr_c_database_subnets = 11
    cidr_c_public_subnets   = 64
}


data "aws_availability_zones" "available" {
    state = "available"
}

locals {
    availability_zones = data.aws_availability_zones.available.names
}

variable "environment" {
    type = string
    description = "Options: development, qa, staging, production"
}

locals {
    private_subnets = [
        for az in local.availability_zones : 
            "${lookup(var.cidr_ab, var.environment)}.${local.cidr_c_private_subnets + index(local.availability_zones, az)}.0/24"
        ]
    database_subnets = [
        for az in local.availability_zones : 
            "${lookup(var.cidr_ab, var.environment)}.${local.cidr_c_database_subnets + index(local.availability_zones, az)}.0/24"
        ]
    public_subnets = [
        for az in local.availability_zones : 
            "${lookup(var.cidr_ab, var.environment)}.${local.cidr_c_public_subnets + index(local.availability_zones, az)}.0/24"
        ]
}

В решении № 3 мы заполнили подсети в соответствии с количеством зон доступности, что отлично, но это может привести к нежелательному поведению при использовании модуля Terraform-AWS-модули/VPC/AWS Отказ

Если вы хотите иметь набор подсетей на зону доступности, не заботясь о том, сколько подсетей создаются в регионе, вы можете остановиться здесь. Будет легче объяснить с примером: CA-Central-1 (Canada Central) — 2 зоны доступности, следовательно, 6 подсети US-WEST-2 (Орегон) — 4 зоны доступности, следовательно, 12 подсеть

Если вы хотите, чтобы количество подсетей было похоже на всех средах (и регионах) — продолжать прочитать. Например: Предположим, мы должны использовать CA-Central-1 (Canada Central), и из-за этого мы вынуждены использовать только две зоны доступности в каждом регионе. CA-Central-1 (Canada Central) — 2 зоны доступности, следовательно, 6 подсети US-WEST-2 (Орегон) — 4 зоны доступности, принудительный максимум 6 подсети (2 на тип подсети) Всего у нас будет шесть подсетей в нашем VPC (не включая «по умолчанию», который поставляется с VPC).

Правило большого пальца — нам нужно самое низкое общее количество зон доступности, которые доступны во всех регионах, которые мы намерены использовать.

Максимальное количество подсетей

Теперь мы инициализируем еще три переменных, subnet_max на подсеть.

variables.tf

locals {
    cidr_c_private_subnets  = 1
    cidr_c_database_subnets = 11
    cidr_c_public_subnets   = 64

    max_private_subnets     = 2
    max_database_subnets    = 2
    max_public_subnets      = 2
}

Условный для петли

К счастью, для петли есть встроенный ключевое слово Если , который до сих пор напоминает мне об понимании списка Python:)

Синтаксис для петли с условием: [Для элемента в списке: do_something_on (элемент), если выражение]

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

И, конечно, нам нужно только изменить variables.tf файл.

variables.tf

variable "cidr_ab" {
    type = map
    default = {
        development     = "172.22"
        qa              = "172.24"
        staging         = "172.26"
        production      = "172.28"
    }
}

locals {
    cidr_c_private_subnets  = 1
    cidr_c_database_subnets = 11
    cidr_c_public_subnets   = 64

    max_private_subnets     = 2
    max_database_subnets    = 2
    max_public_subnets      = 2
}

data "aws_availability_zones" "available" {
    state = "available"
}

locals {
    availability_zones = data.aws_availability_zones.available.names
}

variable "environment" {
    type = string
    description = "Options: development, qa, staging, production"
}

locals {
    private_subnets = [
        for az in local.availability_zones : 
            "${lookup(var.cidr_ab, var.environment)}.${local.cidr_c_private_subnets + index(local.availability_zones, az)}.0/24"
            if index(local.availability_zones, az) < local.max_private_subnets
        ]
    database_subnets = [
        for az in local.availability_zones : 
            "${lookup(var.cidr_ab, var.environment)}.${local.cidr_c_database_subnets + index(local.availability_zones, az)}.0/24"
            if index(local.availability_zones, az) < local.max_database_subnets
        ]
    public_subnets = [
        for az in local.availability_zones : 
            "${lookup(var.cidr_ab, var.environment)}.${local.cidr_c_public_subnets + index(local.availability_zones, az)}.0/24"
            if index(local.availability_zones, az) < local.max_public_subnets
        ]
}
  1. Некоторые архитекторы решения могут предпочесть жесткокодирующие префиксы подсети в vpc.tf Файл, который в большинстве случаев будет работать нормально. Тот факт, что я имел только изменить Переменные .tf. Файл каждый раз бесценен
  2. Логика за порядком переменных в variables.tf файл —

    • Переменные, которые должны быть изменены, такие как:
      • Регион на окружающую среду (карта)
      • local cidr_c и max_subnets для каждого типа подсети
    • Статические переменные/данные, такие как:
      • Данные «aws_availability_zones» «Доступны»
      • local.wailability_zones.
      • local.subnet_list для каждого типа подсети
  3. Я обнаружил, что используя локальные значения вместо переменных — хороший подход, и он обеспечивает гибкость, которую мне нужно при разработке инфраструктуры
    • Единственный случай, когда нам нужны переменные, — это когда мы хотим подсказать значения, например: var.environment.
    • Всегда используйте локальные значения; Они обеспечивают возможность использовать функции, в отличие от переменных
    • Я использовал var.environment и var.cidr_ab — Но я должен был назначить их местным ценностям. Я использовал переменные, потому что я хотел сделать этот учебник универсальным. Помните — локальные значения самые лучшие
  4. AWS продолжает добавлять зоны доступности (AZS), поэтому количество зон доступности на регион в примерах может быть устаревшей. Обязательно проверьте текущий номер AZS

Вам понравился этот учебник? Хлопать/сердце/единорог и поделиться этим с друзьями и коллегами. Вам не понравилось? Дайте мне знать, какие части, и я позабочусь об этом.

Моя следующая статья будет о Terraporm Cloud и Работы террафора Отказ

Первоначально опубликовано в https://www.prodops.io Отказ

Оригинал: «https://dev.to/prodopsio/terraform-aws-dynamic-subnets-2cgo»