Terraform позволяет создать облачную инфраструктуру с помощью всего одной команды. Допустим, вы хотите запустить Elasticsearch и Kibana в кластере Kubernetes.

Для этого можно написать несколько файлов .tf и выполнить команду terraform apply для инициализации кластера Kubernetes и развёртывания на нем нескольких подсистем.

image

Теперь предположим, что вам нужны и другие экземпляры стека Elastic, которые можно использовать для демонстрации. В этом случае придется создать новые рабочие пространства Terraform и выполнить terraform apply несколько раз.

Проблема такого подхода заключается в том, что в этом случае придется каждый раз реплицировать всю инфраструктуру. Следовательно, у вас будет несколько кластеров Kubernetes. На запуск каждого кластера уходит не менее 15 минут, а его стоимость на AWS составляет 72 долл. в месяц.

image

Гораздо лучшей альтернативой было бы повторное использование одного кластера Kubernetes и создание на его основе нескольких сред. Таким образом, вы платите за один кластер, и вам не нужно ждать создания нового кластера каждый раз, когда вы создаете новую среду.

image

Именно для этого и существует Layerform. Layerform позволяет инженерам разбивать файлы Terraform на компонуемые слои. Таким образом, команды могут иметь общий базовый слой для кластера Kubernetes и несколько вышестоящих слоев с Elasticsearch, Kibana и даже другими необходимыми им бессерверными компонентами, такими как Lambdas, очереди SQS или балансировщики нагрузки.

image

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

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

Как работают слои


В Layerform файлы Terraform делятся на слои. В определении каждого слоя указываются входящие в него файлы и список зависимостей.

Допустим, вы хотите запустить Elasticsearch и Kibana в рамках экземпляра EKS (AWS-управляемый k8s).

Для этого у вас будет два слоя: один для eks, другой для elastic_stack.

{
	"layers": [
    	{
            "name": "eks",
            "files": ["layers/eks.tf", "layers/eks/**"]
    	},
    	{
            "name": "elastic_stack",
            "files": ["layers/elastic_stack.tf", "layers/elastic_stack/**"],
        	"dependencies": ["eks"]
    	}
	]
}

В определении слоя eks указывается, какие файлы относятся к этому слою. Поскольку eks не зависит ни от какой другой инфраструктуры, он не будет указывать другие слои в качестве зависимостей. С другой стороны, файлы слоя elastic_stack зависят от eks. Следовательно, он будет включать eks как зависимость.

Определив таким образом слои, можно самостоятельно запустить кластер EKS, выполнив команду layerform spawn eks default.

image

Затем каждый инженер может создавать собственные экземпляры elastic_stack и повторно использовать один и тот же кластер. Для этого все они выполняют команду layerform spawn elastic_stack <_name_>, и каждый из этих слоев ищет нижележащий слой eks с идентификатором default.

image

➜ layerform list instances
INSTANCE NAME                LAYER NAME	DEPENDENCIES
default                      eks
first                        elastic_stack  eks=default
second                       elastic_stack  eks=default

Если кому-то понадобится новый кластер, он может воссоздать весь стек, передав флаг --base, как в layerform spawn elastic_stack third --base eks=another_eks.

image

➜ layerform list instances
INSTANCE NAME                LAYER NAME	DEPENDENCIES
default                      eks
another_eks                  eks
first                        elastic_stack  eks=default
second                       elastic_stack  eks=default
third                        elastic_stack  eks=another_eks

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

image

В некотором смысле слои Layerform похожи на слои контейнеров. Некоторые называют их «Кастомизация для Terraform».

Использование слоев для создания сред разработки


Для большинства команд «staging» является проблемным местом. Обычно в компаниях работает много инженеров, но есть только одна среда «staging» для всех. Соответственно, разработчики, желающие протестировать изменения в среде, похожей на производственную, вынуждены стоять в очереди.

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

image

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

image

Layerform также предоставляет разработчикам ценные возможности для локальной разработки приложений, направляя их на back-end своей среды «staging».

