作为一名处理基础设施即代码(IaC)的软件专业人士,你很可能经常与Terraform打交道。在帮助新客户采用IaC时,简化操作是常见做法,但管理Terraform状态文件却是你面临的首个挑战。本质上,Terraform状态包含敏感信息,不应存储在源代码控制中,但同时,如果多个用户共用同一Terraform状态,这种方式也无法扩展。解决方案呢?就是后端。
值得注意的是,你可以将状态文件存储在S3桶中,并使用DynamoDB来管理锁定状态。然而,这种方法会迫使你创建额外资源,使其成为一个复杂选项,尤其是当客户使用GitLab时。GitLab最近通过提供存储和管理Terraform状态的方法,以及轻松设置CI流程的方式,降低了集成Terraform的门槛。
本文将解释什么是Terraform状态文件,如何将其迁移到GitLab,以及如何为其设置CI管道。你可以访问我们的仓库这里。
目录
- Terraform状态是什么?
- 如何让GitLab管理Terraform状态
- 如何让GitLab通过CI管道运行你的IaC
- 额外提示:Infracost
- 总结
Terraform状态是什么?
Terraform通过状态文件记录了代码中定义的基础设施信息。该文件以JSON格式编写,本质上记录了从Terraform代码到实际创建的资源的映射。以下是一个terraform.tfstate
文件的示例。通常,每次运行Terraform时,它会获取EC2实例的最新状态,并与Terraform配置进行比较,以确定需要应用哪些更改:
{
"version": 4,
"terraform_version": "0.12.0",
"serial": 1,
"lineage": "1f2087f9-4b3c-1b66-65db-8b78faafc6fb",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "aws_instance",
"name": "example",
"provider": "provider.aws",
"instances": [
{
"schema_version": 1,
"attributes": {
"ami": "ami-0c55b159cbfafe1f0",
"availability_zone": "us-west-2a",
"id": "i-00a123a0accffffff",
"instance_state": "running",
"instance_type": "t2.micro",
"(...)": "(truncated)"
}
}
]
}
]
}
默认情况下,terraform.tfstate
存储在本地,即存放Terraform文件、计划和应用更改的位置。对于个人项目,仅进行一些测试时,这样做是可以的,但不推荐,原因如下:
- 存储于共享位置: 如果你将状态文件托管在本地工作站上,并与另一位工程师协作,情况会变得复杂。你们俩都必须确保使用的是状态的最新版本,如果同时运行Terraform计划或应用,可能会遇到竞态条件。
- 保护敏感信息: 生成的状态文件可能包含加密密钥和基础设施密码。然而,状态文件默认不加密,以明文形式存储敏感信息是不安全的。
- 锁定: 大多数版本控制系统不支持锁定机制,这会阻止两个团队成员同时对同一状态文件运行Terraform应用。这也是为什么我们不会看到由源代码控制管理的状态文件的另一个原因。
如何让GitLab管理Terraform状态
鉴于Terraform已成为云基础设施配置的标准,大约一年前,GitLab开始提供一种存储和管理Terraform状态的方法。因此,我们想与您分享迁移过程,因为我们最近开始使用GitLab来管理我们的基础设施即代码(IaC)。
本文假设您当前使用的是本地状态,并且您的状态由AWS S3 Bucket或其他后端解决方案管理。
首先,您需要修改backend.tf
以使用HTTP:
terraform {
backend "http" {}
}
接下来,您需要在终端中设置四个变量:
1. PROJECT_ID
:您可以轻松地在“项目概览”页面上导航到您的仓库来找到此ID。
2. TF_USERNAME
:有权访问您正在工作的仓库的GitLab用户名。
3. TF_PASSWORD
:从您的GitLab用户生成的访问令牌。
4. TF_ADDRESS
:远程状态后端的URL。
PROJECT_ID="28450092"
TF_USERNAME="florianpialoux"
TF_PASSWORD="123456789"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/aws-buckets"
现在,您可以运行迁移命令,将您的Terraform状态从先前的位置移动到GitLab,使用以下命令:
terraform init \
-migrate-state \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
您需要通过输入“是”来确认,以便GitLab可以开始管理您的状态文件。以下是从本地状态迁移到GitLab的示例:
从S3迁移到GitLab的示例:

I noticed for some of the state files I had from S3 will be blank even after using the migrate-state
command ran previously. In this case, you can run this:
terraform state pull > aws-buckets.json
复制并粘贴来自S3状态的内容,并运行推送:
terraform state push -lock=true aws-buckets.json
GitLab支持对Terraform状态文件进行版本控制,但通过WebUI查看或恢复旧版本的功能仅限于GitLab Premium计划用户。若非Premium用户,则需通过GraphQL API发起请求。
如何让GitLab通过CI管道运行您的IaC
GitLab提供一个Docker镜像,其中包含GitLab-Terraform,这是围绕官方Terraform二进制文件的轻量级包装脚本。此外,您也可以使用Hashicorp的官方Docker镜像。更多关于GitLab Terraform镜像的信息可在此查阅。
一旦Terraform apply作业运行,您将能够查看状态文件何时被使用以及对应哪个管道。
gitlab-ci.yml
looks like here. Below, are the variables that will need to be defined on the project level.额外提示:Infracost
如您所见,在我们的gitlab-ci.yaml
中添加了Infracost,它使我们能更精准地控制云账单,因为每当您在IaC中定义新资源时,它都会提供成本估算。
结论
将Terraform状态和CI运行在GitLab上,是遵循GitOps最佳实践的绝佳方式。这两者相得益彰,共同助力基础设施即代码(IaC)的开发与部署。鉴于多数用户可能已使用GitLab管理代码仓库,将IaC整合于一处则更为简便,让GitLab通过支持传输中与静态数据的加密、版本控制、状态锁定及解锁等功能,来管理您的Terraform状态。
Source:
https://dzone.com/articles/how-to-migrate-terraform-state-to-gitlab-cicd