Представьте, что некоторое время назад вы начали небольшой проект в terraform. А теперь у ваших приложений сотни клиентов, инфраструктура имеет несколько окружений, но все тот же монолит terraform отвечает за всю вашу облачную инфраструктуру. Звучит знакомо? Тогда продолжайте читать, и вы узнаете, как разбить монолит terraform на несколько окружений без рекреации ресурсов.
Аудитория
Я предполагаю, что у вас уже есть опыт работы с terraform. Вы управляете некоторыми облачными инфраструктурами с помощью terraform, знакомы с файлами состояний и конфигурацией бэкенда.
Теория
Давайте быстро вспомним, что мы знаем о состоянии terraform. Terraform хранит информацию о своих ресурсах в файле состояния. У Terraform есть несколько вариантов хранения файла состояния, самый популярный из которых, вероятно, находится в облачном хранилище объектов. Поэтому в качестве примера мы будем использовать S3.
Если мы хотим управлять окружениями отдельно, нам нужно иметь состояние для каждого окружения. Чтобы мы могли применять конфигурацию независимо друг от друга. Создание еще одного состояния не представляет собой большой проблемы. Сложная задача — перенести информацию об облачных ресурсах из одного состояния в другое. И сделать это без простоя или без необходимости воссоздавать ресурсы.
В начале у нас есть один каталог с кодом terraform для обеих сред. Наша цель — разделить код, а затем переместить записи о ресурсах из одного состояния в другое.
Теперь давайте договоримся о структуре файловой системы. Для целевого состояния мы будем использовать две отдельные директории. Эта схема очень хорошо объяснена здесь
Если вы хотите узнать больше о лучших практиках Terraform, я бы настоятельно рекомендовал взглянуть на руководство по лучшим практикам Terraform от Антона Бабенко.
Миграция в деталях
Как только вы выделите новую директорию для нового окружения, вы можете начать перенос связанного кода. Просто вырежьте код из одного main.tf
в другой. Не применяйте никаких изменений на этом этапе.
Далее вам нужно будет немного поработать с инструментом terraform. Вот что необходимо сделать
- Создайте новое состояние для нового окружения
- Извлеките файл состояния из удаленного бэкенда в свой локальный каталог
- Переместить соответствующие ресурсы из одного состояния в другое
- Наконец, переместите обновленное состояние для удаленного бэкенда.
Короткий пример
Если вы опытный пользователь terraform, то этот короткий пример для вас
cd dev
# now set up remote backend for this new env
terraform init
terraform state pull > new.tfstate
# now open your favourite text editor
# and move resource definitions from prod tf files to dev tf files
cd ../prod
terraform state list > resource_list.txt
# now open resource_list.txt
# and leave there only the resource that you want to move
for i in $(cat resource_list.txt); do
terraform state mv -state-out=../dev/new.tfstate ${i} ${i}
done
cd ../dev
terraform state pull > new.tfstate
Подробный пример
Существующая инфраструктура
Мы рассмотрим простой пример с двумя сетями VPC.
# prod/main.tf
resource "aws_vpc" "prod" {
cidr_block = "10.0.0.0/24"
}
resource "aws_vpc" "dev" {
cidr_block = "10.1.1.0/24"
}
Конфигурация удаленного бэкенда выглядит следующим образом
# prod/provider.tf
terraform {
required_version = "~> 1.0.0"
backend "s3" {
region = "eu-central-1"
bucket = "myterraformstatemonolith"
key = "prod"
}
}
Инициализация нового окружения
$ mkdir dev
$ cd dev
Настройка удаленного бэкенда. Обратите внимание, что ключ изменился, вы также можете установить новый bucket, если хотите. Но сейчас для наших нужд достаточно отдельного файла состояния.
# dev/provider.tf
terraform {
required_version = "~> 1.0.0"
backend "s3" {
region = "eu-central-1"
bucket = "myterraformstatemonolith"
key = "dev"
}
}
Теперь запустите terraform init
, это создаст файл в ведре S3.
$ terraform init
Initializing the backend...
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
<output omitted>
Перемещение определений ресурсов
Теперь вам нужно переместить содержимое файлов terraform, относящихся к новому окружению. В моем случае мой новый dev/main.tf
будет выглядеть следующим образом
resource "aws_vpc" "dev" {
cidr_block = "10.1.1.0/24"
}
Переместить ресурсы из файла состояния в новый файл.
Это немного сложнее, чем предыдущие шаги. Сначала давайте вытащим новое удаленное состояние
$ cd dev
$ terraform state pull > new.tfstate
Затем вернемся в каталог prod
и переместим ресурсы
$ cd prod
$ terraform state list
aws_vpc.dev
aws_vpc.prod
$ terraform state mv -state-out=../dev/new.tfstate aws_vpc.dev aws_vpc.dev
Move "aws_vpc.dev" to "aws_vpc.dev"
Successfully moved 1 object(s).
Переместите обновленный файл состояния обратно в ведро S3
$ terraform state push new.tfstate
Вот и все, теперь убедитесь, что все обновлено
$ terraform plan
aws_vpc.dev: Refreshing state... [id=vpc-070562866e6399b45a]
No changes. Your infrastructure matches the configuration.