Terraform: terraform_remote_state – отримання outputs інших state-файлів

Автор |  22/09/2023

За допомогою data "terraform_remote_state" ми можемо отримати outputs одного проекту, щоб використати в іншому.

Наприклад, у нас AWS VPC створюється окремо від AWS EKS (хоча в серії Terraform: створення EKS, частина 1 – VPC, Subnets та Endpoints VPC створювалась як частина кластеру, але потім я їх розділив).

Для створення EKS – йому треба передати VPC ID, щоб потім з data "aws_subnets" отримати список сабнетів, в яких буде створено кластер Kubernetes.

Можна захаркодити значення VPC – просто задати змінну string, в якій зберігати значення, і в данному випадку це більш-менш робоче рішення, бо VPC ID навряд чи буде часто змінюватись. Проте якщо у вас досить багато значень, або вони динамічні – то є сенс використати terraform_remote_state, який зможе “сходити” в AWS S3 бакет іншого проекту, і отримати актуальні значення прямо зі стейт-файлу.

Отже, що маємо: проект з VPC модулем, який має output:

output "vpc_id" {
  value = module.vpc.vpc_id
}

Він вже задеплоїний, і ми можемо отримати цей ID зі стейту за допомогою terraform output:

$ terraform output vpc_id
"vpc-0958e335e1c910ece"

Сам стейт проекту з VPC зберігається в AWS S3:

$ aws --profile tf-admin s3 ls tf-state-backend-atlas-vpc/dev/
2023-09-22 15:14:43      81292 atlas-vpc-dev.tfstate

Далі, в проекті з модулем EKS додаємо data "terraform_remote_state":

data "terraform_remote_state" "vpc" {
  backend = "s3"
  config = {
    bucket         = "tf-state-backend-atlas-vpc"
    key            = "${var.environment}/atlas-vpc-${var.environment}.tfstate"
    region         = "${var.aws_region}"
    dynamodb_table = "tf-state-lock-atlas-vpc-${var.environment}"
  }
}

При чому тут, на відміну від звичайної конфіграції terraform.backend{} ми можемо використовувати variables.

Створюємо локальну змінну, щоб потім не міняти по всьому коду EKS при якихось змінах в outputs VPC:

locals {
  vpc_out = data.terraform_remote_state.vpc.outputs
}

І використовуємо цей vpc_out:

...
data "aws_subnets" "private" {
  filter {
    name   = "vpc-id"
    values = [local.vpc_out.vpc_id]
  }

  tags = {
    subnet-type = "private"
  }
}

data "aws_subnets" "intra" {
  filter {
    name   = "vpc-id"
    values = [local.vpc_out.vpc_id]
  }

  tags = {
    subnet-type = "intra"
  }
}
...
module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 19.0"
  ...
  vpc_id                   = local.vpc_out.vpc_id
  subnet_ids               = data.aws_subnets.private.ids
  control_plane_subnet_ids = data.aws_subnets.intra.ids
...

Готово.