3.8.2 · блок 3
Terraform на практике: plan, apply, modules
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».