全部產品
Search
文件中心

Terraform:如何解決存量雲資源的管理難題

更新時間:Jun 30, 2024

本文介紹如何使用Terraform解決存量雲資源管理難題。

背景資訊

本文內容適用於以下四種營運情境:
  • 情境一:長期使用控制台、阿里雲CLI、Resource Orchestration Service服務或者直接調用API建立和管理資源,初次使用Terraform的情境。
  • 情境二:長期使用Terraform管理資源,如果通過控制台對單個雲資源做屬性變更,希望保持原有的資源狀態(State)一致的情境。
  • 情境三:所有資源都定義在一個模板中,想要對原有模板進行重構拆分,以降低隨著資源不斷增多而帶來的模板和state的管理複雜度的情境。
  • 情境四:想要將新版Provider中新增的參數同步到原文檔中的情境。

Terraform基於資源模板定義不僅可以實現對新資源的建立,變更,刪除等操作,還可以通過簡單的命令將那些游離在Terraform管理體系之外的雲資源進行匯入和納管,進而實現對所有雲資源的統一管理。

Terraform 匯入存量資源

Terraform對資源的匯入可以分為三個步驟:
  1. 擷取資源ID:

    基於資源ID查詢資源並擷取其屬性。

  2. 模板聲明所要匯入的資源:

    模板驅動,即使是要匯入的資源,也需要在模板中進行聲明。

  3. 補齊資源模板定義:

    匯入成功後,需要根據資源屬性補齊已經在模板中聲明的資源定義。

  1. 擷取資源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",
    ]
  2. 模板聲明所要匯入的資源。
    和建立資源一樣,在匯入資源前,也需要在模板中進行資源聲明,以便指定所要匯入的資源在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.
  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.

    可以看到,此時已經沒有任何需要變更的資訊。至此完成了對一個資源的完整匯入。

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統一管理起來。