天天看點

一文揭秘存量雲資源的管理難題

一文揭秘存量雲資源的管理難題

作者 | 何貴民 阿裡雲開放平台進階開發工程師 主要負責開源生态工具(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統一管理起來,感興趣的同學趕快動手試試吧。

繼續閱讀