身為處理基礎設施即代碼(IaC)的軟體專業人士,您很可能經常與Terraform打交道。在協助新客戶使用IaC時,簡化流程是常見做法,但管理Terraform狀態檔案卻是您面臨的首要挑戰。實質上,Terraform狀態包含了敏感資訊,不應存放於原始碼控制中,但若有多位使用者共用同一Terraform狀態,則此方法亦難以擴展。解決之道?後端服務。
值得注意的是,您可以將狀態檔案存於S3桶,並利用DynamoDB管理鎖定狀態。然而,此法將迫使您建立額外資源,使其成為複雜選項,尤其是當客戶使用GitLab時。GitLab近期降低了整合Terraform的門檻,提供了儲存與管理Terraform狀態的方法,以及簡便的CI設置方式。
本文將說明何謂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 apply。這是另一個原因,為何我們不會看到由版本控制管理的狀態檔案。
如何在GitLab上管理Terraform狀態
隨著Terraform被視為雲基礎設施配置的標準,GitLab自一年前開始提供存儲和管理Terraform狀態的方法。因此,我們想與您分享遷移過程,因為我們最近開始使用GitLab來管理我們的IaC。
本文假設您正在使用本地狀態,並且您的狀態由AWS S3 Bucket或其他後端解決方案管理。
首先,您需要將backend.tf
更改為使用HTTP:
terraform {
backend "http" {}
}
接下來,您需要在終端中設置四個變量:
1. PROJECT_ID
:您可以通過導航到“項目概覽”頁面上的您的repo輕鬆找到此信息。
2. TF_USERNAME
:具有訪問您正在工作的repo權限的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計劃。若非如此,您將需要透過GraphQL API 請求來操作。
如何在CI管線中讓GitLab執行您的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中定義新資源時,它會提供成本估算。
結論
在GitLab上運行Terraform狀態和CI是遵循GitOps最佳實踐的絕佳方式。這兩者結合起來,非常適合開發和部署基礎設施即代碼(IaC)。鑒於大多數人可能已經在使用GitLab管理代碼庫,將IaC整合在同一平台下,並讓GitLab通過支持傳輸中和靜態加密、版本控制、狀態鎖定和解鎖來管理您的Terraform狀態,變得更加簡單。
Source:
https://dzone.com/articles/how-to-migrate-terraform-state-to-gitlab-cicd