存量资源管理

更新时间:2025-01-10 03:32:29

本文介绍如何使用 Terraform 及其配套工具解决存量云资源管理的难题。

背景介绍

Terraform作为IaC领域的重要工具,已经成为自动化管理云上资源的重要手段。对于新增的资源,直接编写Terraform代码并执行命令即可完成资源的自动化创建;对于存量的资源或者非Terraform创建的资源,需要借助一种资源导出的机制,导出生成资源代码和状态文件,进而通过Terraform来持续管理。

Terraform基于资源代码定义实现了资源创建、变更、删除等操作,借助资源导出能力,可以将那些游离在Terraform管理体系之外的云资源进行统一纳管。

image

使用场景

资源导出机制在资源管理和部署的很多场景都能得到很好的应用。

  1. 管理存量资源:将非Terraform(如控制台、API、CLI或者其他管理工具)管理的资源快速切换为Terraform的管理方式

  2. 解决资源漂移:使用Terraform管理的资源,当出现资源漂移问题(通过非Terraform的方式修改了资源,导致资源状态发生了变化)时,可以通过重新导出来修复

  3. 代码重构:所有资源都定义在一个模板中,想要对原有模板进行重构拆分,以降低随着资源不断增多而带来的模板和state的管理复杂度

  4. 快速部署:将现有资源部署架构在不同地域或者不同账号下进行快速复制和部署

  5. 快速恢复:定期备份现有资源架构,当现有资源架构出现稳定性问题时,可以基于备份代码实现快速恢复

操作步骤

本文提供了三种不同的资源导出的方式:

  1. Import 命令:通过Terraform原生的命令terraform import实现单个资源的快速导入。

  2. Import 代码:编写Terraform import 代码并执行terraform planterraform apply实现单个或者多个资源的快速导出。

  3. Terraformer工具:通过执行开源工具Terraformer命令批量过滤和查询资源,并实现自动导出

以上三种方式在不同的使用场景中各有不同,您可根据自身场景需要进行选择。

导出方式

优势

不足

适用场景

Import 命令

  • 简单直接,执行Terraform原生命令即可

  • 自动生成状态文件

  • 需手动获取资源ID,易出错

  • 单次导入只支持单资源,效率较低

  • 需要手动补齐资源代码

管理存量资源

解决资源漂移

代码重构

Import 代码

  • 操作简单,执行Terraform原生命令即可

  • 支持多资源的批量导出

  • 代码编写可实现较复杂的导入逻辑

  • 需编写导出代码,有一定的学习成本

  • 无法生成多资源间的依赖关系

  • 批量导入资源的配置成本较高

管理存量资源

解决资源漂移

代码重构

快速部署

Terraformer

  • 自动过滤并筛选所要导出的资源集合

  • 自动生成Terraform资源代码

  • 自动生成资源间的依赖关系

  • 需要下载并安装Terraformer

  • Terraform命令,有一定的学习和配置成本

管理存量资源

解决资源漂移

代码重构

快速部署

快速恢复

Terraform Import命令

terraform import命令通过指定资源地址资源 ID 实现导入,同时还支持了若干配置参数

环境准备

  • 准备 Terraform 运行环境。您可以选择以下任一方式来使用

    • Cloud Shell:阿里云Cloud Shell中预装了Terraform的组件,并已配置好身份凭证,您可直接在Cloud Shell中运行Terraform的命令。适用于低成本、快速、便捷地访问和使用Terraform的场景。

    • 在本地安装和配置Terraform:适用于网络连接较差或需要自定义开发环境的场景。

  • 需要为当前账号授予相关资源的只读权限

用法

命令格式为terraform import [配置参数] <资源地址> <资源ID>

  • 资源地址:格式为 <资源类型>.<资源名称>包含资源类型和名称,为基础设施在状态文件中的标识。

    • 例如以下模板片段中的 VPC 的资源地址为 alicloud_vpc.default

    resource "alicloud_vpc" "default" {
      vpc_name   = "tf-example"
      cidr_block = "10.0.0.0/8"
    }
  • 资源ID:资源 ID 为请求服务端信息的入参,可以定位到一个唯一的资源。资源 ID 的格式可以参考每个资源的 Provider 文档,获取详细信息。

    • 例如资源alicloud_security_group,其资源 ID 为安全组 ID;而安全组规则alicloud_security_group_rule的资源 ID 则遵循特定格式。

    image.png

  • 配置参数:terraform 还提供了很多配置参数用于 import 命令,详细可参考官网使用说明

