一、Terraform 状态文件
每次我们运行 Terraform 命令时,它都会在 Terraform 状态文件中记录关于它创建的基础设施资源的信息。默认情况下,会在您的当前工作目录下创建一个terraform.tfstate文件。该文件内容是一个JSON字符串。它记录了从Terraform 模板资源定义到云平台实际资源的映射。
例如:我们用 Terraform 模板定义一个EC2实例。
resource "aws_instance" "example" {
ami = "ami-061eb2b23f9f8839c"
instance_type = "t2.micro"
tags = {
Name = "Example by ChangSha DevOps Union"
Terraform = true
}
}
运行 terraform apply 之后,查看terraform.tfstate内容:
"instances": [
{
"index_key": 0,
"schema_version": 1,
"attributes": {
"ami": "ami-061eb2b23f9f8839c",
"associate_public_ip_address": true,
"availability_zone": "ap-southeast-1b",
"cpu_core_count": 1,
"cpu_threads_per_core": 1,
"id": "i-088137f4282ab6167",
"instance_state": "running",
"instance_type": "t2.micro"
...
}
}]
我们可以很清晰的从这个JSON字符串中了解到实际创建EC2的详细信息。例如:"id" : "i-088137f4282ab6167"。Terraform 在AWS创建了实例ID为 i-088137f4282ab6167 的EC2虚拟机,它的实例类型是 t2.micro(1 vCPUs,1g RAM)。
每次运行 Terraform命令,它会从AWS获取到到EC2的最新信息。并将其与 Terraform模板定义内容进行比较。以确定是否需要更改。如果有更改执行terraform plan 命令会进行高亮显示。执行 terraform apply 则会将更改生效。
二、Terraform 状态文件存储
如果只是你一个人使用Terraform,可以将状态文件存在本地。但是如果是一个团队使用Terraform。你需要考虑以下几个问题:
1、如何共享状态
团队成员维护同一个基础设施资源。每个成员都可能需要更新基础设施。那么必定需要访问相同的 Terraform状态文件。否则会以每个成员的Terraform模板创建各自的资源,产生多份状态文件。
2、如何锁定状态文件
一旦状态文件被共享,如果团队中多个成员同时运行Terraform。就会遇到指令竞争。因为多个Terraform命令会对状态文件进行并发更新。从而导致冲突,造成数据丢失和状态文件损坏。
3、如何隔离状态文件
我们可能有多个基础设施环境(dev/stg/prod)。如果在同一个环境构建基础设施,由于人为的失误删除了状态文件或者Terraform的一个罕见Bug,造成Terraform状态文件损坏。则会给线上环境造成不可挽救的破坏。
接下来,我们将深入讨论这些问题,并展示 Terraform提供的解决办法。
2.1、共享状态文件
共享状态文件,最常见的做法就是使用Git进行版本控制,但是这样做还是会有以下问题:
1、团队成员本地很难同时保存最新的Terraform模板和状态文件,如果其中一个成员忘记Pull最新的更改或者运行了Terraform命令,忘记Push最新的状态文件到版本控制,都会造成资源混乱。
2、状态文件包含敏感信息。Terraform构建资源,可能需要存放敏感数据。例如创建数据库,会将数据库用户名和密码以明文存在状态文件。
关于共享状态文件,Terraform提供了对远程状态存储的支持。如:Amazon S3。
Amazon S3存储支持版本控制,回滚,文件加密,而且还便宜。
resource "aws_s3_bucket" "terraform_state" {
bucket = "terraform-state-store"
versioning {
enabled = true
}
lifecycle {
prevent_destroy = true
}
tags = {
Name = "S3 Remote Terraform State Store"
}
}
terraform {
backend "s3" {
bucket = "terraform-state-store"
key = "example/terraform.tfstate"
region = "ap-southeast-1"
encrypt = true
}
}
2.2、锁定状态文件
使用远程状态存储(S3)可以解决多人共享状态文件的问题,但还是存在:
多人协作时在同一个状态文件同时执行terraform命令,产生指令竞争的情况。
Terraform支持Amazon DynamoDB锁定状态。DynamoDB会将Terraform状态存储路径和文件名称作为唯一主键ID进行锁定。每次在执行Terraform Apply 命令之前先从DynamoDB获取锁,执行完之后释放锁。
terraform {
backend "s3" {
bucket = "terraform-state-store"
key = "example/terraform.tfstate"
region = "ap-southeast-1"
encrypt = true
# 使用DynamoDB锁定状态
dynamodb_table = "dev-terraform-state-lock"
}
}
2.3、隔离状态文件
通过共享状态文件存储和状态文件锁定,多人协作不再是问题。但是,仍然存在另一个问题:环境隔离。你在dev环境做测试,但是不小心中断了操作或者Terraform某个Bug,损坏了状态文件。这将导致prod环境受到影响。
有两种方法可以隔离状态文件:
1、通过工作空间隔离
2、通过文件布局隔离
2.3.1、通过工作空间隔离
Terraform默认工作空间为:default
$ terraform workspace show
default
创建新的工作空间:dev 和 prod
$ terraform workspace new dev
Created and switched to workspace "dev"!
You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.
S3存储桶将会创建名为 env:的文件夹。env:文件夹里会分别创建dev和prod子目录
查询所有的工作空间
$ terraform workspace list
default
dev
* prod
通过 workspace select 命令来切换当前工作空间
$ terraform workspace select dev
Switched to workspace "dev".
$ terraform workspace list
default
* dev
prod
2.3.2、通过文件布局隔离
.
├── dev
│ ├── ec2
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ └── variables.tf
│ └── vpc
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
├── prod
│ ├── data-storage
│ │ ├── mysql
│ │ └── redis
│ ├── ec2
│ └── vpc
└── stg
文件布局隔离在此不再详细述说,大家可以对比一下工作空间布局和文件布局隔离的优劣。找到适合自己团队的方式。
如果您喜欢这篇文章,请考虑关注我。
长沙DevOps联盟 - 关注容器技术,K8S,自动化部署,基础设施架构。