TLDR: Lưu trữ trạng thái từ xa (S3, Azure Blob, GCS, Terraform Cloud) để các nhóm chia sẻ cùng một trạng thái. Bật khóa trạng thái để ngăn sửa đổi đồng thời. Giữ dữ liệu nhạy cảm được mã hóa. Sử dụng kiểm soát phiên bản cho các tệp cấu hình (không phải trạng thái). Triển khai quy trình phê duyệt các thay đổi của production.
Khi làm việc một mình, các tệp trạng thái cục bộ hoạt động tốt. Đối với các nhóm, backend từ xa rất cần thiết cho sự cộng tác, bảo mật và độ tin cậy.
Tại sao backend từ xa lại quan trọng
trạng thái cục bộ tạo ra các vấn đề trên quy mô lớn:
Không cộng tác: Các thành viên trong nhóm không thể biết cơ sở hạ tầng nào tồn tại hoặc những thay đổi mà người khác đang thực hiện.
Dễ bị mất: Nếu máy tính xách tay của ai đó bị lỗi, tệp trạng thái sẽ biến mất. Việc tái tạo nó rất khó khăn và dễ xảy ra lỗi.
Không khóa: Hai người chạy terraform apply đồng thời làm hỏng trạng thái.
H Khó bảo mật: Các tệp trạng thái chứa dữ liệu nhạy cảm. Việc giữ chúng an toàn trên từng máy tính xách tay là điều khó khăn.
Không có lịch sử: Bạn không thể thấy điều gì đã thay đổi khi hoặc quay lại trạng thái trước đó.
backend từ xa giải quyết những vấn đề này bằng cách lưu trữ trạng thái tập trung bằng tính năng khóa, mã hóa và lập phiên bản.
S3 backend (AWS)
backend từ xa phổ biến nhất sử dụng AWS S3 để lưu trữ và DynamoDB để khóa.
Đang thiết lập S3 backend
Tạo nhóm S3 cho trạng thái:
aws s3api create-bucket \
--bucket mycompany-terraform-state \
--region us-east-1
# Enable versioning for state history
aws s3api put-bucket-versioning \
--bucket mycompany-terraform-state \
--versioning-configuration Status=Enabled
# Enable encryption
aws s3api put-bucket-encryption \
--bucket mycompany-terraform-state \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}]
}'
# Block public access
aws s3api put-public-access-block \
--bucket mycompany-terraform-state \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
Tạo bảng DynamoDB để khóa:
aws dynamodb create-table \
--table-name terraform-locks \
--attribute-definitions AttributeName=LockID,AttributeType=S \
--key-schema AttributeName=LockID,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--region us-east-1
Định cấu hình backend trong mã Terraform của bạn:
# backend.tf
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
Khởi tạo để di chuyển trạng thái cục bộ hiện có:
terraform init
# Terraform asks if you want to copy existing state to S3
# Type 'yes' to migrate
trạng thái của bạn hiện được lưu trữ từ xa. Các thành viên trong nhóm có thể truy cập nó bằng cách định cấu hình cùng một backend.
S3 backend với các môi trường khác nhau
Sử dụng các tệp trạng thái khác nhau cho từng môi trường:
# environments/dev/backend.tf
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "dev/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# environments/prod/backend.tf
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
Điều này giúp tách biệt các trạng thái môi trường trong khi sử dụng cùng một nhóm.
Khóa trạng thái bằng DynamoDB
Khi ai đó chạy terraform apply, Terraform sẽ nhận được khóa trong DynamoDB. Các hoạt động khác chờ cho đến khi khóa được nhả ra.
Developer A DynamoDB Lock Table Developer B
│ │ │
│ terraform apply │ │
├───────────────────────────>│ │
│ Lock acquired │ │
│<───────────────────────────┤ │
│ Making changes... │ terraform apply │
│ │<─────────────────────────┤
│ │ Lock held by A │
│ ├─────────────────────────>│
│ │ Waiting for lock... │
│ Changes complete │ │
├───────────────────────────>│ │
│ Lock released │ │
│ ├─────────────────────────>│
│ │ Lock acquired │
│ │<─────────────────────────┤
│ │ Making changes... │
Nếu Terraform gặp sự cố, khóa có thể không mở được. Buộc mở khóa:
terraform force-unlock LOCK_ID
Nhận LOCK_ID từ thông báo lỗi. Chỉ làm điều này nếu bạn chắc chắn không có ai khác đang chạy Terraform.
Azure backend
Đối với cơ sở hạ tầng dựa trên Azure, hãy sử dụng Azure Blob Storage:
# Create resource group
az group create --name terraform-state-rg --location eastus
# Create storage account
az storage account create \
--name mycompanytfstate \
--resource-group terraform-state-rg \
--location eastus \
--sku Standard_LRS \
--encryption-services blob
# Create container
az storage container create \
--name tfstate \
--account-name mycompanytfstate
Định cấu hình backend:
terraform {
backend "azurerm" {
resource_group_name = "terraform-state-rg"
storage_account_name = "mycompanytfstate"
container_name = "tfstate"
key = "prod.terraform.tfstate"
}
}
Azure tự động xử lý việc khóa thông qua hợp đồng thuê blob.
Google Cloud backend
Đối với GCP:
# Create bucket
gsutil mb gs://mycompany-terraform-state
# Enable versioning
gsutil versioning set on gs://mycompany-terraform-state
Định cấu hình backend:
terraform {
backend "gcs" {
bucket = "mycompany-terraform-state"
prefix = "prod"
}
}
GCS tự động cung cấp khóa.
Đám mây địa hình
Terraform Cloud (trước đây là Terraform Enterprise) là dịch vụ được quản lý bởi HashiCorp. Nó cung cấp trạng thái từ xa, khóa, giao diện người dùng web và tích hợp CI/CD.
Thiết lập đám mây Terraform
Tạo tài khoản tại app.terraform.io.
Tạo một tổ chức và không gian làm việc thông qua giao diện người dùng web.
Tạo mã thông báo API:
terraform login
Điều này tạo ra ~/.terraform.d/credentials.tfrc.json bằng mã thông báo của bạn.
Định cấu hình backend:
terraform {
cloud {
organization = "mycompany"
workspaces {
name = "production"
}
}
}
Khởi tạo và di chuyển trạng thái:
terraform init
Đám mây Terraform cung cấp:
- Giao diện người dùng web để xem tài nguyên và trạng thái
- Thực thi từ xa (chạy trong Terraform Cloud, không chạy cục bộ)
- Chính sách dưới dạng mã với Sentinel
- Dự toán chi phí
- Đăng ký mô-đun riêng
- Kiểm soát truy cập nhóm
- Chạy lịch sử và nhật ký kiểm tra
Đối với các nhóm, Terraform Cloud đơn giản hóa việc cộng tác một cách đáng kể.
Thực tiễn tốt nhất về kiểm soát phiên bản
Lưu trữ cấu hình Terraform trong Git, nhưng không bao giờ lưu trữ tệp hoặc thông tin xác thực commit trạng thái.
.gitignore
Luôn sử dụng .gitignore thích hợp:
# Local state files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Exclude override files
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# CLI configuration
.terraformrc
terraform.rc
# Variable files with secrets
*.tfvars
!example.tfvars
# Lock file (some teams commit this, others don't)
# .terraform.lock.hcl
# Terraform cache
.terraform/
.terraform.lock.info
Commit làm gì
commit:
- Tệp cấu hình
*.tf *.tfvars.examplevới các biến ví dụ- Tài liệu
README.md - Mã mô-đun
- Kịch bản tự động hóa
Đừng commit:
- Các tệp
*.tfstatetrạng thái - Tệp
*.tfvarscó giá trị thực - Thông tin xác thực hoặc khóa API
- Thư mục
.terraform/
Tệp biến ví dụ
Cung cấp một ví dụ cho thấy những biến nào là cần thiết:
# terraform.tfvars.example
aws_region = "us-east-1"
environment = "production"
instance_type = "t3.large"
database_password = "CHANGE_ME"
allowed_ssh_cidrs = ["YOUR_IP/32"]
Các thành viên trong nhóm sao chép mã này vào terraform.tfvars và điền vào các giá trị thực (không phải là đã commit).
Quy trình làm việc nhóm
Thiết lập quy trình làm việc để cộng tác an toàn:
Quy trình làm việc pull request
- Tạo nhánh để thay đổi cơ sở hạ tầng
- Thực hiện thay đổi sang cấu hình Terraform
- Run
terraform planvà lưu kết quả đầu ra - Tạo yêu cầu kéo với đầu ra kế hoạch
- Nhóm đánh giá những thay đổi
- Merge sau khi được phê duyệt
- Apply những thay đổi trong nhánh chính
Tự động hóa việc này với CI/CD:
# .github/workflows/terraform.yml
name: Terraform
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.6.5
- name: Terraform Init
run: terraform init
working-directory: environments/prod
- name: Terraform Format
run: terraform fmt -check
working-directory: environments/prod
- name: Terraform Validate
run: terraform validate
working-directory: environments/prod
- name: Terraform Plan
if: github.event_name == 'pull_request'
run: terraform plan -no-color
working-directory: environments/prod
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve
working-directory: environments/prod
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Quy trình công việc này:
- Chạy
plantrên pull request (thay đổi bản xem trước) - Chạy
applykhi hợp nhất vào chính (áp dụng các thay đổi) - Hiển thị các thay đổi về cơ sở hạ tầng trong pull request
- Yêu cầu phê duyệt trước khi thay đổi xảy ra
Các phương pháp hay nhất về khóa trạng thái
Không bao giờ ép buộc mở khóa trừ khi cần thiết. Hãy kiểm tra với đội trước.
Keep áp dụng short. Chạy lâu áp dụng khóa giữ lâu hơn.
Sử dụng không gian làm việc hoặc thư mục riêng cho các môi trường để tránh xung đột khóa.
Giám sát ổ khóa bị kẹt. Nếu máy tính xách tay của ai đó bị hỏng giữa chừng, hãy mở khóa theo cách thủ công.
Kiểm soát truy cập
Kiểm soát ai có thể sửa đổi cơ sở hạ tầng:
Chính sách IAM của AWS
Tạo chính sách IAM cho Terraform:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::mycompany-terraform-state"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::mycompany-terraform-state/*"
},
{
"Effect": "Allow",
"Action": [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem"
],
"Resource": "arn:aws:dynamodb:us-east-1:*:table/terraform-locks"
}
]
}
Đính kèm phần này với người dùng IAM hoặc vai trò chạy Terraform.
Đối với production, hãy sử dụng các vai trò IAM riêng biệt với các quyền chặt chẽ hơn và yêu cầu MFA.
Nhóm đám mây Terraform
Terraform Cloud cung cấp khả năng kiểm soát truy cập theo nhóm:
- Read: Xem lượt chạy và trạng thái
- Plan: Chạy kế hoạch nhưng không áp dụng
- Write: Chạy kế hoạch và áp dụng
- Admin: Quản lý cài đặt không gian làm việc
Chỉ định các thành viên trong nhóm quyền thích hợp dựa trên vai trò của họ.
Di chuyển trạng thái giữa backend
Chuyển từ một backend sang người khác rất đơn giản:
# Change backend configuration
terraform {
backend "s3" {
bucket = "new-bucket"
key = "terraform.tfstate"
region = "us-east-1"
}
}
Chạy init để di chuyển:
terraform init -migrate-state
Terraform sao chép trạng thái sang backend mới. Xác minh việc di chuyển:
terraform plan
Nếu kế hoạch không có thay đổi thì việc di chuyển đã thành công.
Xử lý dữ liệu nhạy cảm
Tệp trạng thái chứa thông tin nhạy cảm. Bảo vệ họ:
Encrypt trạng thái ở phần còn lại: Sử dụng mã hóa S3, mã hóa Azure hoặc Terraform Cloud (được mã hóa theo mặc định).
Encrypt trạng thái đang chuyển tiếp: Sử dụng HTTPS để truy cập S3/Azure/GCS.
Hạn chế truy cập: Sử dụng chính sách IAM để giới hạn người có thể đọc trạng thái.
Sử dụng các biến nhạy cảm: Đánh dấu các bí mật là nhạy cảm để chúng không xuất hiện trong nhật ký:
variable "database_password" {
type = string
sensitive = true
}
Xem xét quản lý bí mật bên ngoài: Lưu trữ bí mật trong AWS Secrets Manager, Vault hoặc tương tự:
data "aws_secretsmanager_secret_version" "db_password" {
secret_id = "prod/database/password"
}
resource "aws_db_instance" "main" {
password = data.aws_secretsmanager_secret_version.db_password.secret_string
# ...
}
Ví dụ thực tế: Hoàn tất thiết lập backend từ xa
Đây là ví dụ đầy đủ về S3 backend và quy trình làm việc của nhóm:
# bootstrap/main.tf - Run this once to create the backend
terraform {
required_version = "~> 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "terraform_state" {
bucket = "mycompany-terraform-state"
lifecycle {
prevent_destroy = true
}
}
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
}
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
output "s3_bucket_name" {
value = aws_s3_bucket.terraform_state.id
}
output "dynamodb_table_name" {
value = aws_dynamodb_table.terraform_locks.name
}
Sau khi tạo cơ sở hạ tầng backend, hãy định cấu hình nó trong mã Terraform chính của bạn:
# environments/prod/backend.tf
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
backend từ xa và quy trình làm việc nhóm phù hợp là những điều giúp Terraform khả thi để sử dụng production. Tiếp theo, chúng tôi sẽ đề cập đến các phương pháp và mẫu tốt nhất để duy trì các dự án Terraform quy mô lớn.