03 · Платформа: DevOps, k8s, сеть, хранилище3.8 · Terraform и IaC3.8.2сложный

Terraform на практике: plan, apply, modules

Зачем это нужно

Предыдущий урок — «зачем IaC». Здесь — как читать и безопасно менять Terraform в команде: variables, outputs, modules, workspaces (или отдельные каталоги env), типичный workflow MR. Даже если вы не platform engineer, вы будете review'ить MR с новым bucket для dataset или quota на namespace через Terraform provider Kubernetes.

Основные идеи

Минимальный root module.

` terraform { required_version = ">= 1.5" required_providers { kubernetes = { source = "hashicorp/kubernetes" version = "~> 2.23" } } backend "s3" { bucket = "mdp-terraform-state" key = "dev/k8s-addons/terraform.tfstate" region = "eu-central-1" } }

provider "kubernetes" { config_path = var.kubeconfig_path }

variable "namespace" { type = string default = "ml-dev" }

resource "kubernetes_namespace" "ml" { metadata { name = var.namespace } } `

Variables и tfvars. Общие defaults в variables.tf; окружение — в dev.tfvars:

namespace = "ml-dev"

terraform plan -var-file=dev.tfvars

Outputs — контракт модуля наружу:

output "namespace_name" { value = kubernetes_namespace.ml.metadata[0].name }

Module call.

` module "minio_tenant" { source = "../modules/minio-tenant"

bucket_name = "ml-datasets-dev" replicas = 4 }

output "bucket" { value = module.minio_tenant.bucket_id } `

Внутри module — свои main.tf, variables.tf, outputs.tf. Версионирование module: git tag или Terraform Registry.

Lifecycle hooks.

` resource "kubernetes_persistent_volume_claim" "example" {

...

lifecycle { prevent_destroy = true } } `

Защита критичных ресурсов от случайного terraform destroy.

Count / for_each. Создать N похожих namespace или S3 prefix:

` variable "teams" { type = list(string) default = ["alpha", "beta"] }

resource "kubernetes_namespace" "team" { for_each = toset(var.teams) metadata { name = "ml-${each.key}" } } `

Plan output читать обязательно.

  • + create — новый ресурс

  • ~ update in-place — изменение

  • -/+ destroy and recreateопасно для stateful (PVC, DB)

  • - destroy — удаление

Targeted apply (-target) — только для emergency debug, не для routine (ломает dependency graph).

Как это выглядит на практике

MR workflow в platform team:

  1. Ветка feat/minio-bucket-ml-capstone.

  2. Добавить module call + tfvars для dev.

  3. CI: terraform fmt -check, validate, plan — comment bot постит plan diff в MR.

  4. Review двумя инженерами.

  5. Merge → CD job terraform apply на dev → smoke → apply prod в maintenance window.

Локально (учебный sandbox только):

cd environments/dev terraform init terraform plan -var-file=dev.tfvars -out=plan.bin terraform apply plan.bin

Kubernetes provider use case для ML. Namespace, ResourceQuota (limits CPU/GPU), LimitRange, optional NetworkPolicy baseline — всё reproducible.

resource "kubernetes_resource_quota" "ml_dev" { metadata { name = "gpu-quota" namespace = "ml-dev" } spec { hard = { "requests.nvidia.com/gpu" = "2" } } }

Типичные ошибки студентов.

  • Забыли terraform init после clone — provider not found.

  • Правят prod tfvars локально и apply с laptop — обход CI запрещён политикой.

  • Commit .tfstate в Git — утечка metadata и secrets.

Что сделать после занятия

  • Выполните terraform validate в учебном каталоге (read-only sandbox).

  • Найдите в plan строку forces replacement и объясните риск для ML workload.

  • Опишите, какие inputs/outputs были бы у module «namespace + quota для capstone team».

Официальные материалы