示例

下面展示如何导入一个对象存储实例:

  1. 创建一个工作目录,并在目录下创建名为 main.tf 的配置文件,在其中定义将要导入的资源地址

    resource "alicloud_oss_bucket" "default"{ }
  2. 确定资源 ID,通过 alicloud_oss_bucket 得到其 ID 为 bucket 名称

  3. 初始化运行环境

    terraform init
  4. 执行 import 导入命令

    # 此处替换为自己的 bucket 名称
    terraform import alicloud_oss_bucket.default oss-bucket-import

    返回以下信息即为导入成功:

    alicloud_oss_bucket.default: Importing from ID "oss-bucket-import"...
    alicloud_oss_bucket.default: Import prepared!
      Prepared alicloud_oss_bucket for import
    alicloud_oss_bucket.default: Refreshing state... [id=oss-bucket-import]
    
    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.
    
  5. terraform import 导入后,属性不会自动填充到模板中,还需要手工补齐,执行 terraform show可以查看当前资源的所有属性:

    # alicloud_oss_bucket.default:
    resource "alicloud_oss_bucket" "default" {
        acl               = "private"
        bucket            = "oss-bucket-import"
        creation_date     = "2024-11-22"
        extranet_endpoint = "oss-cn-beijing.aliyuncs.com"
        id                = "oss-bucket-import"
        intranet_endpoint = "oss-cn-beijing-internal.aliyuncs.com"
        location          = "oss-cn-beijing"
        owner             = "1511928*****"
        redundancy_type   = "ZRS"
        resource_group_id = "rg-acf***"
        storage_class     = "Standard"
        tags              = {}
    
        access_monitor {
            status = "Disabled"
        }
    }

    将以上信息补充到您的模板中,再根据 alicloud_oss_bucket 中的信息,去掉只读属性,就可以通过 Terraform 来进行资源的管理了。

Terraform Import代码

Terraform 从 V1.5.0 版本起支持了使用 import block 的方式进行导入。您可以在模板中编写 import block,规定要导入的资源 id 和 资源地址,通过 terraform planterraform apply命令可对导入结果进行预览和执行。

官方文档参考:https://developer.hashicorp.com/terraform/language/import

环境准备

  • 准备 Terraform 运行环境。您可以选择以下任一方式来使用

    说明

    当前命令要求 Terraform 版本在 v1.5.0 以上,在环境配置时请注意切换到可用版本。

    • Cloud Shell:阿里云Cloud Shell中预装了Terraform的组件,并已配置好身份凭证,您可直接在Cloud Shell中运行Terraform的命令。适用于低成本、快速、便捷地访问和使用Terraform的场景。

    • 在本地安装和配置Terraform:适用于网络连接较差或需要自定义开发环境的场景。

  • 需要为当前账号授予相关资源的只读权限

用法

其语法格式为:

import {
  to = alicloud_oss_bucket.example
  id = "oss-bucket-import"
}

# 可选
# resource "alicloud_oss_bucket" "example" {
#   # (other resource arguments...)
# }

相较于 import 命令,import block 有如下两个优势:

  1. 自动生成模板文件。您可以将资源导入一个在模板中已定义好的资源地址中,也可以使用参数-generate-config-out自动生成,省去了模板填充的成本。

  2. 批量导入。在 import 块中可以通过for_each实现批量资源的导入,在资源属性一致的情况下,可以将其导入到同一个资源地址中进行管理,通过下标加以区分。

说明

需要注意的是,以上两个特性不能同时使用。Terraform CLI 暂不支持对使用了for_each的资源自动生成模板。image.png

示例

