使用 Terraform 配置数据库(IaC)
症状
目标:使用 Terraform 将数据库基础设施(实例、参数组、网络)定义为代码(基础设施即代码);建立 plan/apply 流程、远程 state 和漂移管理。
1. 选择并配置 provider(aws / google / azurerm)
为你所使用的云定义 provider 并固定其版本。在 required_providers 块中,AWS 锁定 hashicorp/aws provider,GCP 锁定 hashicorp/google,Azure 锁定 hashicorp/azurerm。固定版本可确保团队内行为一致。
PostgreSQL
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-central-1"
}2. 设置远程 state 和锁定
不要将 state 文件保存在本地;为团队协作和安全起见,使用远程 backend。常见选择是 AWS 上的 S3 backend + DynamoDB 锁表、GCP 上的 gcs backend 以及 Azure 上的 azurerm backend(Storage Account)。远程 state 通过锁定防止并发 apply,并使 state 成为唯一可信来源。由于 state 中可能以明文保存密码,backend 必须加密并限制访问。
PostgreSQL
terraform {
backend "s3" {
bucket = "company-tfstate"
key = "db/terraform.tfstate"
region = "eu-central-1"
dynamodb_table = "tf-lock"
encrypt = true
}
}3. 定义数据库资源
为你的引擎和云编写主资源:AWS 上为 aws_db_instance(Aurora 为 aws_rds_cluster),GCP 上为 google_sql_database_instance,Azure 上为 azurerm_mssql_database(对于 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 上使用 aws_db_parameter_group,GCP 上使用 google_sql_database_instance 中的 settings.database_flags,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 机密提供其值。请记住:该值会写入 state 文件,因此远程 state 必须加密。最干净的做法是永远不将密码传入 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 流程
先用 terraform init 准备 provider/backend,用 terraform plan 查看将要变更的内容,批准后用 terraform apply 应用。不要在未审查 plan 输出的情况下 apply;CI 中的安全流程是将 'plan' 作为 PR 评论发布,经人工批准后再 apply。通过 plan 输出中的 -/+ 标记识别破坏性变更(例如实例重建)。
PostgreSQL
terraform init
terraform plan -out=plan.tfplan
terraform apply plan.tfplan7. 检测并修复漂移
若有人在控制台中手动更改,实际基础设施与 state 就会出现偏离(漂移)。在“本不应有任何变更”时 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