В этой статье я собираюсь поделиться своим опытом в написании конфигураций Terraform с использованием node.js.
Я собираюсь продемонстрировать некоторые преимущества написания конфигураций Terraform в JavaScript/TypeScript по сравнению с написанием собственных конфигураций Terraform.
Рекомендует ли это Хашикор?
Terraform также поддерживает альтернативный синтаксис, который совместим с JSON. Этот синтаксис полезен при разработке части конфигурации, поскольку существующие библиотеки JSON можно использовать для подготовки сгенерированных файлов конфигурации.
Выше цитата можно увидеть в документации Terraform: https://www.terraform.io/docs/configuration/syntax-json.html Анкет
Хотя Hashicorp на самом деле не рекомендует использовать какой -либо инструмент для создания конфигураций Terraform, он признает, что вполне возможно и хорошо для программного создания конфигураций Terraform.
Инструмент
Инструмент, который я использую, называется Terraform-Generator
Анкет Он доступен в реестре NPM: https://www.npmjs.com/package/terraform Generator Анкет
Что Terraform-Generator
DISE помогает генерировать конфигурации Terraform, используя возможности Node.js & JavaScript/TypeScript. В настоящее время он поддерживает создание конфигураций для Terraform 0,11 и 0,12.
Отношения между Terraform-Generator
и конфигурация Terraform аналогична конфигурации запроса и запроса базы данных, TypeScript и JavaScript или React.js и HTML & Web JavaScript.
Синтаксис
Синтаксис на самом деле очень похож на нативный синтаксис Terraform. Ниже приводится сравнение создания ресурса в нативном терраформе и в Terraform-Generator
Анкет
Терраформ
resource "aws_vpc" "default" { cidr_block = "172.88.0.0/16" }
Терраформ-генератор
tfg.resource('aws_vpc', 'default', { cidr_block: '172.88.0.0/16' });
Преимущества
Расширение VSCODE
В прошлый раз, когда я проверил, нет расширения VSCODE для Terraform 0.12. Это боль, когда вы хотите ориентироваться между ресурсами, переменными и т. Д.
Написав JavaScript/TypeScript в VSCODE, у вас не будет проблем с этим. Он также предоставляет все обычные преимущества, такие как Auto-Complete, которые недоступны в родном Terraform.
Общие конфигурации
Проект Terraform — это папка, которая содержит один или много файлов .tf и папку .Terraform, которая содержит необходимые плагины Terraform.
Допустим, у меня есть 3 проекта для настройки системы, у них есть общий поставщик, некоторые общие локальные переменные и некоторые общие входные переменные, общие вещи должны существовать во всех 3 проектах. Это заставляет мои сценарии иметь дублированные элементы и уменьшает обслуживание.
Одно лекарство — поместить все общие конфигурации в другую папку за пределами всех папок проекта, а затем скопировать их (вручную или через скрипт, я расскажу о сценарии, который я написал в следующем разделе), прежде чем выполнять проекты.
Используя Node.js и Terraform-Generator, общие переменные или код могут быть записаны везде, где вы считаете подходящим, их использование-это просто импорт их.
Местные экологические состояния
Terraform будет генерировать Terraform.tfstate и Terraform.tfstate.backup, когда мы применяем проект. Один проект может иметь только одно состояние.
Допустим, мой проект будет выполнен в 3 средах (разработка, постановка и производство), я не смогу сохранить состояние в своем местном каталоге, потому что у меня будет 3 разных штата, 1 для каждой среды. Мне придется сохранить штаты в удаленном хранилище (например, AWS S3).
Одним из способов достижения сохранения состояний для нескольких среда в локации является перемещение состояний в другую папку, вне папки проекта после выполнения проекта.
Ниже приведен пример моей структуры папок Terraform и того, как я решаю общие конфигурации и проблемы окружающей среды со сценарием Bash. Это увеличивает сложность и уменьшает обслуживание.
Структура папки
. ├── common # Shared configurations, to be copied to project folder before execution | ├── constants.tf | ├── env.tf | ├── provider.tf | ├── env # Environmental variables, to be copied to project folder before execution | ├── dev.tfvars | ├── stg.tfvars | ├── prd.tfvars | ├── outputs # Environmental states, to be copied to project folder before execution, | | and then moved out from project folder after execution | ├── project1 | | ├── dev | | | ├── terraform.tfstate | | | ├── terraform.tfstate.backup | | | | | ├── stg | | | ├── ... | | | | | ├── prd | | ├── ... | | | ├── project2 | | ├── ... | | | ├── project3 | ├── ... | ├── projects # Actual Terraform projects | ├── project1 | | ├── .terraform | | ├── terraform.tf | | | ├── project2 | | ├── ... | | | ├── project3 | ├── ... | ├── run.sh # Bash script to do all the copying and moving of all the shared & environmental configurations and environmental states
run.sh
ACTION=$1 PROJECT=$2 ENV=$3 cd projects/$PROJECT # Copy common tf, tfvars & tfstate to project folder cp ../../common/* . cp ../../env/$ENV.tfvars . cp ../../outputs/$PROJECT/$ENV/* . # Run terraform terraform $ACTION -var-file=$ENV.tfvars # Remove common tf & tfvars rm -f constants.tf rm -f env.tf rm -f provider.tf rm -f $ENV.tfvars # Move tfstate to outputs folder mkdir -p ../../outputs/$PROJECT/$ENV mv terraform.tfstate ../../outputs/$PROJECT/$ENV mv terraform.tfstate.backup ../../outputs/$PROJECT/$ENV
Используя Terraform-Generator, сохраняя один исходный код, я смогу генерировать несколько проектов Terraform для нескольких сред, чтобы сэкономить местные государства в их соответствующей папке проекта.
Ниже приведен пример моей структуры папок Terraform Generator, чтобы показать вам, где находятся созданные конфигурации и состояния Terraform.
. ├── node_modules | ├── ... | ├── outputs | ├── dev | | ├── project1 | | | ├── .terraform | | | ├── terraform.tf | | | ├── terraform.tfstate | | | ├── terraform.tfstate.backup | | | | | ├── project2 | | | ├── ... | | | | | ├── project3 | | ├── ... | | | ├── stg | | ├── ... | | | ├── prd | ├── ... | ├── src | ├── constants | | ├── ... | | | ├── env | | ├── dev.env.ts | | ├── index.ts | | ├── stg.env.ts | | ├── prd.env.ts | | | ├── projects | ├── project1 | ├── ... | | | ├── project2 | ├── ... | | | ├── project3 | ├── ... | ├── package.json ├── tsconfig.json
Папка SRC содержит мой исходный код, он генерирует конфигурацию Terraform для папки выходов в соответствии с средой и проектом, а состояния сохраняются в той же папке, что и сгенерированная конфигурация Terraform.
Короче говоря, у меня будет 3 аналогичные конфигурации Terraform и 3 состояния, сохраняя только 1 исходный код.
Переменные
Чтобы использовать переменные, Terraform требует от нас написать что -то вроде этого:
variable "env" { type = string } variable "vpc_cidr" { type = string }
Вам придется помнить, чтобы добавить переменный блок всякий раз, когда вы вводите новую переменную и удаляете блок всякий раз, когда вы решите удалить переменную для поддержания чистой конфигурации.
В JavaScript использование переменной является лишь вопросом импорта переменной или импорта файла JSON.
Если вы используете TypeScript и хотите объявить интерфейс для всех ваших переменных, он так же просто, как и следующий пример:
export interface Variables { env: string; vpcCidr: string; }
Вы также можете использовать различные библиотеки для управления переменными, например, Dotenv.
Условные
Terraform не поддерживает if-else-statement, точка.
Используя JavaScript/TypeScript, вы можете использовать if-else или коммутатор, как вам нравится.
В следующем примере показан один из использования использования if-else в моем проекте:
const getAvailabilityZone = (idx: number): string => { const i = 3 % idx; if (i === 0) { return 'ap-southeast-1a'; } else if (i === 1) { return 'ap-southeast-1b'; } else { return 'ap-southeast-1c'; } }; for (let i = 0; i < 3; i++) { tfg.resource('aws_subnet', `subnet${i}`, { vpc_id: vpc.attr('id'), cidr_block: env.subnetCidrs[i], availability_zone: getAvailabilityZone(i) }); }
Без петли (я расскажу об этом в следующем разделе) и If-Else Statement, мне придется повторить создание подсети 3 раза, чтобы создать их в 3 зонах доступности.
Вы также можете использовать условные для управления атрибутами ресурсов и создания ресурсов, например
if (env === 'production') { // create resource that is exclusive to production environment } tfg.resource('resource_type', 'resource_name', { attribute: env === 'production' ? 'some value': 'other value' }
Петли
Terraform поддерживает какую -то цикл, например, count & for_each.
Ограничение петли Terraform заключается в том, что они поддерживаются только блоком ресурсов, но не модульными блоками на данный момент.
Что если мы хотим создать несколько ресурсов в цикле? Нам придется использовать счет/for_each в каждом блоке ресурсов. Разве не было бы более выгодным иметь только 1 петлю и создавать все ресурсы внутри цикла?
Цикл Terraform — это один цикл уровня (1 петля в блоке ресурсов). Что если есть необходимость иметь вложенную петлю? Например. Используя цикл для создания 3 групп безопасности для каждой группы безопасности, создайте 3 правила группы безопасности. Без вложенного цикла невозможно сохранить вашу конфигурацию в чистоте.
В Terraform мне придется сделать что -то вроде этого:
resource "aws_security_group" "sg" { count = 3 ... } resource "aws_security_group_rule" "sgrule0" { count = length(aws_security_group.sg) security_group_id = aws_security_group.sg.*.id[count.index] ... } resource "aws_security_group_rule" "sgrule1" { count = length(aws_security_group.sg) security_group_id = aws_security_group.sg.*.id[count.index] ... } resource "aws_security_group_rule" "sgrule2" { count = length(aws_security_group.sg) security_group_id = aws_security_group.sg.*.id[count.index] ... }
Используя Terraform-Generator, вы сможете сделать что-то вроде этого:
for (let i = 0; i < 3; i++) { const sg = tfg.resource('aws_security_group', `sg${i}`, { ... }); for (let j = 0; j < 3; j++) { tfg.resource('aws_security_group_rule', `sgrule${j}`, { security_group_id = sg.attr('id') ... }); } }
Используя JavaScript/TypeScript, не стесняйтесь использовать любой цикл, как вы считаете нужным. Пример использования для петли показан в предыдущем разделе.
Модули против функций
Модуль Terraform аналогичен проекту Terraform (проект также известен как корневой модуль).
Процесс создания и использования модуля Terraform утомите, у меня будет другая папка с другим набором файлов .tf и требуемыми плагинами, и он даже не имеет прямого доступа к моим общим конфигурациям и переменным окружающей среды.
Например, чтобы создать модуль для простого создания тегов для всех моих ресурсов, я сделаю следующее:
variable "project_name" { type = string } variable "env" { type = string } output "tags" { value = { Project = var.project_name Env = var.env } }
В проекте я сделаю следующее, чтобы использовать модуль:
module "tags" { source = "../../modules/tags" project_name = local.projectName env = var.env } resource "aws_vpc" "default" { cidr_block = var.vpc_cidr tags = merge(module.tags.tags, map( "Name", "vpc-${local.project_name}-${var.env}" )) }
Project_Name и Env — мои общие переменные, они обмениваются всеми проектами в рамках одной и той же настройки системы, но мне все еще нужно передать их в модуль, потому что он не может получить к ним доступ напрямую.
Кроме того, блок модуля имеет набор фиксированных атрибутов и фиксированный выход, я не могу передать аргументы и получить адаптированный выход, поэтому мне нужно объединить мои переменные теги с моими постоянными тегами вручную. Процесс утомительный.
Используя функцию Terraform-Generator и JavaScript, вот как я это сделаю:
const getTags = (name: string): Map => map({ Name: `${name}-${constants.projectName}-${env.env}`, Project: constants.projectName, Env: env.env }); tfg.resource('aws_vpc', 'default', { cidr_block: env.vpcCidr, tags: getTags('vpc') });
Очевидно, что версия TypeScript намного проще и гораздо проще. Он имеет доступ к моим постоянным и переменным окружающей среды, он принимает аргументы и возвращает именно то, что мне нужно.
Другие возможности
Сила использования node.js для генерации конфигураций терраформ безгранична, или я должен сказать, что он ограничен только теми способностью, предоставляемыми Node.js и миром JavaScript, что намного шире, чем то, что обеспечивается Terraform. Вы сможете использовать любые модули API node.js и NPM.
Когда мы должны использовать это
Если вы профессиональный поставщик услуг, я не могу сообщить вам о том, использует ли это Terraform-Generator
это хороший шаг, потому что это не широко принятый инструмент (пока). Есть больше соображений, о которых можно подумать, например, Примут ли ваши клиенты использование этого непопулярного инструмента? Ваша компания/коллеги достаточно открыты, чтобы попробовать это? Будет ли он иметь проблему оперативного/технического обслуживания в будущем?
Однако, если вы делаете свою собственную облачную инфра -настройку и думаете, что это может решить некоторые ваши боли в использовании Terraform, почему бы не попробовать и рассказать мне, что вы думаете в разделе комментариев.
Оригинал: «https://dev.to/ahzhe/writing-terraform-using-node-js-3l09»