下面展示如何使用 import block 导入一个对象存储实例:

  1. 创建一个工作目录,并在目录下创建名为 main.tf 的配置文件,编写 import block 确定要导入的资源 ID 和地址

    import {
      to = alicloud_oss_bucket.default
      id = "oss-bucket-import"
    }
  2. 初始化运行环境

    terraform init
  3. 执行 terraform plan命令,预览将要导入的资源模板,使用-generate-config-out参数自动生成模板

    terraform plan -generate-config-out=generated.tf

    执行后将展示以下信息:

    alicloud_oss_bucket.default: Preparing import... [id=oss-bucket-import]
    alicloud_oss_bucket.default: Refreshing state... [id=oss-bucket-import]
    
    Terraform will perform the following actions:
    
      # alicloud_oss_bucket.default will be imported
      # (config will be generated)
        resource "alicloud_oss_bucket" "default" {
            acl               = "private"
            bucket            = "oss-bucket-import"
            creation_date     = "2024-11-22"
            extranet_endpoint = "oss-cn-beijing.aliyuncs.com"
            id                = "oss-bucket-import"
            intranet_endpoint = "oss-cn-beijing-internal.aliyuncs.com"
            location          = "oss-cn-beijing"
            owner             = "15119****"
            redundancy_type   = "ZRS"
            resource_group_id = "rg-acfmzaq*****"
            storage_class     = "Standard"
            tags              = {}
    
            access_monitor {
                status = "Disabled"
            }
        }
    
    Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
    ╷
    │ Warning: Config generation is experimental
    │ 
    │ Generating configuration during import is currently experimental, and the generated configuration
    │ format may change in future versions.
    ╵
    
    ─────────────────────────────────────────────────────────────────────────────────────────────────────
    
    Terraform has generated configuration and written it to generated.tf. Please review the configuration
    and edit it as necessary before adding it to version control.
    
    Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly
    these actions if you run "terraform apply" now.
  4. 确认后,执行 terraform apply命令执行导入

    terraform apply 

    根据提示输入 yes 后返回以下结果即为导入成功:

    ......
    
    Do you want to perform these actions?
      Terraform will perform the actions described above.
      Only 'yes' will be accepted to approve.
    
      Enter a value: yes
    
    alicloud_oss_bucket.default: Importing... [id=oss-bucket-import]
    alicloud_oss_bucket.default: Import complete [id=oss-bucket-import]
    
    Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.

Terraformer 工具

除 Terraform 原生功能外,还可以使用开源导出工具 Terraformer,快速、批量地将账号下的资源导出为 Terraform 模板。开源 Terraformer 中只对各个云厂商的部分资源做了支持,各厂商还需进行二次开发,对齐各自 Provider 支持的资源。

Terraformer工具有两种使用方式:

  1. 开源 Terraformer:原生Terraformer,支持对多个云厂商的导出

  2. 阿里云 Terraformer:基于原生Terraformer增强的面向阿里云导出工具,只支持对阿里云资源的导出。

功能点

开源 Terraformer

阿里云 Terraformer

查看支持导出的产品列表

查看支持导出的资源类型列表

Region维度过滤

Region维度反向过滤(即排除指定的Region)

按可用区维度过滤

按可用区维度反向过滤(即排除指定的可用区)

按产品维度过滤

按产品维度反向过滤(即排除指定的产品)

按资源类型过滤

按资源类型反向过滤(即排除指定的资源类型)

按资源ID列表过滤

按资源ID列表反向过滤(即排除指定的资源ID)

按资源名称过滤

按资源组过滤

按标签过滤

自动建立资源依赖关系

自动导出变量variables

自动导出出参outputs

开源 Terraformer

