Развёртывание баз данных с Terraform (IaC)
Симптом
Цель: описать инфраструктуру баз данных (экземпляр, группу параметров, сеть) как код (Infrastructure as Code) с помощью Terraform; настроить процесс plan/apply, удалённое состояние (remote state) и управление дрейфом (drift).
1. Выберите и настройте провайдер (aws / google / azurerm)
Определите провайдер для используемого облака и зафиксируйте его версию. В блоке required_providers закрепите hashicorp/aws для AWS, hashicorp/google для GCP и hashicorp/azurerm для Azure. Фиксация версии обеспечивает одинаковое поведение во всей команде.
PostgreSQL
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-central-1"
}2. Настройте удалённое состояние и блокировку
Не храните файл состояния локально; для командной работы и безопасности используйте удалённый backend. Типичные варианты: backend S3 + таблица блокировок DynamoDB в AWS, backend gcs в GCP и backend azurerm (Storage Account) в Azure. Удалённое состояние предотвращает параллельные apply за счёт блокировки и делает состояние единым источником истины. Поскольку пароли могут храниться в состоянии открытым текстом, держите backend зашифрованным и с ограниченным доступом.
PostgreSQL
terraform {
backend "s3" {
bucket = "company-tfstate"
key = "db/terraform.tfstate"
region = "eu-central-1"
dynamodb_table = "tf-lock"
encrypt = true
}
}3. Определите ресурс базы данных
Опишите основной ресурс для вашего движка и облака: aws_db_instance в AWS (или aws_rds_cluster для Aurora), google_sql_database_instance в GCP, azurerm_mssql_database в Azure (для SQL Server — внутри azurerm_mssql_server). Здесь задайте движок, версию, класс, хранилище и окно бэкапа.
PostgreSQL
resource "aws_db_instance" "pg" {
identifier = "app-db"
engine = "postgres"
engine_version = "16"
instance_class = "db.t3.medium"
allocated_storage = 50
db_name = "appdb"
username = "pgadmin"
password = var.db_password
backup_retention_period = 7
}SQL Server
resource "azurerm_mssql_database" "db" {
name = "appdb"
server_id = azurerm_mssql_server.srv.id
sku_name = "S1"
}4. Опишите группу параметров как код
Задавайте настройки базы данных (max_connections, work_mem, кодировка) ресурсом параметров, а не вручную в консоли. Используйте aws_db_parameter_group в AWS, settings.database_flags внутри google_sql_database_instance в GCP и ресурс конфигурации сервера в Azure. Тогда настройки версионируются и воспроизводимы.
PostgreSQL
resource "aws_db_parameter_group" "pg" {
name = "app-pg16"
family = "postgres16"
parameter {
name = "max_connections"
value = "200"
}
}
# inside aws_db_instance:
# parameter_group_name = aws_db_parameter_group.pg.name5. Передавайте секреты через переменные и менеджер секретов
Не прописывайте пароль в файле .tf; определите его как чувствительную переменную (variable ... sensitive = true) и передавайте значение через переменную окружения TF_VAR_, менеджер секретов (AWS Secrets Manager, Vault) или секрет CI. Помните: значение записывается в файл состояния, поэтому удалённое состояние должно быть зашифровано. Самый чистый подход — вообще не передавать пароль в Terraform, а читать его из ресурса менеджера секретов.
PostgreSQL
variable "db_password" {
type = string
sensitive = true
}
# CI/shell:
export TF_VAR_db_password="$(vault kv get -field=pw secret/db)"6. Выполните процесс plan и apply
Сначала подготовьте провайдер/backend командой terraform init, посмотрите, что изменится, через terraform plan, утвердите и примените через terraform apply. Не применяйте без просмотра вывода plan; безопасный процесс в CI — публиковать 'plan' комментарием к PR и применять после утверждения человеком. Деструктивные изменения (например, пересоздание экземпляра) выявляйте по маркеру -/+ в выводе plan.
PostgreSQL
terraform init
terraform plan -out=plan.tfplan
terraform apply plan.tfplan7. Обнаружение и устранение дрейфа
Если кто-то вручную вносит изменение в консоли, реальная инфраструктура и состояние расходятся (drift). Различия, появляющиеся в terraform plan, «когда ничего не должно было измениться», выявляют дрейф; разница читается через terraform refresh/plan. Либо перенесите изменение обратно в код, либо верните инфраструктуру к коду через apply. Запретите ручные изменения как правило; код должен быть единым источником истины.
PostgreSQL
# drift check (when no changes are expected):
terraform plan
# expect 'No changes'; any diff means drift
# bring an existing resource into state with import:
terraform import aws_db_instance.pg app-db