Предположим, что вы не можете запустить Elasticsearch локально, например, потому что JVM требует слишком много памяти. В этом случае можно использовать вывод layerform для получения адреса удаленного экземпляра Elasticsearch.

➜ layerform output elastic_stack first
 
{
  "cluster_name": {
	"sensitive": false,
	"type": "string",
	"value": "demo-eks-post-example"
  },
  "elasticsearch_url": {
	"sensitive": false,
	"type": "string",
	"value": "https://elasticsearch-post-example.environment.ergomake.link"
  }
}

Вы можете использовать этот URL в файле конфигурации Kibana (config.yml). Таким образом, в процессе разработки можно будет указывать локальную Kibana на удаленный Elasticsearch.

elasticsearch.hosts:
    ["https://elasticsearch-post-example.environment.ergomake.link"]

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

В качестве примера можно привести следующий файл-шаблон для config.yml Kibana.

elasticsearch.hosts: ["{{elasticsearch_url.value}}"]

Чтобы вывести этот файл и заменить {{ elasticsearch_url.value }} реальными значениями для конкретного слоя, можно использовать флаг --template для вывода выведенного файла в stdout.

➜ layerform output elastic_stack first --template config/kibana-template.yml
 
elasticsearch.hosts: ['http://elastic-stack-xehl-es.environment.ergomake.link']

Затем инженеры могут передать полученный файл в реальный config.yml и использовать его, не зная ничего о слоях и не вводя значения вручную.

➜ layerform output elastic_stack first --template config/kibana-template.yml > config.yml

После этого yarn start заставит Kibana прочитать config.yml и указать на удаленный Elasticsearch.

Примечание по совместной работе со слоями


Аналогично Terraform, Layerform может использовать удаленный back-end для хранения состояний и определений слоев.

Когда инженер создает экземпляр слоя, Layerform синхронизирует его с удаленным файлом состояний в S3. Затем, когда кто-то другой использует список экземпляров layerform, Layerform получает состояние из удаленного бэкенда и выводит актуальный список экземпляров.

image

Предположим, что инженер A создал первый слой. Если инженер B захочет сотрудничать с инженером A, он сможет увидеть первый слой в списке слоев, поскольку список хранится удаленно.

# Выполнено инженером B
➜ layerform list instances
 
INSTANCE NAME                LAYER NAME 	DEPENDENCIES
default                      eks
first                        elastic_stack  eks=default

Затем инженер B также может получить URL-адрес экземпляра Elasticsearch в первом слое, выполнив вывод layerform.

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

Использование слоев для превью пул-реквестов


Каждый раз, когда инженеры вносят изменения и открывают пул-реквестор, Vercel запускает свое приложение Next.js и добавляет ссылку на превью в PR.

image

Большинство разработчиков, дизайнеров и менеджеров по продуктам любят превью-версии Vercel. Проблема заключается в том, что эти предварительные версии не подходят для команд с более сложной конфигурацией. Например, вы не можете получить превью полного стека, если у вас есть бессерверное приложение или вам нужен кластер Kubernetes.

Сегодня большинство команд создают такие предварительные среды собственными силами, используя кучу специальных скриптов.

Layerform помогает командам решить эту проблему, позволяя им создавать отдельный слой превью. Затем инженеры могут вызвать Layerform CLI из своего CI и развернуть только ту инфраструктуру, которая им необходима.

Поскольку Layerform использует файлы Terraform, он может создавать любые типы инфраструктуры для этих предварительных версий, включая ресурсы Kubernetes, Lambdas, экземпляры SQS и ведра S3.

Например, в случае стека Elastic инженеры могут создать действие на GitHub для layerform, чтобы размножить только слой стека Elastic поверх общего кластера предварительных версий, что значительно снизит стоимость предварительных версий.

name: Preview
 
on:
	pull_request:
 