环境准备
  1. 下载和安装

    开源 Terraformer 发布包中既包含了针对所有 Provider 的包,又针对每个 Provider 提供了一个单独的包,您可根据自己的需要进行下载。此处展示了 Linux 以及 Mac 用户下载的方式,更多方式可参考 Installation

    • Linux 用户

    export PROVIDER=all
    curl -LO "https://github.com/GoogleCloudPlatform/terraformer/releases/download/$(curl -s https://api.github.com/repos/GoogleCloudPlatform/terraformer/releases/latest | grep tag_name | cut -d '"' -f 4)/terraformer-${PROVIDER}-linux-amd64"
    chmod +x terraformer-${PROVIDER}-linux-amd64
    sudo mv terraformer-${PROVIDER}-linux-amd64 /usr/local/bin/terraformer
    • MacOS 用户

    export PROVIDER=all
    curl -LO "https://github.com/GoogleCloudPlatform/terraformer/releases/download/$(curl -s https://api.github.com/repos/GoogleCloudPlatform/terraformer/releases/latest | grep tag_name | cut -d '"' -f 4)/terraformer-${PROVIDER}-darwin-amd64"
    chmod +x terraformer-${PROVIDER}-darwin-amd64
    sudo mv terraformer-${PROVIDER}-darwin-amd64 /usr/local/bin/terraformer
  2. 依赖条件

    1. 需要为当前账号授予相关资源的只读权限

    2. 安装 Terraform

      详细步骤可参考入门文档:在本地安装和配置Terraform。若在 Cloud Shell 中执行可省略这一步

    3. 下载相关的 Provider,可通过以下两种方式配置

      1. 在运行 Terraformer 命令的目录下初始化 Provider

      2. 将 Provider 下载到~/.terraform.d/plugins/路径下

    4. 配置访问凭证:目前只支持读取本地 profile 这一种认证方式,默认会使用第一个凭证进行导入。配置阿里云访问凭证可参考 配置凭证

用法

以 terraformer-all-darwin-amd64 v0.8.24 版本为例。

共支持了四个命令:help、import、plan、version

  1. help:查看当前命令详情

    image.png

  2. version:查看当前版本

    image.png

  3. import:提供针对各个 Provider 的导入功能

    image.png

  4. plan:提供针对各个 Provider 导入的预览功能

示例

以导出杭州区域下所有的阿里云 VPC 为例:

  1. 创建一个目录用来存放导入后的模板和状态文件

    mkdir example && cd example
  2. 执行以下命令

    terraformer-all-darwin-arm64 import alicloud --resources=vpc --regions=cn-hangzhou --path-pattern={output} --path-output=./     
    • --resources:指定要导出的资源集合

    • --regions:指定资源所在地域

    • --path-pattern:导出的目录模式

    • --path-output:导出的文件路径

  3. 导出后的模板文件如下所示,导出的目录上会默认加上地域信息。若需要将所有资源模板压缩到一个文件中,可指定 --compact参数,将资源都输出到 resources.tf

    └── cn-hangzhou
        ├── outputs.tf
        ├── provider.tf
        ├── terraform.tfstate
        ├── variables.tf
        ├── vpc.tf
        └── vswitch.tf
    
    2 directories, 6 files
  4. 若您本地的 Terraform 版本>=0.13.0,您需要执行以下命令来对状态文件进行修改以适配新版本 Terraform

    terraform state replace-provider -auto-approve "registry.terraform.io/-/alicloud" "aliyun/alicloud"

阿里云 Terraformer - aliterraformer(推荐)

基于开源 Terraformer,我们对更多资源进行了支持。并在访问凭证的配置、导出维度功能上进行了增强优化。

