
# 通过Terraform一键部署CCI在线应用
#### 应用场景
Terraform是一个开源的IT基础设施编排管理工具，通过Terraform您可以轻松的创建、更新、删除华为云资源。部署CCI在线应用，用户除了需要部署业务容器，还要配置对应的网络资源和负载均衡资源。基于Terraform工具，用户可以自动化创建、更新和删除CCI实例、网络配置、负载均衡资源，并且Terraform可以自动处理资源之间的依赖关系，确保资源按正确的顺序创建和更新，一键部署应用。
 #### 示例说明
本文以Nginx镜像为例创建无状态工作负载，通过Poolbinding对象将容器实例自动更新至弹性负载均衡ELB服务后端服务器组的后端，实现Nginx应用发布和公网访问的目标。通过Terraform实现Nginx应用发布的过程，涉及创建的资源和依赖关系如下图所示。
![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002482475885.png "点击放大")
本文示例涉及的外部参数包括用户自定义参数和依赖其它云服务资源提供的参数，详细参数说明如[表1]和[表2]所示。
 表1用户自定义参数说明 
| 参数名称                   | 参数说明                                                                      |
|:---|:---|
| ns_name                | 创建的命名空间名称，示例中默认值为"tf-ns"，用户可自定义。                                          |
| network_name           | 创建的network名称，示例中默认值为"tf-network"，用户可自定义。                                  |
| project_id             | 项目ID，详情请参见<https://support.huaweicloud.com/usermanual-ca/ca_01_0001.html> |
| domain_id              | 账号ID，详情请参见<https://support.huaweicloud.com/usermanual-ca/ca_01_0001.html> |
| deploy_name            | 创建的deployment名称，示例中默认值为"tf-deploy"，用户可自定义。                                |
| replica                | 创建的deployment副本数，示例中默认值为1，用户可自定义。                                         |
| image_address          | 创建的deployment容器镜像地址，示例中为容器镜像服务SWR镜像中Nginx镜像地址。                            |
| pool_binding_name      | 创建的poolbinding名称，示例中默认值为"tf-binding"，用户可自定义。                              |
| container_port         | 创建的deployment容器开放的端口，示例中采用Nginx镜像，默认80。该参数与容器镜像对应，如果配置错误，会导致访问异常。         |
| vpc_name               | 创建的vpc名称，示例中默认值为"tf-cci-vpc"，用户可自定义。                                      |
| subnet_name            | 创建的subnet名称，示例中默认值为"tf-cci-subnet"，用户可自定义。                                |
| sg_name                | 创建的安全组名称，示例中默认值为"tf-sg"，用户可自定义。                                           |
| bandwidth_name         | 创建的带宽名称，示例中默认值为"tf-bandwidth"，用户可自定义。                                     |
| elb_name               | 创建的elb名称，示例中默认值为"tf-elb"，用户可自定义。                                          |
| listener_name          | 创建的listener名称，示例中默认值为"tf-listener"，用户可自定义。                                |
| pool_name              | 创建的pool名称，示例中默认值为"tf-pool"，用户可自定义。                                        |
| listener_protocol_port | 创建的listener监控端口，示例中默认值为"8080" ，用户可自定义。                                    |
   
 表2其它云服务资源参数说明 
| 参数名称                 | 参数说明                                                                         |
|:---|:---|
| swr_vpcep_service_id | swr终端节点服务ID，获取方式请参见[通过Terraform查询资源]。     |
| obs_vpcep_service_id | obs终端节点服务ID，请向OBS服务提交工单获取。                                                   |
| l4_flavor_id         | 弹性负载均衡配置的4层规格ID，获取方式请参见[通过Terraform查询资源]。 |
| l7_flavor_id         | 弹性负载均衡配置的7层规格ID，获取方式请参见[通过Terraform查询资源]。 |
   
