本文將介紹Terraform的Backend機制及如何使用Terraform OSS Backend。
Terraform State簡介
Terraform State是用來存放基礎設施資源及其屬性和狀態的機制。Terraform State從儲存形態上分為兩種:
local:本機存放區
資源狀態存放在本地的一個state檔案中,預設為執行目錄下的名為terraform.tfstate檔案。此方式也是Terraform預設的儲存形式。
remote:遠端儲存
資源狀態存放在遠端的一個服務中,例如阿里雲的OSS Terraform Cloud,HashiCorp Consul等。遠端儲存帶來的好處是實現了與資源定義範本管理員的解耦,可以讓State脫離本地磁碟而儲存,在提升State安全性的同時,團隊協作可以不再受制於Terraform的執行環境、執行目錄和多人執行時間的限制,提升了管理的靈活性。
Terraform State的儲存是由一個稱之為Backend的組件決定的,local state使用的是local backend。除了local backend,其他所有的backend在使用之前都需要在模板中顯式定義並通過terraform init來實現載入和配置。
Terraform Backend簡介
Backend是儲存State的機制,它決定了State資料的載入邏輯和Terraform命令執行之後State的資料的更新過程。Terraform生命週期中與Backend的互動過程,如下圖所示。
Terraform通過init命令完成Backend的載入和配置。在執行plan和apply命令,載入資源模板的同時,通過Backend載入State中的存量資料(如果有),命令結束後,將Provider或Provisioner響應中的資料通過Backend更新到State中,最終達到State資料與模板定義的一致。
從功能實現層級的角度,Backend可以分為兩種:
Standard
State管理的標準化實現,覆蓋標準的功能點State儲存和State加鎖。這種Backend目前只適用於在本地系統上運行所有操作的情境,儘管也實現了對State的遠程儲存,但Backend的執行邏輯仍發生在本地並通過直接調用API請求來完成。
目前這種Backend總共有13種,阿里雲的OSS Backend也屬於此類。
Enhanced
可以看作是Standard的加強版,即Backend的執行邏輯不僅可以發生在本地,還可以通過API或者CLI的方式發生在遠端。目前這種Backend的種類有兩種,一是local,另一個是只支援Terraform Cloud的remote 。
阿里雲也提供了一個標準的Backend-oss ,在Terraform 0.12.2中予以支援,並在Terraform 0.12.6 和0.12.8版本中對OSS進行了升級,支援profile設定, ecs_role_name , assume_role等鑒權方式。
阿里雲OSS Backend詳解
OSS Backend是基於阿里雲的Table Store服務(Tablestore)和Object Storage Service服務(OSS)實現的Standard Backend,其中Tablestore用來儲存運行過程中產生的“Locking”,保證State的正確性和完整性;OSS用來儲存最終的State檔案。接下來將詳細介紹OSS Backend。
工作原理
OSS Backend的工作流程可以分為加鎖、儲存State、釋放鎖三步,下圖是一個簡單的工作流程圖:

主要包含以下幾個部分:
運行Terraform命令後,Backend首先會從Tablestore中擷取LockID,如果已經存在,表明State被損壞或者有人正在操作,返回報錯,否則,自動產生一個LockID並儲存在Tablestore中。
如果是init命令,初次會產生一個新的state檔案並儲存在OSS的特定目錄下,並釋放LockID。
如果是plan、apply、destroy等涉及到修改State的命令,會在命令結束後將最新的資料同步更新到State檔案中,並釋放LockID。
如果是 state、show 等不涉及修改的操作,會直接讀取State內容並返回。
模板定義
和Provider和Provisioner一樣,Backend在使用時同樣需要在模板中定義。Backend 通過關鍵字backend來聲明
如下代碼聲明了一個oss backend,其state儲存在名為terraform-oss-backend-1024的bucket中,對應的檔案為prod/terraform.tfstate,並聲明state檔案為唯讀和加密;鎖資訊儲存在一個名為terraform-oss-backend-1024的表格中,這個表格位於杭州的Tablestore執行個體tf-oss-backend中。
terraform { backend "oss" { profile = "terraform" bucket = "terraform-oss-backend-1024" key = "prod/terraform.tfstate" tablestore_endpoint = "https://tf-oss-backend.cn-hangzhou.Tablestore.aliyuncs.com" tablestore_table = "terraform-oss-backend-1024" acl = "private" encrypt = true ... } }對backend的定義包含如下幾個部分:
terraform為運行主體,定義了Backend的操作主體。Backend的邏輯實現是存放在Terraform倉庫中的,服務於所有Provider和Provisioner,因此它的運行主體是terraform ,而不是具體某個Provider。
oss 為Backend類型,用來標識一個特定的Backend。
大括弧裡面的內容為參數配置,用來定義Backend屬性,例如鑒權資訊,OSS Bucket的名稱,存放路徑,Tablestore配置資訊等。更多參數和含義可參考官方文檔:https://www.terraform.io/docs/backends/types/oss.html
一鍵產生OSS Backend模板
為了更快捷的編寫OSS Backend模板,阿里雲提供了一個Terraform Module:remote-backend
module "remote_state" { source = "terraform-alicloud-modules/remote-backend/alicloud" create_backend_bucket = true create_ots_lock_instance = true # 注意,為了避免OTS執行個體名稱的衝突,此處需要指定自己的OTS Instance名稱 # 如果指定的OTS Instance已經存在,那麼需要設定 create_ots_lock_instance = false backend_ots_lock_instance = "<your-ots-instance-name>" create_ots_lock_table = true # 注意,如果想要自訂OTS Table或者使用已經存在的Table,可以通過參數backend_ots_lock_table來指定 # 如果指定的OTS Table已經存在,那麼需要設定 create_ots_lock_table = false # backend_ots_lock_table = "<your-ots-table-name>" region = "cn-hangzhou" state_name = "prod/terraform.tfstate" encrypt_state = true }運行完成後,會在目前的目錄下產生一個名為terraform.tf的設定檔,檔案內容即為已經配置好的OSS Backend:
terraform { backend "oss" { bucket = "terraform-remote-backend-94a22ee-0714-e8ef-8573-21df8b021f86" prefix = "env:" key = "new/terraform.tfstate" acl = "private" region = "cn-hangzhou" encrypt = "true" tablestore_endpoint = "https://<your-ots-instance-name>.cn-hangzhou.Tablestore.aliyuncs.com" tablestore_table = "terraform_remote_backend_lock_table_38001042_0714_e8ef_8573_21df8b021f86" } }產生後的terraform.tf可以直接跟目標模板放在同一個目錄下,以用於後續State的遠端儲存。
如果想把產生terraform.tf的state也存放在上述的OSS Backend中,只需再次運行terraform init命令,本地目錄下的local state將會自動同步到OSS Backend中。