环境准备
  1. 下载和安装

    目前 aliterraformer 存储在阿里云的OSS上,可按照如下的地址进行下载:

    # Mac
    wget https://terraform-share.oss-cn-hangzhou.aliyuncs.com/aliterraformer/aliterraformer_darwin_amd64.zip
    
    # Linux
    wget https://terraform-share.oss-cn-hangzhou.aliyuncs.com/aliterraformer/aliterraformer_linux_amd64.zip

    下载之后,解压文件:

    unzip aliterraformer_darwin_amd64.zip
    chmod +x aliterraformer
    sudo mv aliterraformer /usr/local/bin/aliterraformer
  2. 依赖条件

    与开源 Terraformer 相同,也需要准备 terraform 和 terraform-provider-alicloud 这两个文件,并配置访问控制的配置。

    1. 为 RAM 账号授予相关资源的只读权限

    2. 安装 Terraform

      详细步骤可参考入门文档:在本地安装和配置Terraform。若在 Cloud Shell 中执行可省略这一步

    3. 下载 terraform-provider-alicloud

      通过以下方式可设置导出模板的 Provider 版本,执行 init 后的缓存目录在 v0.13.0 前后的结构不同,此处展示 v0.13.0 版本之后的读取方式

      # 1. 通过环境变量 TF_DATA_TFER_DIR 来设置
      <$TF_DATA_TFER_DIR>/providers/registry.terraform.io/aliyun/alicloud/1.239.0/darwin_arm64/terraform-provider-alicloud_v1.239.0
      
      # 2. 设置在当前工作目录下的隐藏目录
      .terraform/providers/registry.terraform.io/aliyun/alicloud/1.239.0/darwin_arm64/terraform-provider-alicloud_v1.239.0
      
      # 3. 设置在用户根目录下的隐藏目录
      <HOME>/.terraform.d/plugins/registry.terraform.io/aliyun/alicloud/1.239.0/darwin_arm64/terraform-provider-alicloud_v1.239.0
    4. 配置访问凭证

      aliterraformer 在 profile 的基础上支持了通过环境变量和命令参数的方式设置访问凭证:

      # 1. 通过环境变量 ALICLOUD_ACCESS_KEY 和 ALICLOUD_SECRET_KEY
      $ export ALICLOUD_ACCESS_KEY=xxxx
      $ export ALICLOUD_SECRET_KEY=xxxxx
      
      # 2. 通过 aliterraformer 命令参数 --access-key 和 --secret-key 传递
      $ aliterraformer import alicloud --access-key=xxxx --secret-key=xxx ...
      
      # 3. 通过 profile 机制来设置AK并传递,具体 Profile 的配置,详见:https://help.aliyun.com/document_detail/121258.html。
      $ aliterraformer import alicloud --profile=default ...
用法

aliterraformer 目前共支持了五个命令:help,version,products,resources,import。在开源 Terraformer 的基础上增加了 products、resources 两个命令

  1. help:查看当前支持的命令详情

    aliterraformer help

    image.png

  2. version:查看当前的 terraformer 版本

    aliterraformer version
  3. products:查看当前版本支持导出的产品列表

    aliterraformer products

    image.png

  4. resources:查看当前版本某一产品下支持导出的资源列表,通过 -p 指定

    aliterraformer resources -p <productName>

    image.png

    image.png

  5. import:执行具体的导入。阿里云资源需要指定 alicloud,通过以下命令可查看阿里云资源导入支持的参数:

    aliterraformer import alicloud -h

    image.png

    import 时需要先确定需要导出的资源集合,再按需通过 filter 对资源进行过滤、通过 output-variables 变量将属性抽取为参数

    • 构建资源集合:

      当前命令提供了四个 flag:<--products>、<--resources>、<--excludes-products>、<--excludes> 来指定要导出的资源,通过对其进行组合可以便利地构造出资源集合。用法示例如下:

      • 导出指定的资源

        # 导出 vpc、vswitch、ECS 实例
        aliterraformer import alicloud -r=vpc,vswitch,instance
      • 导出指定的产品

        # 导出 ACK、ALB 产品下所有资源
        aliterraformer import alicloud --products=ACK,ALB
      • 导出指定的产品及资源

        # 导出 ACK、ECS 产品下所有资源以及所有 vpc、vswitch
        aliterraformer import alicloud --products=ACK,ECS -r=vpc,vswitch
      • 导出指定的产品,排除产品下部分资源

        # 导出 ACK 下除 alicloud_cs_kubernetes 外所有资源
        aliterraformer import alicloud --products=ACK --excludes=cs_kubernetes
      • 导出所有产品下的所有资源

        # products 输入 ALL 代表所有的产品
        aliterraformer import alicloud --products=ALL
      • 导出所有产品下所有资源,排除指定的部分产品

        # 导出除 VPNGateway,WAF 外的所有产品
        aliterraformer import alicloud --products=ALL --excludes-products=VPNGateway,WAF
      • 导出所有产品下所有资源,排除指定的部分产品及部分资源

        # 导出除 VPNGateway,WAF 外的所有产品,排除 alicloud_cs_kubernetes 资源
        aliterraformer import alicloud --products=ALL --excludes-products=VPNGateway,WAF --excludes=cs_kubernetes
    • 通过 filter 对资源进行过滤

      此参数的格式为 --filter=Type1.AttrKey=AttrValue1;AttrValue2,Type2.AttrKey=AttrValue1;AttrValue2,Type 若缺省,此过滤条件对所有资源生效

      • 导出 vpc id为 vpc-123 的专有网络

        # 若指定多个,用分号进行分割:--filter="vpc.id=vpc-123;vpc-456"
        aliterraformer import alicloud -r=vpc --filter="vpc.id=vpc-123"
      • 导出名称均为 tf-example 的 vpc 和 vswitch

        aliterraformer import alicloud -r=vpc,vswitch --filter="vpc.vpc_name=tf-example,vswitch.vswitch_name=tf-example"
      • 导出资源组均为rg-12345的 vpc、ecs 实例

        aliterraformer import alicloud -r=vpc,instance --filter="resource_group_id=rg-12345"
    • 通过 output-variables 指定将属性抽取为参数变量

      当前命令的格式为r1:attr1,attr2;r2:attr1,attr2,attr3

      • 指定将 ECS 实例中 vpc_id、vswitch_id 抽取为变量

        aliterraformer import alicloud -r=instance --output-variables="instance:vpc_id,vswitch_id"
