
作者 | 何貴民 阿裡雲開放平台進階開發工程師 主要負責開源生态工具(Terraform,Ansible,Spinnaker)與阿裡雲的內建,專注于借助主流開源工具幫助企業上阿裡雲和雲上運維提效。
摘要
開源生态工具Terraform通過簡單的用戶端指令即可實作對阿裡雲資源的建立,更改和删除等操作,但對于很多以非Terraform建立的雲資源,是否有辦法統一管理呢?本文将向你揭秘如何使用Terraform Import指令來實作對存量雲資源的導入和統一管理。
前兩篇文章《
一分鐘部署阿裡雲ECS叢集》和《
五分鐘入門阿裡雲Terraform OSS Backend》分别向大家詳細介紹了Terraform的一些基本概念,用法和State的工作原理。通過這兩篇的介紹,相信大家一定可以感受到Terraform 在資源編排,多雲管理,團隊協作,簡單易用等方面的優勢,在持續提升企業上雲效率,降低運維成本等方面的強大能力。本文将繼續向大家介紹Terraform的一個進階功能-Terraform Import。
在開始閱讀本文之前,先介紹四種運維場景:
場景一:我是Terraform的新人,從來沒有使用Terraform管控過任何資源,目前所有的存量雲資源都是通過控制台,阿裡雲CLI,ROS或者直接調用API建立和管理的,現在想要切換為Terraform,如何實作對這些存量資源的管理?
場景二:我們團隊所有的雲資源都是通過Terraform來管理的,某一天團隊的新人通過控制台對其中某個雲資源做了屬性變更,導緻原有的資源狀态State不一緻,該如何處理?
場景三:我的所有資源都定義在一個模闆中,随着資源數的不斷增多,模闆和state的管理複雜度也在持續增大,現在想要對原有模闆進行重構,将其進行拆分,如何在不影響資源正常使用的前提下實作?
場景四:阿裡雲的Provider進行了相容性更新,新版Provider對原有模闆中所定義的資源支援了更多的參數,如何把新加入的參數值同步進來?
面對以上四種甚至更多類似的場景,在閱讀完本文後,都可以找到對應的解決方案。
Terraform基于資源模闆定義不僅可以實作對新資源的建立,變更,删除等操作,還可以通過簡單的指令将那些遊離在Terraform管理體系之外的雲資源進行導入和納管,進而實作對所有雲資源的統一管理。
1 Terraform 導入存量資源
Terraform對資源的導入可以分為三個部分:
-
擷取資源ID
基于資源ID查詢資源并擷取其屬性;
-
模闆聲明所要導入的資源
模闆驅動,即使是要導入的資源,也需要在模闆中進行聲明;
-
補齊資源模闆定義
導入成功後,需要根據資源屬性補齊已經在模闆中聲明的資源定義。
接下來,将詳細介紹以上三個部分。
1.1 擷取資源ID
在Terraform中,每個被管理的資源有且僅有一個資源ID。Terraform對模闆中所定義的資源完成建立之後,都會将所建立的資源ID存儲到
Terraform State
中,并通過資源ID來精确地實作對特定資源的查找,變更,删除等持續地管理操作。
阿裡雲Provider所産生的資源ID通常有兩種格式:阿裡雲後端系統自動生成的ID和阿裡雲Provider生成的ID。大部分的資源ID都屬于前一種,即每個資源在通過阿裡雲API完成建立之後,系統都會自動生成一個資源的唯一辨別符,Provider會将其直接作為資源ID儲存在State檔案中。第二種格式通常出現在資源關系所對應的
resource
中,如磁盤挂載
alicloud_disk_attachment
,EIP的綁定
alicloud_eip_association
等,這類資源的ID都是通過關系兩端的資源ID和特殊字元
:
拼接起來的。在阿裡雲每個Resource文檔最後的
Attribute Reference
部分都會顯示目前資源的ID及其格式描述。
對資源ID的擷取可以通過Web控制台,CLI,API等多種方式,最簡單的方式是通過Terraform的DataSource,輸入簡單的查詢條件,如擷取一個負載均衡執行個體:
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",
]
1.2 模闆聲明所要導入的資源
和建立資源一樣,在導入資源前,也需要在模闆中進行資源聲明,以便指定所要導入的資源在State中的存放路徑。如下所示,聲明一個負載均衡執行個體:
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.
1.3 補齊資源模闆定義
由于模闆中沒有完成對所導入資源的詳細定義,是以,資源導入成功後,模闆内容與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.
可以看到,此時已經沒有任何需要變更的資訊。至此完成了對一個資源的完整導入。
2 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檔案中移除,并不會将其真正删除,這也正是為後續的導入操作做好了鋪墊。
3 回顧使用場景
在閱讀完前面兩部分的内容後,再來回顧文章開始提到的四種場景,相信大家都已經找到了答案,本文做一個小結:
場景一的解決方案:不論是Terraform的新手還是“老司機”,都可以通過
terraform import
指令來完成對存量資源的導入,進而使用Terraform統一管理。
場景二的解決方案:在确定清楚參數屬性的具體值之後,如果以模闆參數值為準,那麼隻需要運作
apply
指令再變更回來即可;如果以控制台的值為準,那麼隻需要補充/修改模闆參數值即可。
場景三的解決方案:可以先通過
terraform state rm
指令将所有需要重組的資源移出State,等模闆重構結束後,再使用
terraform import
将其導入即可。
場景四的解決方案:和上一解決方案一樣,通過“先移出再導入”調整一番即可。
4 寫在最後
從如上的操作可以看出,Terraform的指令非常靈活和簡單,基于模闆和State一緻性的原理,借助Terraform Import 可以輕松地實作對存量資源的統一管理,不用再擔心那些遊離在Terraform管理體系之外資源無法管理的痛點,也無需懼怕某個資源從State中移除後無法繼續管理的問題,所有的雲資源都可以被Terraform統一管理起來,感興趣的同學趕快動手試試吧。