jobs:
	preview:
    	runs-on: ubuntu-latest
 
    	steps:
        	# + + Проверка кода, установка deps и т.д..
        	- name: Install Layerform
          	run: go install github.com/ergomake/layerform@main
 
        	# Настройка удаленного статуса - мы будем улучшать это
        	- name: Create Layerform config file
          	run: |
              	mkdir -p ~/.layerform
              	echo "currentContext: demo" > ~/.layerform/config
              	echo "contexts:" >> ~/.layerform/config
              	echo "  demo:" >> ~/.layerform/config
              	echo "	type: s3" >> ~/.layerform/config
              	echo "	bucket: layerform-post-demo" >> ~/.layerform/config
              	echo "	region: us-west-1" >> ~/.layerform/config
 
        	# Собственно создание слоя превью
        	- id: layerform
          	name: Spawn Elasticstack using Layerform
          	run: |
                  layerform spawn elastic_stack ${{ github.event.pull_request.head.ref }}
          	env:
       	       AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
                  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

В приведенной выше схеме работы в качестве имени инстанса слоя будет использоваться имя ветки пул-реквеста.

Как и любой другой инстанс слоя он будет отображаться при запуске списка layerform, поэтому при желании можно подключиться к нему и из терминала.

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

# ...
 
# Получение URL Kibana из результатов layerform с помощью jq
- id: layerform
  name: Spawn Elasticstack using Layerform
  run: |
  	layerform spawn elastic_stack ${{ github.event.pull_request.head.ref }}
  	kibana=$(layerform output elastic_stack ${{ github.event.pull_request.head.ref }} | jq -r .kibana_url.value)
  	echo "kibana=$kibana" >> "$GITHUB_OUTPUT"
  env:
  	AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
 
# Добавление комментария к пул-реквесту
- uses: actions/github-script@v6
  with:
  	script: |
          github.rest.issues.createComment({
        	issue_number: context.issue.number,
        	owner: context.repo.owner,
        	repo: context.repo.repo,
        	body: '${{ steps.layerform.outputs.kibana }}'
      	})

После этого изменения в каждом открытом PR появится ссылка на превью, указывающая на реальную производственную инфраструктуру.

image

Для уничтожения этих инстансов слоя необходимо создать второй рабочий процесс, который запускается при закрытии или объединении PR. Этот рабочий процесс должен вызывать layerform kill и передавать ему имя слоя, которое в данном случае совпадает с именем ветки.

имя: Уничтожать предварительные просмотры при закрытии PR
name: Destroy previews when PRs are closed
 
on:
	pull_request:
    	types: [closed]
 
jobs:
	kill_preview:
    	runs-on: ubuntu-latest
    	steps:
        	# + Проверка кода, установка deps и т.д..
        	- name: Install Layerform
          	run: go install github.com/ergomake/layerform@main
 
        	- name: Kill preview
          	run: layerform kill elastic_stack ${{ github.event.pull_request.head.ref }}

Дополнительные заметки по внедрению


В этих примерах я предполагаю, что пользователи развернули контроллер nginx-ingress-controller на своем кластере через уровень eks. Этот контроллер отвечает за создание nlb и открытие Elasticsearch и Kibana для выхода в Интернет через их ингрессы.

В любом случае, многие разработчики, вероятно, захотят держать свои среды разработки в пределах VPN, что также возможно, поскольку Layerform предоставляет всю инфраструктуру в вашем облаке с помощью простых файлов Terraform.

Когда дело доходит до развертывания собственно капсул в кластере, вы можете использовать все, что пожелаете. Когда я сам тестировал примеры, я указывал необработанные ресурсы Kubernetes через провайдера kubernetes. Тем не менее, вы можете использовать диаграммы Helm с провайдером Helm. Единственное требование для использования слоев — чтобы ваша информация находилась в файле Terraform, а не в специальных скриптах.

Наконец, еще одна интересная деталь заключается в том, что инженеры должны предоставить определения слоев удаленному внутреннему серверу с помощью layerform configure, прежде чем кто-либо сможет породить экземпляры.

Если эта идея показалась вам интересной, пожалуйста, поставьте нам звезду на GitHub.



Возможно, захочется почитать и это:



Комментарии (0)