远程后端配置
学习如何配置和使用 Terraform 远程后端,实现团队协作。
一、为什么需要远程后端
1.1 本地状态的问题
# 本地状态文件
./terraform.tfstate
./terraform.tfstate.backup
问题:
- ❌ 无法团队协作
- ❌ 没有版本控制
- ❌ 容易丢失
- ❌ 无法并发保护
- ❌ 敏感信息明文存储
1.2 远程后端的优势
- ✅ 集中存储状态
- ✅ 自动备份
- ✅ 状态锁定(防止并发冲突)
- ✅ 加密存储
- ✅ 版本历史
- ✅ 团队协作
二、S3 后端(AWS)
2.1 基础配置
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-west-2"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
2.2 创建 S3 桶和 DynamoDB 表
# backend-setup.tf
resource "aws_s3_bucket" "terraform_state" {
bucket = "my-terraform-state"
lifecycle {
prevent_destroy = true
}
tags = {
Name = "Terraform State"
Environment = "Infrastructure"
}
}
# 启用版本控制
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
# 启用服务端加密
resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
# 阻止公开访问
resource "aws_s3_bucket_public_access_block" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
# DynamoDB 表用于状态锁定
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = {
Name = "Terraform State Locks"
Environment = "Infrastructure"
}
}
2.3 迁移到远程后端
# 1. 添加 backend 配置到 main.tf
# 2. 初始化(会提示迁移)
terraform init
# 输出示例:
# Do you want to copy existing state to the new backend?
# Pre-existing state was found while migrating the previous "local" backend to the
# newly configured "s3" backend. No existing state was found in the newly
# configured "s3" backend. Do you want to copy this state to the new "s3"
# backend? Enter "yes" to copy and "no" to start with an empty state.
#
# Enter a value: yes
# 3. 验证迁移
terraform state list
2.4 多环境配置
# environments/dev/backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "dev/terraform.tfstate"
region = "us-west-2"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# environments/prod/backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-west-2"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
三、Azure Storage 后端
3.1 基础配置
terraform {
backend "azurerm" {
resource_group_name = "terraform-state-rg"
storage_account_name = "tfstatestorage"
container_name = "tfstate"
key = "prod.terraform.tfstate"
}
}
3.2 创建 Azure 存储
# 创建资源组
az group create --name terraform-state-rg --location westus2
# 创建存储账户
az storage account create \
--name tfstatestorage \
--resource-group terraform-state-rg \
--location westus2 \
--sku Standard_LRS \
--encryption-services blob
# 创建容器
az storage container create \
--name tfstate \
--account-name tfstatestorage
3.3 使用服务主体认证
terraform {
backend "azurerm" {
resource_group_name = "terraform-state-rg"
storage_account_name = "tfstatestorage"
container_name = "tfstate"
key = "prod.terraform.tfstate"
# 使用服务主体
client_id = var.client_id
client_secret = var.client_secret
tenant_id = var.tenant_id
subscription_id = var.subscription_id
}
}
四、Google Cloud Storage 后端
4.1 基础配置
terraform {
backend "gcs" {
bucket = "my-terraform-state"
prefix = "prod"
# 可选:指定凭证
credentials = file("account.json")
}
}
4.2 创建 GCS 桶
# 创建桶
gsutil mb -p my-project -c STANDARD -l us-west1 gs://my-terraform-state
# 启用版本控制
gsutil versioning set on gs://my-terraform-state
# 设置生命周期(保留最近 10 个版本)
cat > lifecycle.json <<EOF
{
"rule": [
{
"action": {"type": "Delete"},
"condition": {
"numNewerVersions": 10,
"isLive": false
}
}
]
}
EOF
gsutil lifecycle set lifecycle.json gs://my-terraform-state
五、Terraform Cloud
5.1 基础配置
terraform {
cloud {
organization = "my-org"
workspaces {
name = "my-app-prod"
}
}
}
5.2 使用标签选择工作区
terraform {
cloud {
organization = "my-org"
workspaces {
tags = ["app:myapp", "env:prod"]
}
}
}
5.3 认证配置
# 登录 Terraform Cloud
terraform login
# 手动配置 token
cat > ~/.terraform.d/credentials.tfrc.json <<EOF
{
"credentials": {
"app.terraform.io": {
"token": "YOUR_TOKEN_HERE"
}
}
}
EOF
5.4 Terraform Cloud 优势
- ✅ UI 界面管理
- ✅ 自动运行 plan/apply
- ✅ 变量管理
- ✅ 成本估算
- ✅ 策略检查(Sentinel)
- ✅ 私有模块注册表
- ✅ 团队协作和权限管理
六、后端配置最佳实践
6.1 部分配置(Partial Configuration)
# backend.tf
terraform {
backend "s3" {
# 基础配置
region = "us-west-2"
encrypt = true
}
}
# 通过命令行或配置文件提供其余配置
terraform init \
-backend-config="bucket=my-terraform-state" \
-backend-config="key=prod/terraform.tfstate" \
-backend-config="dynamodb_table=terraform-locks"
# 或使用配置文件
# backend-config.tfbackend
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
dynamodb_table = "terraform-locks"
terraform init -backend-config=backend-config.tfbackend
6.2 多环境管理
project/
├── backend.tf
├── environments/
│ ├── dev.tfbackend
│ ├── staging.tfbackend
│ └── prod.tfbackend
└── deploy.sh
dev.tfbackend:
bucket = "my-terraform-state"
key = "dev/terraform.tfstate"
deploy.sh:
#!/bin/bash
ENV=$1
if [ -z "$ENV" ]; then
echo "Usage: ./deploy.sh <env>"
exit 1
fi
terraform init -backend-config="environments/${ENV}.tfbackend"
terraform plan -var-file="environments/${ENV}.tfvars"
6.3 状态锁定
# 自动获取锁
terraform apply
# 强制解锁(谨慎使用)
terraform force-unlock LOCK_ID
锁定信息:
{
"ID": "abc-123-def",
"Operation": "OperationTypeApply",
"Info": "",
"Who": "user@example.com",
"Version": "1.6.0",
"Created": "2024-01-10T12:00:00Z",
"Path": "prod/terraform.tfstate"
}
七、后端迁移
7.1 从本地迁移到 S3
# 1. 配置新后端
cat >> main.tf <<EOF
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "terraform.tfstate"
region = "us-west-2"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
EOF
# 2. 重新初始化
terraform init -migrate-state
# 3. 验证
terraform state list
# 4. 删除本地状态文件(可选)
rm terraform.tfstate*
7.2 更换后端
# 1. 修改 backend 配置
# 2. 重新初始化(会提示迁移)
terraform init -migrate-state -force-copy
# 3. 验证新后端
terraform state pull
7.3 从 S3 迁移回本地
# 1. 移除 backend 配置块
# terraform {
# backend "s3" { ... }
# }
# 2. 初始化
terraform init -migrate-state
八、安全最佳实践
8.1 加密配置
# S3 后端加密
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "terraform.tfstate"
region = "us-west-2"
encrypt = true # 启用加密
kms_key_id = "arn:aws:kms:us-west-2:ACCOUNT_ID:key/KEY_ID" # 使用 KMS
dynamodb_table = "terraform-locks"
}
}
8.2 访问控制
// S3 桶策略
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_ID:role/TerraformRole"
},
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-terraform-state/*"
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_ID:role/TerraformRole"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::my-terraform-state"
}
]
}
8.3 审计和日志
# 启用 S3 访问日志
resource "aws_s3_bucket_logging" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
target_bucket = aws_s3_bucket.logs.id
target_prefix = "terraform-state/"
}
# 启用 CloudTrail
resource "aws_cloudtrail" "terraform_audit" {
name = "terraform-audit"
s3_bucket_name = aws_s3_bucket.audit_logs.id
include_global_service_events = true
is_multi_region_trail = true
event_selector {
read_write_type = "All"
include_management_events = true
data_resource {
type = "AWS::S3::Object"
values = ["${aws_s3_bucket.terraform_state.arn}/*"]
}
}
}
九、故障排查
9.1 常见问题
状态锁定超时:
# 查看锁定信息
aws dynamodb get-item \
--table-name terraform-locks \
--key '{"LockID":{"S":"my-terraform-state/prod/terraform.tfstate"}}'
# 强制解锁
terraform force-unlock LOCK_ID
后端配置错误:
# 重新配置后端
terraform init -reconfigure
# 迁移状态
terraform init -migrate-state
权限问题:
# 验证 AWS 凭证
aws sts get-caller-identity
# 测试 S3 访问
aws s3 ls s3://my-terraform-state/
9.2 备份和恢复
# 手动备份状态
terraform state pull > backup-$(date +%Y%m%d-%H%M%S).tfstate
# 恢复状态
terraform state push backup.tfstate
# 从 S3 恢复特定版本
aws s3api list-object-versions \
--bucket my-terraform-state \
--prefix terraform.tfstate
aws s3api get-object \
--bucket my-terraform-state \
--key terraform.tfstate \
--version-id VERSION_ID \
restored.tfstate
小结
远程后端配置要点:
- 选择合适的后端:S3、Azure、GCS、Terraform Cloud
- 启用加密:保护敏感数据
- 使用状态锁定:防止并发冲突
- 版本控制:保留历史记录
- 访问控制:限制权限
- 定期备份:防止数据丢失
配置好远程后端是团队协作的基础,下一章我们将学习模块化设计。