Перейти к основному содержимому

Тестирование Terraform

Инженеру Архитектору

Зачем тестировать инфраструктурный код

IaC даёт уверенность, а не гарантию: если модуль прошёл plan и apply в test-аккаунте, высока вероятность, что тот же код сработает в prod. Тесты сокращают страх перед изменениями и позволяют чаще выкатывать.


Пирамида тестов IaC

┌─────────────┐
│ E2E / live │ curl ALB, полный стек в test-аккаунте
├─────────────┤
│ Integration │ Terratest: apply + assert + destroy
├─────────────┤
│ Static/unit │ validate, fmt, tflint, checkov, plan
└─────────────┘
УровеньЧто проверяетСтоимость
StaticСинтаксис, стиль, policy (открытые SG, публичный S3)Секунды, без облака
Unit (plan)terraform plan с mock tfvars — ожидаемые +/−/~/ destroyМинуты, read-only или test account
IntegrationРеальный apply модуля, проверка outputs/APIДеньги + минуты
E2EПолный live-стек + HTTP/health checksМаксимум

Статический уровень (CI на каждый PR)

terraform fmt -check -recursive
terraform init -backend=false
terraform validate
tflint --recursive
checkov -d .
terraform plan -input=false -var-file=test.tfvars -out=tfplan

Разбор:

  • -backend=false на validate — без доступа к prod state.
  • checkov/tflint — policy и устаревшие конструкции до apply.
  • Артефакт tfplan — тот же план, что ревьюит человек в PR.

См. также эксплуатация CI/CD — IaC.


Ручное тестирование

После apply модуля ALB (из практического пути):

terraform output alb_dns_name
curl "http://$(terraform output -raw alb_dns_name)/"

Ожидаемый ответ — 200 и тело страницы. После проверки — terraform destroy в test-аккаунте, иначе останутся платные ресурсы.


Terratest (интеграционные тесты на Go)

Terratest поднимает реальную инфраструктуру в изолированном каталоге, проверяет outputs и всегда вызывает destroy в defer:

func TestWebserverCluster(t *testing.T) {
terraformOptions := &terraform.Options{
TerraformDir: "../modules/services/webserver-cluster",
Vars: map[string]interface{}{
"cluster_name": "test-" + random.UniqueId(),
},
}
defer terraform.Destroy(t, terraformOptions)

terraform.InitAndApply(t, terraformOptions)
url := terraform.Output(t, terraformOptions, "alb_url")
http_helper.HttpGetWithRetry(t, url, nil, 200, "Hello", 30, 5*time.Second)
}

Разбор:

  • defer Destroy — обязательная очистка даже при падении assert.
  • Уникальный cluster_name — параллельные тесты не конфликтуют в одном аккаунте.
  • Go + AWS credentials на CI-runner; для команд без Go достаточно static + ручного staging.

Terraform 1.6+ — terraform test

Встроенные mock-провайдеры и .tftest.hcl позволяют unit-тестировать модули без облака (см. документацию HashiCorp). Подходит для проверки логики locals и условных ресурсов; E2E по-прежнему требует test-аккаунта.


Практические правила

  • Отдельный AWS account / subscription для CI-тестов.
  • Tag Environment=test и auto-cleanup по расписанию на случай упавшего job.
  • Не гонять integration-тесты на каждый commit в main — nightly или перед release module version.
  • Секреты в test — те же паттерны, что в аутентификации CI/CD.

См. также

См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").