示例

下面展示如何导入杭州区域下id 为vpc-12345的 VPC、VSwitch 和 ECS 实例,并将交换机的 zone_id 抽取为变量:

  1. 创建一个目录用来存放导入后的模板和状态文件

    mkdir example && cd example
  2. 构造导出命令

    aliterraformer import alicloud \
        --regions=cn-hangzhou \
        -r=vpc,vswitch,instance \
        --filter="vpc.id=vpc-12345,vswitch.vpc_id=vpc-12345,instance.vpc_id=vpc-12345" \
        --output-variables="vswitch:zone_id" \
        --path-output=example               \
        --path-pattern={output}            \
        --compact
    • --path-output: 指定导出的文件夹

    • --path-pattern:导出资源模板的目录结构格式,默认格式{output}/{provider}/{service}/,可选格式还有{output}/{provider}/以及{output}/。例如指定 --path-pattern={output}代表将所有模板平铺到一个文件夹下

    • --compact:不指定时资源将按照{service}.tf分开存放,指定后统一存放到resources.tf

  3. 执行导出,在 example 目录生成了如下文件

    .
    ├── outputs.tf
    ├── provider.tf
    ├── resources.tf
    ├── terraform.tfstate
    └── variables.tf

    若不指定--path-pattern={output},目录结构如下所示:

    .
    └── alicloud
        ├── instance
        │   ├── provider.tf
        │   ├── terraform.tfstate
        │   └── variables.tf
        ├── vpc
        │   ├── outputs.tf
        │   ├── provider.tf
        │   ├── terraform.tfstate
        │   ├── variables.tf
        │   └── vpc.tf
        └── vswitch
            ├── outputs.tf
            ├── provider.tf
            ├── terraform.tfstate
            ├── variables.tf
            └── vswitch.tf
  4. 若您本地的 Terraform 版本>=0.13.0,您需要执行以下命令来对状态文件进行修改以适配新版本 Terraform

    terraform state replace-provider -auto-approve "registry.terraform.io/-/alicloud" "aliyun/alicloud"

反馈建议

如果您在使用教程或实践过程中有任何问题或建议,可以加入客户钉钉群(钉钉群号:34240022836)与我们的工程师在线交流,也可以直接在阿里云Terraform Provider Github中提交Issue,将有专人跟进您的问题和建议。

image

  • 本页导读 (1)
  • 背景介绍
  • 使用场景
  • 操作步骤
  • Terraform Import命令
  • Terraform Import代码
  • Terraformer 工具
  • 反馈建议