背景資訊
本文內容適用於以下四種營運情境:
- 情境一:長期使用控制台、阿里雲CLI、Resource Orchestration Service服務或者直接調用API建立和管理資源,初次使用Terraform的情境。
- 情境二:長期使用Terraform管理資源,如果通過控制台對單個雲資源做屬性變更,希望保持原有的資源狀態(State)一致的情境。
- 情境三:所有資源都定義在一個模板中,想要對原有模板進行重構拆分,以降低隨著資源不斷增多而帶來的模板和state的管理複雜度的情境。
- 情境四:想要將新版Provider中新增的參數同步到原文檔中的情境。
Terraform基於資源模板定義不僅可以實現對新資源的建立,變更,刪除等操作,還可以通過簡單的命令將那些游離在Terraform管理體系之外的雲資源進行匯入和納管,進而實現對所有雲資源的統一管理。
Terraform 匯入存量資源
Terraform對資源的匯入可以分為三個步驟:
- 擷取資源ID:
基於資源ID查詢資源並擷取其屬性。
- 模板聲明所要匯入的資源:
模板驅動,即使是要匯入的資源,也需要在模板中進行聲明。
- 補齊資源模板定義:
匯入成功後,需要根據資源屬性補齊已經在模板中聲明的資源定義。
- 擷取資源ID。
對資源ID的擷取可以通過Web控制台,CLI,API等多種方式,最簡單的方式是通過Terraform的DataSource,輸入簡單的查詢條件,例如擷取一個Server Load Balancer執行個體:
data "alicloud_slbs" "default" {
name_regex = "for-demo*"
}
output "slb_ids" {
value = data.alicloud_slbs.default.ids
}
運行
terraform apply 命令即可展示所有合格SLB的ID:
$ terraform apply
data.alicloud_slbs.default: Refreshing state...
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
slb_ids = [
"lb-gw8vinrqxxxxxxxxxxx",
"lb-gw8axostxxxxxxxxxxx",
]
- 模板聲明所要匯入的資源。
和建立資源一樣,在匯入資源前,也需要在模板中進行資源聲明,以便指定所要匯入的資源在State中的存放路徑。如下所示,聲明一個Server Load Balancer執行個體:
resource "alicloud_slb" "this" {}
簡單的聲明之後,無需定義具體的參數即可開始資源的匯入操作。在Terraform中,匯入一個資源的操作通過import命令來完成,完整的命令格式為
terraform import <資源類型>.<資源標識> <資源ID>
,詳細操作如下:
$ terraform import alicloud_slb.this lb-gw8vinrqxxxxxxxxxxx
alicloud_slb.this: Importing from ID "lb-gw8vinrqxxxxxxxxxxx"...
alicloud_slb.this: Import prepared!
Prepared alicloud_slb for import
alicloud_slb.this: Refreshing state... [id=lb-gw8vinrqxxxxxxxxxxx]
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
- 補齊資源模板定義。
由於模板中沒有完成對所匯入資源的詳細定義,因此,資源匯入成功後,模板內容與State儲存的內容存在差異,此時如果直接運行plan命令,將會看到一個update:
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
data.alicloud_slbs.default: Refreshing state...
alicloud_slb.this: Refreshing state... [id=lb-gw8vinrqxxxxxxxxxxx]
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# alicloud_slb.this will be updated in-place
~ resource "alicloud_slb" "this" {
address = "47.254.181.122"
...
~ delete_protection = "on" -> "off"
id = "id=lb-gw8vinrqxxxxxxxxxxx"
...
~ name = "for_demo-test" -> "tf-lb-20191108144235105700000001"
...
}
Plan: 0 to add, 1 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
為了保持資源模板與資源狀態的一致,需要在模板中手動補齊缺失的參數定義,直到運行plan不會再有變更資訊為止:
resource "alicloud_slb" "this" {
delete_protection = "on"
name = "for_demo-test"
}
所要補齊的內容主要以那些引起更新的欄位為主,補齊完成後運行terraform plan進行測試:
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
data.alicloud_slbs.default: Refreshing state...
alicloud_slb.this: Refreshing state... [id=lb-gw8vinrqtqx1ro1r94c96]
------------------------------------------------------------------------
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
可以看到,此時已經沒有任何需要變更的資訊。至此完成了對一個資源的完整匯入。
Terraform移除存量資源
在實際操作環境中,經常會遇到資源的誤匯入,匯入路徑不符,想要調整資源路徑,想要持續保留某資源等多種複雜情況。面對這些情況,整體的實現思路也是非常簡單:先將匯入後的資源從State中移除,然後重新匯入。
資源的移除操作可以通過
state rm命令來完成,完整的命令格式為
terraform state rm <資源類型>.<資源標識>
,詳細操作如下:
$ terraform state rm alicloud_slb.this
Removed alicloud_slb.this
Successfully removed 1 resource instance(s).
state rm命令只是將指定的資源從State檔案中移除,並不會將其真正刪除,這也正是為後續的匯入操作做好了鋪墊。
總結
對於以上四種情境我們可以使用以下解決方案:
- 情境一的解決方案:
通過terraform import命令來完成對存量資源的匯入,進而使用Terraform統一管理。
- 情境二的解決方案:
在確定清楚參數屬性的具體值之後,如果以模板參數值為準,那麼只需要運行apply命令再變更回來即可;如果以控制台的值為準,那麼只需要補充或修改模板參數值即可。
- 情境三的解決方案:
可以先通過terraform state rm命令將所有需要重組的資源移出State,等模板重構結束後,再使用terraform import將其匯入即可。
- 情境四的解決方案:
和上一解決方案一樣,通過“先移出再匯入”調整即可。
Terraform的命令非常靈活和簡單,基於模板和State一致性的原理,藉助terraform import可以輕鬆地實現對存量資源的統一管理,不用再擔心那些游離在Terraform管理體系之外資源無法管理的痛點,也無需懼怕某個資源從State中移除後無法繼續管理的問題,所有的雲資源都可以被Terraform統一管理起來。