极狐Gitlab CI 的Terraform backend http管理
一 背景
Terraform是一款基础设施即代码的编排工具,可以使用代码定义和预建立基础设施,如GCE、AWS和Azure等平台。在使用Terraform管理基础设施的过程中,状态管理起着至关重要的作用。 Terraform状态用于源控Terraform管理的资源,如果丢失状态,Terraform将无法确定哪些资源已创建,将导致错误或重复创建资源。GitLab是一款基于Web的Git代码仓库管理工具,提供Git仓库管理、代码审查、CI/CD管道、安全脚本等功能。GitLab可以很好的与Terraform进行集成,用于管理Terraform的状态。本文主要介绍如何在GitLab中管理Terraform的状态。
Terraform在执行基础设施编排过程中,为实现团队合作,其重要的state文件需要与基础设施配置代码分离,存储在外部共享存储中,默认情况下,Terraform使用名为local的后端,它将状态存储为磁盘上的本地文件。您还可以配置本文档中包含的一个内置后端。其中一些后端类似于状态文件的普通远程磁盘,而其他后端则支持在执行操作时锁定状态。这有助于防止冲突和不一致。
二 原理及功能
极狐Gitlab提供一个 Terraform HTTP 后端,以最少的配置安全地存储state文件。
在极狐GitLab 中,可以:
- 版本化的 Terraform 状态文件。
- 加密传输中和静止时的状态文件。
- 锁定和解锁状态。
- 远程执行
terraform plan
和terraform apply
命令。
三 实现
在极狐Gitlab的CI/CD中运行terraform
命令,在具体要实现的Terraform项目中,在backend.tf
文件中定义HTTP后端:
terraform {
backend "http" {
}
}
在项目内编写.gitlab-ci.yml
在其stage中执行terraform 命令
配置http 类型terraform后端状态
PROJECT_ID="<gitlab-project-id>"
TF_USERNAME="<gitlab-username>"
TF_PASSWORD="<gitlab-personal-access-token>"
TF_ADDRESS="https://jihu.com/api/v4/projects/${PROJECT_ID}/terraform/state"
terraform init \
-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
配置完成后在后续基础设施执行编排过程后,可以在具体项目的基础设施->Terraform 中看到State状态文件。
四 实战
预知条件,在仓库上已经注册了gitlab runner,后期Gitlab CI/CD可以直接使用。
可以将源码仓库与Terraform State存储放在同一个仓库内
4.1 创建仓库token
创建对应权限的token,后期用于tf配置认证Gitlab进行state状态文件存储。
-iJh84Jy1bCyj4nu2vzS
4.2 配置变量
TENCENTCLOUD_SECRET_ID:为腾讯云密钥ID,用于编排腾讯云资源认证;
TENCENTCLOUD_SECRET_KEY:为腾讯云密钥KEY,用于编排腾讯云资源认证;
TF_ADDRESS:为极狐Gitlab的state认证地址,(https://jihu.com/api/v4/projects/111969/terraform/state)
TF_USERNAME:为极狐Gitlab的state认证用户名;
TF_PASSWORD:为极狐Gitlab的state认证token;
4.3 代码
- .gitlab-ci.yml
variables:
# PHASE: BUILD|DESTROY
PHASE: BUILD
REGION: "ap-beijing"
PLAN_JSON: plan.json
before_script:
- apk add --no-cache jq
- export TENCENTCLOUD_SECRET_KEY=${TENCENTCLOUD_SECRET_KEY}
- export TENCENTCLOUD_SECRET_ID=${TENCENTCLOUD_SECRET_ID}
- export TF_REGISTRY_CLIENT_TIMEOUT=120000
- export CHECKPOINT_TIMEOUT=500000
- export TF_REGISTRY_DISCOVERY_RETRY=5
- alias convert_report="jq -r '([.resource_changes[]?.change.actions?]|flatten)|{\"create\":(map(select(.==\"create\"))|length),\"update\":(map(select(.==\"update\"))|length),\"delete\":(map(select(.==\"delete\"))|length)}'"
- terraform init -backend-config=address=${TF_ADDRESS} -backend-config=username=${TF_USERNAME} -backend-config=password=${TF_PASSWORD} -backend-config=lock_address=${TF_ADDRESS}/lock -backend-config=unlock_address=${TF_ADDRESS}/lock -backend-config=lock_method=POST
# 配置缓存
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- .terraform/
stages:
- init
- validate
- plan
- deploy
Init:
image:
name: hashicorp/terraform:1.3.7
entrypoint: [""]
stage: init
retry:
max: 1
when:
- script_failure
tags:
- gitlab-runner
script:
- terraform version
- terraform init -backend-config=address=${TF_ADDRESS} -backend-config=username=${TF_USERNAME} -backend-config=password=${TF_PASSWORD}
# -backend-config=lock_address=${TF_ADDRESS}/lock \
# -backend-config=unlock_address=${TF_ADDRESS}/lock \
# -backend-config=lock_method=POST \
# -backend-config=unlock_method=DELETE \
# -backend-config=retry_wait_min=5
Validate:
image:
name: hashicorp/terraform:1.3.7
entrypoint: [""]
stage: validate
tags:
- gitlab-runner
retry: 2
script:
- terraform validate
- terraform fmt -check -recursive || echo 0
cache:
paths:
- .terraform/
policy: pull
allow_failure: true
Plan:
image:
name: hashicorp/terraform:1.3.7
entrypoint: [""]
stage: plan
retry: 2
tags:
- gitlab-runner
cache:
paths:
- .terraform/
policy: pull
artifacts:
paths:
- plan.bin
- app_config.zip
expire_in: 2 week
script:
- terraform plan -input=false -out=plan.bin -var region=${REGION}
- terraform show --json "plan.bin" | convert_report > ${PLAN_JSON}
- cat ${PLAN_JSON}
only:
variables:
- $PHASE == "BUILD"
Apply:
image:
name: hashicorp/terraform:1.3.7
entrypoint: [""]
when: manual
stage: deploy
cache:
paths:
- .terraform/
retry: 2
tags:
- gitlab-runner
script:
- terraform apply -auto-approve -input=false
only:
variables:
- $PHASE == "BUILD"
Destroy:
image:
name: hashicorp/terraform:1.3.7
entrypoint: [""]
stage: deploy
cache:
paths:
- .terraform/
retry: 2
tags:
- gitlab-runner
script:
- terraform destroy -auto-approve -var region=${REGION}
only:
variables:
- $PHASE == "DESTROY"
provider "tencentcloud" {
region = var.region
}
terraform {
required_providers {
tencentcloud = {
source = "registry.terraform.io/tencentcloudstack/tencentcloud"
version = ">=1.61.5"
}
}
backend "http" {}
}
variable "region" {
type = string
default = "ap-beijing"
}
//data "tencentcloud_instances" "cvm" {
//}
locals {
cidr_block_vpc_name = "10.0.0.0/16"
}
resource "tencentcloud_vpc" "sampletfvpc" {
cidr_block = local.cidr_block_vpc_name
name = "sampletfvpc"
}
output "result" {
value = {
// cvm_result = { for k, v in data.tencentcloud_instances.cvm : k => v },
// count = data.tencentcloud_instances.cvm.instance_list[*]
vpc = {for k,v in tencentcloud_vpc.sampletfvpc :k=>v}
}
}
4.4 查看流水线
推送代码至Gitlab后,查看流实现CI/CD
查看plan
手动apply进行资源 编排
查看编排云资源
4.5 State文件
可以使用web页面进行后端state管理,也可以通过API进行操作。
五 其他
同样的可以使用极狐Gitlab后端 作为terraform的远端数据源,使用 data.terraform_remote_state.example.outputs.<OUTPUT-NAME>
在 Terraform 资源中引用数据源的输出。
在CI/CD流程中使用cache进行provider相关文件缓存,方便后续工作流快速高效运行。
六 总结
通过在GitLab CI中集成Terraform并使用HTTP backend管理状态,可以实现对Terraform基础设施编排的CI/CD。但同时也带来了一定的挑战
- Terraform server作为单点故障,其可用性直接影响GitLab CI中Terraform作业。需要考虑高可用方案。
- Terraform状态安全性直接决定基础设施的安全,需要严格控制对Terraform server的访问权限。
- Terraform exec模块的使用会使环境变得难以重现。需要考虑使用Packer等工具来标准化环境。
- 大规模环境的管理可能导致Terraform server性能瓶颈,需要测试环境大小与Terraform server配置的匹配性。
- 与其他CI工具的集成还需要深入研究。例如,支持从Jenkins或CircleCI中调用Terraform HTTP API。
总之,使用HTTP backend可以很好的在GitLab CI中管理Terraform状态在单独使用Gitlab CI不失为一个比较优选的解决方案,另外有待进一步改进的是提高Terraform server的可靠性、严密控制其安全性和改进Terraform状态API的实现。
参考链接
- 点赞
- 收藏
- 关注作者
评论(0)