#### 前置条件
已安装配置Terraform。为了降低密钥泄露的风险，下文示例配置Terraform认证鉴权采用环境变量的方式，执行Terraform相关命令会自动获取凭据相关的环境变量，故操作步骤中不涉及静态凭据配置。
![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
下文Terraform资源及参数说明，仅包含本文示例涉及的资源及参数，更多关于Terraform支持的华为云资源使用方式详见【[terraform-provider-huaweicloud](https://github.com/huaweicloud/terraform-provider-huaweicloud)】。
#### 操作步骤
1. 创建工作项目。 
   根据[示例说明]中相关资源和创建流程图，创建如下关系的工作目录和文件。
   ```
   demo
   |- main.tf
   |- variables.tf
   |- outputs.tf
   |- vpc
   |  |- main.tf
   |  |- variables.tf
   |  |- outputs.tf
   |- elb
   |  |- main.tf
   |  |- variables.tf
   |  |- outputs.tf
   |- cci
      |- main.tf
      |- variables.tf
      |- outputs.tf(optional)
   ```
   - demo：项目名称，用户可自定义。
   
   - main.tf：provider和各模块声明。
   
   - variables.tf：各模块资源所使用的参数声明。
   
   - outputs.tf：各模块资源或表达式关系值的输出声明。
   
   - vpc：网络子模块文件，其中包含main.tf、variables.tf和outputs.tf。
   
   - elb：弹性负载均衡子模块文件，其中包含main.tf、variables.tf和outputs.tf。
   
   - cci：云容器实例子模块文件，其中包含main.tf、variables.tf和outputs.tf，其中outputs.tf可选，因为本示例不涉及，用户可自定义CCI资源输出信息。
   
   
   创建完成后的工作目录和文件如下：
   ![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002449653820.png "点击放大")
   
   
2. 编写网络子模块（vpc）配置文件。 
   1. 编写main.tf文件，创建虚拟私有云（VPC）、子网（Subnet）、VPCEP（包含SWR VPCEP和OBS VPCEP）、安全组（SecurityGroups）、安全组规则（SecurityGroup Rule）和弹性公网IP（EIP）。
      ```
      terraform {
        required_providers {
          huaweicloud = {
            source  = "huaweicloud/huaweicloud"
            version = ">= 1.36.0"
          }
        }
      }
      # 1.创建VPC。
      resource "huaweicloud_vpc" "vpc" {
        name = var.vpc_name        # VPC名称，作为变量输入。
        cidr = "172.16.0.0/16"     # VPC下可用子网的范围。
      }
      # 2.创建子网。
      resource "huaweicloud_vpc_subnet" "subnet" {
        name       = var.subnet_name            # 子网名称，作为变量输入。
        cidr       = "172.16.0.0/24"            # 子网的网段。
        gateway_ip = "172.16.0.1"               # 子网的网关，必须是ip格式。
        vpc_id     = huaweicloud_vpc.vpc.id     # 子网所在的VPC ID，即创建VPC所返回的ID。
      }
      # 3.创建SWR VPCEP和OBS VPCEP，根据SWR公共镜像仓库的实现，需要购买SWR VPCEP和OBS VPCEP，才能完成镜像拉取动作。
      resource "huaweicloud_vpcep_endpoint" "swr_vpcep" {
        service_id = var.swr_vpcep_service_id             # SWR终端节点服务的ID，作为变量输入。
        vpc_id     = huaweicloud_vpc.vpc.id               # 终端节点所在的VPC ID，即创建VPC所返回的ID。
        network_id = huaweicloud_vpc_subnet.subnet.id     # 需要指定vpc_id对应VPC下已创建的网络（network）的ID。
      }
      resource "huaweicloud_vpcep_endpoint" "obs_vpcep" {
        service_id = var.obs_vpcep_service_id      # OBS终端节点服务的ID，作为变量输入。
        vpc_id     = huaweicloud_vpc.vpc.id        # 终端节点所在的VPC ID，即创建VPC所返回的ID。
      }
      # 4.创建安全组。
      resource "huaweicloud_networking_secgroup" "secgroup" {
        name = var.sg_name    # 安全组名称，作为变量输入。
      }
      # 5.创建安全组入方向规则，出方向规则默认全放通，不单独配置。
      resource "huaweicloud_networking_secgroup_rule" "ingress" {
        security_group_id = huaweicloud_networking_secgroup.secgroup.id  # 安全组ID，即创建安全组所返回的ID。
        direction         = "ingress"                                    # 安全组规则入控制方向。
        ethertype         = "IPv4"                                       # IP地址协议类型。
        ports             = "1-65535"                                    # 端口。
        protocol          = "tcp"                                        # 协议类型。
      }
      # 6.创建弹性公网IP。
      resource "huaweicloud_vpc_eip" "eip" {
        publicip {
          type = "5_bgp"  # 弹性公网IP的类型。
        }
        bandwidth {
          share_type  = "PER"                # 带宽类型，PER为独占带宽。
          charge_mode = "traffic"            # 计费模式，traffic为按流量计费。
          size        = "5"                  # 带宽大小。
          name        = var.bandwidth_name   # 带宽名称，作为变量输入。
        }
      }
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      Terraform会根据创建资源的参数依赖关系，自动识别资源间的依赖关系，按顺序创建资源。例如创建子网时引用了VPC ID，最终创建资源时Terraform会先创建VPC，再创建子网。
      
   
   2. 编写variables.tf文件，配置网络子模块的输入变量。
      ```
      variable "vpc_name" {
        default = "tf-vpc"
      }
      variable "subnet_name" {}
      variable "swr_vpcep_service_id" {}
      variable "obs_vpcep_service_id" {}
      variable "sg_name" {}
      variable "bandwidth_name" {}
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      variables.tf中的变量即上一步中创建的资源参数中配置的变量，支持通过父模块传递值，若父模块未传递值，也可以配置使用默认值，如vpc_name。
      
   
   3. 编写outputs.tf文件，配置网络子模块中向上一级模块回传的输出变量。
      ```
      # 创建的子网IPv4 ID，创建CCI Network资源时引用。
      output "subnet_ipv4_id" {
        value = huaweicloud_vpc_subnet.subnet.ipv4_subnet_id
      }
      # 创建的安全组ID，创建CCI network资源时引用。
      output "sg_id" {
        value = huaweicloud_networking_secgroup.secgroup.id
      }
      # 创建的VPC ID，创建ELB资源时引用。
      output "vpc_id" {
        value = huaweicloud_vpc.vpc.id
      }
      # 创建的弹性公网IP ID，创建ELB资源时引用。
      output "eip_id" {
        value = huaweicloud_vpc_eip.eip.id
      }
      # 创建的弹性公网IP IPv4地址。
      output "eip_address" {
        value = huaweicloud_vpc_eip.eip.address
      }
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      子模块中的output定义表示向上一级模块回传值，最终可作为根模块需要打印在终端上的信息，同级子模块也可以引用回传的值。
      例：网络子模块上一级模块即为根模块，根模块outputs.tf文件引用输出变量后，执行应用，最终会在终端打印对应的信息。此外，网络子模块的输出变量，例如子网IPv4 ID，可以被云容器实例子模块引用，作为network资源对象的子网参数。
      
   
   
   
   
3. 编写弹性负载均衡子模块（elb）配置文件。 
   1. 编写main.tf文件，创建独享型负载均衡器（ELB）、监听器（Listener）、后端服务器组（Pool）。
      ```
      terraform {
        required_providers {
          huaweicloud = {
            source  = "huaweicloud/huaweicloud"
            version = ">= 1.36.0"
          }
        }
      }
      # 1.创建ELB。
      resource "huaweicloud_elb_loadbalancer" "elb" {
        name = var.elb_name     # ELB名称，作为变量输入。
        vpc_id         = var.vpc_id            # ELB所在的VPC ID，作为变量输入，即网络子模块创建的VPC ID。
        ipv4_subnet_id = var.ipv4_subnet_id    # ELB所在子网的IPv4子网ID，作为变量输入，即网络子模块创建的子网IPv4 ID。
        l4_flavor_id = var.l4_flavor_id    # 网络型规格ID，作为变量输入，可查询对应局点的flavor获取。
        l7_flavor_id = var.l7_flavor_id    # 应用型规格ID，作为变量输入，可查询对应局点的flavor获取。
        availability_zone = [    # ELB所在的可用区列表，为了支持可用区容灾，建议选取不少于2个可用区。
          "ap-southeast-3a",
          "ap-southeast-3b",
        ]
        ipv4_eip_id = var.eip_id    # ELB绑定的公网IP的ID，作为变量输入，即网络子模块创建的公网IP ID。
      }
      # 2.创建HTTP协议的监听器。
      resource "huaweicloud_elb_listener" "listener" {
        name            = var.listener_name                    # 监听器名称，作为变量输入。
        protocol        = "HTTP"                               # 监听器的监听协议。
        protocol_port   = var.listener_protocol_port           # 监听器的监听端口。
        loadbalancer_id = huaweicloud_elb_loadbalancer.elb.id  # 监听器所属的负载均衡器的ID，即创建ELB所返回的ID。
      }
      # 3.创建后端服务器组。
      resource "huaweicloud_elb_pool" "pool" {
        name        = var.pool_name                          # 后端服务器组名称，作为变量输入。
        protocol    = "HTTP"                                 # 后端服务器组的后端协议，创建的监听器为HTTP时，该参数必须为HTTP。
        lb_method   = "ROUND_ROBIN"                          # 后端服务器组的负载均衡算法，示例中使用加权轮询算法。
        listener_id = huaweicloud_elb_listener.listener.id   # 后端服务器组关联的监听器的ID，即创建监听器返回的ID。
        vpc_id      = var.vpc_id                             # 后端服务器组关联的虚拟私有云的ID，即网络子模块创建的VPC ID。
        type        = "instance"                             # 后端服务器组的类型，instance表示允许任意类型的后端。
      }
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      Terraform会根据创建资源的参数依赖关系，自动识别资源间的依赖关系，按顺序创建资源。例如创建ELB时引用了网络子模块的公网IP ID，最终创建资源时Terraform会先创建网络子模块的弹性公网IP，再创建弹性负载均衡子模块的ELB。
      
   
   2. 编写variables.tf文件，配置网络子模块的输入变量。
      ```
      variable "vpc_id" {}
      variable "ipv4_subnet_id" {}
      variable "elb_name" {}
      variable "l4_flavor_id" {}
      variable "l7_flavor_id" {}
      variable "eip_id" {}
      variable "listener_name" {}
      variable "pool_name" {}
      variable "listener_protocol_port" {}
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      variables.tf中的变量即[3.a]中创建的资源参数中配置的变量，支持通过父模块传递值，若父模块未传递值，也可以配置使用默认值。
      
   
   3. 编写outputs.tf文件，配置网络子模块中向上一级模块回传的输出变量。
      ```
      # 创建的后端服务器组ID，创建CCI poolbinding资源时引用。
      output "pool_id" {
        value = huaweicloud_elb_pool.pool.id
      }
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      子模块中的output定义表示向上一级模块回传值，最终可作为根模块需要打印在终端上的信息，同级子模块也可以引用回传的值。
      例：弹性负载均衡子模块上一级模块即为根模块，根模块outputs.tf文件引用输出变量后，执行应用，最终会在终端打印对应的信息。此外，弹性负载均衡子模块的输出变量，例如后端服务器组ID，可以被云容器实例子模块引用，作为poolbinding资源对象的子网参数。
      
   
   
   
   
4. 云容器实例子模块（cci）配置文件编写。 
   1. 编写main.tf文件，创建命名空间（namespace）、network、负载（deployment）和poolbinding。
      ```
      terraform {
        required_providers {
          huaweicloud = {
            source  = "huaweicloud/huaweicloud"
            version = ">= 1.36.0"
          }
        }
      }
      # 1.创建namespace。
      resource "huaweicloud_cciv2_namespace" "ns" {
        name = var.ns_name  # namespace名称，作为变量输入。
      }
      # 2.创建network。
      resource "huaweicloud_cciv2_network" "network" {
        name      = var.network_name  # network名称，作为变量输入
        namespace = var.ns_name       # network所在namespace名称，作为变量输入。
        annotations = {
          "yangtse.io/project-id" = var.project_id  # 项目ID，作为变量输入。
          "yangtse.io/domain-id"  = var.domain_id   # 账号ID，作为变量输入。
        }
        subnets {
          subnet_id = var.subnet_ipv4_id  # 子网IPv4 ID，作为变量输入，即网络子模块创建的子网IPv4 ID。
        }
        security_group_ids = var.sg_ids  # 安全组ID，即网络子模块创建的安全组ID。
        # 显示声明和namespace的依赖关系
        depends_on = [huaweicloud_cciv2_namespace.ns]
      }
      # 3.创建deployment。
      resource "huaweicloud_cciv2_deployment" "deploy" {
        namespace = var.ns_name       # deployment所在namespace的名称，作为变量输入。
        name      = var.deploy_name   # deployment的名称，作为变量输入。
        replicas  = var.replica       # deployment的副本数，作为变量输入。
        selector {
          match_labels = {
            app = var.deploy_name    # 指定selector的labels，用户可自定义，作为变量输入。
          }
        }
        template {
          metadata {
            labels = {
              app = var.deploy_name  # 指定labels，用户可自定义，作为变量输入。
            }
          }
          spec {
            containers {
              name  = "container1"
              image = var.image_address  # 容器镜像地址，用户可自定义，本示例使用Nginx镜像，作为变量输入。
              resources {
                limits = {
                  cpu    = "1"
                  memory = "2G"
                }
                requests = {
                  cpu    = "1"
                  memory = "2G"
                }
              }
            }
            image_pull_secrets {
              name = "imagepull-secret"
            }
          }
        }
        # 显示声明和network的依赖关系
        depends_on = [huaweicloud_cciv2_network.network]
      }
      # 4.创建poolbinding，后端关联创建的deployment。
      resource "huaweicloud_cciv2_pool_binding" "binding" {
        name      = var.pool_binding_name  # poolbinding名称，作为变量输入。
        namespace = var.ns_name            # poolbinding所在namespace名称，作为变量输入。
        pool_ref {
          id = var.pool_id  # 关联的ELB后端服务器组ID，作为变量输入，即弹性负载均衡子模块创建的后端服务器组ID。
        }
        target_ref {
          group     = "cci/v2"            # 关联的后端对象group。
          kind      = "Deployment"        # 关联的后端对象类型。
          name      = var.deploy_name     # 关联的后端对象deployment名称，作为变量输入。
          namespace = var.ns_name         # 关联的后端对象所在namespace名称，作为变量输入。
          port      = var.container_port  # 关联的后端对象目标端口号，即开放的容器端口，作为变量输入。
        }
        # 显示声明和Deployment的依赖关系
        depends_on = [huaweicloud_cciv2_deployment.deploy]
      }
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      Terraform会根据创建资源的参数依赖关系，自动识别资源间的依赖关系，按顺序创建资源。如果两个资源存在依赖关系且无隐性依赖关系，可通过在资源中声明**depends_on** 来为某个特性资源指定依赖，使其创建时间点位于被依赖资源之后。例如network的创建需要在namespace之后，但是创建network时参数中不涉及对创建的namespace资源的参数引用，因此通过声明**depends_on**显示指定network和namespace的依赖关系。
      
   
   2. 编写variables.tf文件，配置云容器实例子模块的输入变量。
      ```
      variable "ns_name" {}
      variable "network_name" {}
      variable "project_id" {}
      variable "domain_id" {}
      variable "sg_ids" {
        type = list(string)
      }
      variable "subnet_ipv4_id" {}
      variable "deploy_name" {}
      variable "replica" {
        type = number
      }
      variable "image_address" {}
      variable "pool_binding_name" {}
      variable "container_port" {}
      variable "pool_id" {}
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      variables.tf中的变量即[4.a]中创建的资源参数中配置的变量，支持通过父模块传递值，若父模块未传递值，也可以配置使用默认值。
      
   
   
   
   
5. 编写根模块配置文件。
   
   1. 编写main.tf文件，配置网络、弹性负载均衡和云容器实例子模块。
      ```
      terraform {
        required_providers {
          huaweicloud = {
            source  = "huaweicloud/huaweicloud"
            version = ">= 1.36.0"
          }
        }
      }
      # 云容器实例子模块。
      module "cci" {
        # 声明云容器实例子模块所在的路径。
        source = "./cci"  
        # 云容器实例子模块涉及的变量输入，引用根模块变量或者其它子模块输出值。
        ns_name           = var.ns_name
        network_name      = var.network_name
        sg_ids            = [module.vpc.sg_id]
        subnet_ipv4_id    = module.vpc.subnet_ipv4_id
        project_id        = var.project_id
        domain_id         = var.domain_id
        deploy_name       = var.deploy_name
        replica           = var.replica
        image_address     = var.image_address
        pool_binding_name = var.pool_binding_name
        pool_id           = module.elb.pool_id
        container_port    = var.container_port
        # 显示声明云容器实例子模块和弹性负载均衡子模块的依赖关系。
        depends_on = [module.elb]
      }
      # 网络子模块。
      module "vpc" {
        # 申明网络子模块所在的路径。
        source = "./vpc"
        # 网络子模块涉及的变量输入，引用根模块变量或者其它子模块输出值。
        vpc_name             = var.vpc_name
        subnet_name          = var.subnet_name
        swr_vpcep_service_id = var.swr_vpcep_service_id
        obs_vpcep_service_id = var.obs_vpcep_service_id
        sg_name              = var.sg_name
        bandwidth_name       = var.bandwidth_name
      }
      # 弹性负载均衡子模块。
      module "elb" {
        # 声明弹性负载均衡子模块的路径。
        source = "./elb"
        
        # 弹性负载均衡子模块涉及的变量输入，引用根模块变量或者其它子模块输出值。
        elb_name               = var.elb_name
        l4_flavor_id           = var.l4_flavor_id
        l7_flavor_id           = var.l7_flavor_id
        vpc_id                 = module.vpc.vpc_id
        ipv4_subnet_id         = module.vpc.subnet_ipv4_id
        listener_name          = var.listener_name
        pool_name              = var.pool_name
        eip_id                 = module.vpc.eip_id
        listener_protocol_port = var.listener_protocol_port
      }
      ```
      
   
   2. 编写variables.tf文件，配置根模块的输入变量。
      ```
      # 云容器实例子模块涉及的输入变量。
      # namespace名称。
      variable "ns_name" {
        default = "tf-ns"
      }
      # network名称。
      variable "network_name" {
        default = "tf-network"
      }
      # 用户项目ID。
      variable "project_id" {
        default = "0582xxxxxxxxxxxxxxxxxxxxxxxxdb94"
      }
      # 用户账号ID。
      variable "domain_id" {
        default = "0560xxxxxxxxxxxxxxxxxxxxxxxxa060"
      }
      # deployment名称。
      variable "deploy_name" {
        default = "tf-deploy"
      }
      # deployment副本数。
      variable "replica" {
        type = number
        default = "1"
      }
      # deployment容器镜像地址。
      variable "image_address" {
        default = "library/nginx:stable-alpine-perl"
      }
      # poolbinding名称。
      variable "pool_binding_name" {
        default = "tf-binding"
      }
      # deployment容器开放的端口，本文示例采用Nginx镜像，默认80端口。
      variable "container_port" {
        default = "80"
      }
      # 网络子模块涉及的输入变量。
      # vpc名称。
      variable "vpc_name" {
        default = "tf-cci-vpc"
      }
      # subnet名称。
      variable "subnet_name" {
        default = "tf-cci-subnet"
      }
      # swr终端节点服务ID。
      variable "swr_vpcep_service_id" {
        default = "005axxxx-xxxx-xxxx-xxxx-xxxx019eb5c6"
      }
      # obs终端节点服务ID。
      variable "obs_vpcep_service_id" {
        default = "a372xxxx-xxxx-xxxx-xxxx-xxxx8fb2e98f"
      }
      # 安全组名称。
      variable "sg_name" {
        default = "tf-sg"
      }
      # 带宽名称。
      variable "bandwidth_name" {
        default = "tf-bandwidth"
      }
      # 弹性负载均衡子模块涉及的输入变量。
      # 弹性负载均衡器名称。
      variable "elb_name" {
        default = "tf-elb"
      }
      # 弹性负载均衡配置的4层规格ID。
      variable "l4_flavor_id" {
        default = "7699xxxx-xxxx-xxxx-xxxx-xxxxf76a3dc4"
      }
      # 弹性负载均衡配置的7层规格ID。
      variable "l7_flavor_id" {
        default = "47b9xxxx-xxxx-xxxx-xxxx-xxxxd3e73e26"
      }
      # 监听器名称。
      variable "listener_name" {
        default = "tf-listener"
      }
      # 后端服务器组名称。
      variable "pool_name" {
        default = "tf-pool"
      }
      # 监听器的监听端口。
      variable "listener_protocol_port" {
        default = "8080"
      }
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      根模块variables.tf中的变量即子模块涉及的外部输入变量，通过父模块传递给子模块，示例中均配置了默认值，执行Terraform创建命令时，若未设置外部输入，直接使用默认值。
      
   
   3. 编写outputs.tf文件，配置终端输出变量，本文示例只显示弹性公网IP IPv4地址，用户可定义输出其它变量。
      ```
      # 弹性公网IP IPv4地址。
      output "eip_address" {
        value = module.vpc.eip_address
      }
      ```
      ![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/note_3.0-zh-cn.png)
      根模块中的output定义表示需要打印在终端上的信息。
      
   
   
   
   
6. 应用部署。 
   1. 在项目"demo"中执行如下命令初始化。
      ```
      terraform init
      ```
      回显如下，首次执行时会下载HuaweiCloud Provider并安装。
      ![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002449653828.png "点击放大")
      
   
   2. 在项目"demo"中执行如下命令查看要创建的资源。
      ```
      terraform plan
      ```
      回显如下，Terraform会显示要创建哪些资源。
      ![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002449494192.png "点击放大")
      
   
   3. 在项目"demo"中执行如下命令创建资源。
      ```
      terraform apply
      ```
      根据提示输入"yes"，回显如下，可以看到资源已经创建，您也可以到华为云控制台上查看资源是否已经创建。
      ![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002482693697.png "点击放大")
      
   
   4. 访问Nginx应用，根据资源创建后终端回显的弹性公网IP IPv4地址，构造curl命令。
      ```
      curl http://${eip_address}:${port}
      ```
      - eip_address：弹性公网IP IPv4地址，即创建资源后终端显示的地址。
      
      - port：监听器的监听端口，若未在创建资源时指定，即[5]配置在variables.tf中的默认值。
      
      
      回显如下，表明访问成功。
      ![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002482773713.png "点击放大")
      
   
   
   
   
7. 资源销毁。 
   执行如下命令销毁资源，默认释放所有资源。
   ```
   terraform destroy
   ```
   根据提示输入"yes"，回显如下，可以看到资源全部删除，您也可以到华为云控制台上查看资源是否已经清理。
   ![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002449653832.png "点击放大")
   
   
 
 #### 通过Terraform查询资源
Terraform支持资源查询，下文示例展示了用户如何通过Terraform命令查询SWR终端节点服务和弹性负载均衡服务支持的规格。
![](https://support.huaweicloud.com/bestpractice-cci2/public_sys-resources/caution_3.0-zh-cn.png)
如果Terraform查询的资源信息过多，直接输出到终端会不便于阅读和检索。为提高可用性，建议将查询结果重定向保存到本地。
1. 重新创建一个项目，例如命名为"demo2"，编写main.tf文件，内容如下所示。 
   ```
   terraform {
     required_providers {
       huaweicloud = {
         source = "huaweicloud/huaweicloud"
         version = ">= 1.20.0"
       }
     }
   }
   # 查询swr终端节点服务。
   data "huaweicloud_vpcep_public_services" "swr_service" {
     service_name = "swr"
   }
   # 在终端输出swr终端节点服务查询结果。
   output "swr_service" {
     value = data.huaweicloud_vpcep_public_services.swr_service
   }
   # 查询对应局点弹性负载均衡服务支持的规格。
   data "huaweicloud_elb_flavors" "flavors" {}
   # 在终端输出规格查询结果。
   output "all_flavors" {
     value = data.huaweicloud_elb_flavors.flavors
   }
   ```
   
   
2. 在项目"demo2"中执行如下命令初始化。 
   ```
   terraform init
   ```
   回显如下，首次执行时会下载HuaweiCloud Provider并安装。
   ![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002451417932.png "点击放大")
   
   
3. 在项目"demo2"中执行如下命令查询资源。 
   ```
   terraform apply
   ```
   回显如下，可以看到查询结果示例如下。其中，用户可根据需要自行选择对应的4层和7层规格ID。
   ![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002484657409.png "点击放大")
   ![](https://support.huaweicloud.com/bestpractice-cci2/zh-cn_image_0000002451577544.png "点击放大")
   
   
 
