通过Terraform实现IaC自动化部署事件总线

本文介绍如何应用IaC(Infrastructure as Code)理念自动化部署事件总线EventBridge,帮助您解决大量云产品手工管理负担沉重的问题。

背景信息

IaC是一种以代码来配置和管理虚拟机、网络等基础设施的实践方法。通过将基础设施代码化、版本化来取代传统的手工操作基础设施。传统的基础设施管理方法是人工手动处理模式,不仅效率低下,而且还有很多人为操作的风险。在IaC的实践中,开发者通过代码描述基础设施的配置及变更,再执行代码完成配置和变更,就可以在几分钟后得到所需的虚拟机、网络等云上的服务,极大地缩短了部署时间,同时还能够保证多个环境的配置一致性,减少人为操作,降低了引入错误的概率。

HashiCorp Terraform是一个IT基础架构自动化编排工具。作为最主流的IaC工具之一,它提供了强大的自动化管理基础设施的能力。Terraform的命令行接口(CLI)提供一种简单机制,用于将配置文件部署到阿里云或其他任意支持的云上,并对其进行版本控制。阿里云的大多数产品(包括事件总线EventBridge)都对Terraform进行支持,使得跨多云部署基础设施变得简单。更多信息,请参见Terraform产品介绍

本文以Terraform为例介绍两个基于IaC理念自动化部署基础设施的案例。

前提条件

  • 由于阿里云账号(主账号)具有资源的所有权限,一旦发生泄露将面临重大风险。建议您使用RAM用户,并为该RAM用户创建AccessKey,具体操作方式请参见创建RAM用户创建AccessKey

  • 为运行Terraform命令的RAM用户绑定以下最小权限策略,以获取管理本示例所涉及资源的权限。更多信息,请参见通过脚本编辑模式创建自定义权限策略

    该自定义权限策略允许RAM用户或角色对阿里云事件总线(EventBridge)和函数计算(Function Compute)服务进行全面管理和操作。

    {
      "Version": "1",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "eventbridge:CreateEventBus",
            "eventbridge:DeleteEventBus",
            "eventbridge:DescribeEventBus",
            "eventbridge:ListEventBuses",
            "eventbridge:PutRule",
            "eventbridge:DeleteRule",
            "eventbridge:DescribeRule",
            "eventbridge:ListRules",
            "eventbridge:PutTargets",
            "eventbridge:RemoveTargets",
            "eventbridge:ListTargetsByRule",
            "eventbridge:PutEvents",
            "eventbridge:PutPermission",
            "eventbridge:RemovePermission",
            "eventbridge:CreateEventSource",
            "eventbridge:DeleteEventSource",
            "eventbridge:DescribeEventSource",
            "eventbridge:ListEventSources"
          ],
          "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "ram:PassRole"
          ],
          "Resource": "*"
        },
        {
          "Effect": "Allow",
          "Action": [
            "fc:CreateService",
            "fc:DeleteService",
            "fc:UpdateService",
            "fc:DescribeService",
            "fc:ListServices",
            "fc:CreateFunction",
            "fc:DeleteFunction",
            "fc:UpdateFunction",
            "fc:InvokeFunction",
            "fc:DescribeFunction",
            "fc:ListFunctions"
          ],
          "Resource": "*"
        }
      ]
    }
  • 准备Terraform运行环境,您可以选择以下任一方式来使用Terraform。

    • Terraform Explorer中使用Terraform:阿里云提供了Terraform的在线运行环境,您无需安装Terraform,登录后即可在线使用和体验Terraform。适用于零成本、快速、便捷地体验和调试Terraform的场景。

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

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

使用的资源

  • alicloud_event_bridge_rule:资源允许您在阿里云事件总线中定义规则,以过滤和处理事件,并将它们发送到指定的目标,如函数计算、钉钉机器人等。

说明

当前场景示例代码支持一键运行,您可以直接运行代码。一键运行

场景一:通过钉钉监控云上资源状态变化

若您使用了大量云资源作为生产环境,传统的手工操作控制台方式虽然简单易操作,但是不能很好地感知云上资源的变更操作。使用事件总线EventBridge将事件的状态变更投递到钉钉,用户可以通过钉钉机器人的消息通知更加直观地感知云上资源的变更。此处以ActionTrail:ApiCall事件为例,为您演示使用Terraform工具将所有云产品事件源的ActionTrail:ApiCall事件投递给钉钉。

  1. 创建一个钉钉机器人,记录Webhook地址和密钥。详细操作,请参见钉钉官方文档

  2. 创建terraform.tf文件。Terraform可以通过此文件调用阿里云上的资源。

  3. 创建1_actiontrail2dingding.tf文件,声明一个default总线上的规则:audit_notify_fofo,通过后缀匹配的方式将所有云产品事件源的ActionTrail:ApiCall事件路由到钉钉上。

    # 定义变量
    variable "region_id" {
      type    = string
      default = "cn-shenzhen"
    }
    
    variable "dingtalk_webhook_endpoint" {
      type    = string
      default = "https://oapi.dingtalk.com/robot/send?access_token=8e7d6880d9eca81764ee888bdfb03fd795******************"
    }
    
    variable "dingtalk_secret_key" {
      type    = string
      default = "SECedd9fbd3eb89aa1986******************"
    
    # 配置阿里云Provider
    provider "alicloud" {
      region = var.region_id
    }
    
    resource "alicloud_event_bridge_rule" "audit_notify" {
      event_bus_name = "default"
      rule_name      = "audit_notify_fofo"
      description    = "yiyi"
    
      filter_pattern = jsonencode(
        {
          "type" : [
            {
              "suffix" : ":ActionTrail:ApiCall"
            }
          ]
        }
      )
    
      targets {
        target_id = "test-target"
        endpoint  = var.dingtalk_webhook_endpoint
        type      = "acs.dingtalk"
    
        param_list {
          resource_key = "URL"
          form         = "CONSTANT"
          value        = var.dingtalk_webhook_endpoint
        }
    
        param_list {
          resource_key = "SecretKey"
          form         = "CONSTANT"
          value        = var.dingtalk_secret_key
        }
    
        param_list {
          resource_key = "Body"
          form         = "TEMPLATE"
          value        = jsonencode(
            {
              "source": "$.source",
              "type": "$.type",
              "region": "$.data.acsRegion",
              "accountId" : "$.data.userIdentity.accountId",
              "eventName" : "$.data.eventName",
            }
          )
          template = jsonencode(
            {
              "msgtype" : "text",
              "text" : {
                "content":  "测试:来自 $${source} 的 $${type} 审计事件:$${accountId} 在 $${region} 执行了 $${eventName} 操作"
              }
            }
          )
        }
      }
    }
  4. 使用Terraform工具部署1_actiontrail2dingding.tf中创建的规则。

    1. 在命令行窗口执行初始化命令:terraform init。出现以下结果则表示初始化成功:

      image

    2. 执行预览变更命令:terraform plan。在运行结果中可以预览到audit_notify_fofo规则将被创建。

      image

    3. 执行应用变更命令:terraform apply在执行过程中,根据提示输入yes并按下Enter键,等待命令执行完成,若出现以下信息,则表示授权完成,出现以下结果则表示资源被创建成功:

      image

执行terraform show命令

您可以使用以下命令查询Terraform已创建的资源详细信息:

terraform show

image

触发事件验证

  1. 以密钥管理服务产品为例,创建一个ActionTrail:ApiCall事件。

  2. 登录密钥管理服务控制台,在左侧导航栏,单击凭据管理

  3. 在顶部菜单栏,选择地域。

  4. 凭据管理页面的通用凭据页签,单击创建凭据,然后根据提示创建凭据。

  5. 结果验证。

  6. 查看钉钉机器人推送的消息通知。

    钉钉机器人

  7. 查看事件详情。

  8. 事件总线EventBridge控制台

    在左侧导航栏,单击事件总线

    在顶部菜单栏,选择地域。

    事件总线页面,找到audit_notify_fofo,在其右侧操作列,单击事件追踪查看事件轨迹。

删除创建资源

本示例以介绍如何停用并删除应用,audit_notify为例。

  1. 在目标项目目录内执行以下命令,运行配置文件。

    terraform destroy
  2. 预期结果:image

    已成功删除应用audit_notify

说明

当前场景示例代码支持一键运行,您可以直接运行代码。一键运行

场景二:自定义总线触发函数计算

当您的应用产生的事件是通过函数计算FC(Function Compute)进行处理时,就可以通过事件总线EventBridge的自定义事件源和函数计算事件目标来实现,与传统控制台部署方式不同,本案例使用Terraform工具自动化部署自定义总线与函数计算服务。

  1. 创建2_trigger_function.tf文件,声明自定义总线、自定义事件源、函数计算服务、函数和过滤自定义事件源的规则。

    # 定义变量
    variable "region_id" {
      type    = string
      default = "cn-shenzhen"
    }
    
    # 配置阿里云Provider
    provider "alicloud" {
      region = var.region_id
    }
    
    # 获取当前账号信息
    data "alicloud_caller_identity" "current" {}
    
    # 创建自定义事件总线
    resource "alicloud_event_bridge_event_bus" "demo_event_bus" {
      event_bus_name = "demo_event_yiyi"
      description    = "This is a demo event bus."
    }
    
    # 创建自定义事件源
    resource "alicloud_event_bridge_event_source" "demo_event_source" {
      event_bus_name         = alicloud_event_bridge_event_bus.demo_event_bus.event_bus_name
      event_source_name      = "demo_event_source_yiyi"
      description            = "This is a demo event source."
      linked_external_source = false
    }
    
    # 创建函数计算服务
    resource "alicloud_fc_service" "fc_service" {
      name        = "eb-fc-service"
      description = "This service handles events from EventBridge."
      publish     = true
    }
    
    # 自动生成Python脚本文件
    resource "local_file" "python_script" {
      content  = <<EOF
    # -*- coding: utf-8 -*-
    import logging
    
    def handler(event, context):
        logger = logging.getLogger()
        logger.info('Event: ' + str(event))
        return str(event)
    EOF
      filename = "${path.module}/src/index.py"
    }
    
    # 将Python脚本文件打包成ZIP
    data "archive_file" "code" {
      type        = "zip"
      source_dir  = "${path.module}/src"
      output_path = "${path.module}/code.zip"
      depends_on = [local_file.python_script]
    }
    
    # 创建OSS Bucket
    resource "alicloud_oss_bucket" "code_bucket" {
      bucket = "fc-code-bucket-${random_string.random_suffix.result}"
    }
    
    # 生成随机字符串后缀确保OSS Bucket名称的唯一性
    resource "random_string" "random_suffix" {
      length  = 8
      special = false
      upper   = false
    }
    
    # 将ZIP包上传到OSS
    resource "alicloud_oss_bucket_object" "function_code" {
      bucket = alicloud_oss_bucket.code_bucket.bucket
      key    = "index.py.zip"
      source = data.archive_file.code.output_path
    }
    
    # 创建函数计算函数,使用OSS中的代码
    resource "alicloud_fc_function" "fc_function" {
      service     = alicloud_fc_service.fc_service.name
      name        = "eb-fc-function"
      description = "This function executes based on EventBridge rules."
      oss_bucket  = alicloud_oss_bucket.code_bucket.bucket
      oss_key     = alicloud_oss_bucket_object.function_code.key
      memory_size = 128
      runtime     = "python3"
      handler     = "index.handler"
    }
    
    # 在事件总线中创建事件规则
    resource "alicloud_event_bridge_rule" "demo_rule" {
      event_bus_name = alicloud_event_bridge_event_bus.demo_event_bus.event_bus_name
      rule_name      = "demo_rule"
      description    = "Rule for triggering Function Compute on events."
      filter_pattern = jsonencode({
        "source" : [alicloud_event_bridge_event_source.demo_event_source.id]
      })
      lifecycle {
        ignore_changes = [
          targets
        ]
      }
      targets {
        target_id = "demo-fc-target"
        type      = "acs.fc.function"
        endpoint  = "acs:fc:${var.region_id}:${data.alicloud_caller_identity.current.account_id}:services/${alicloud_fc_service.fc_service.name}.LATEST/functions/${alicloud_fc_function.fc_function.name}"
    
        param_list {
          resource_key = "serviceName"
          form         = "CONSTANT"
          value        = alicloud_fc_service.fc_service.name
        }
        param_list {
          resource_key = "functionName"
          form         = "CONSTANT"
          value        = alicloud_fc_function.fc_function.name
        }
        param_list {
          resource_key = "Qualifier"
          form         = "CONSTANT"
          value        = "LATEST"
        }
        param_list {
          resource_key = "Body"
          form         = "ORIGINAL"
        }
      }
    }
  2. 使用Terraform工具部署2_trigger_function.tf中创建的资源。

    1. 在命令行窗口执行初始化命令:terraform init。出现以下结果则表示初始化成功:

      image

    2. 执行预览变更命令:terraform plan。在结果中可以预览到即将被创建的资源:

      image

    3. 执行应用变更命令:terraform apply在执行过程中,根据提示输入yes并按下Enter键,等待命令执行完成,若出现以下信息,则表示授权完成,出现以下结果则表示资源被创建成功:

      image

  3. 执行terraform show命令

    您可以使用以下命令查询Terraform已创建的资源详细信息:

    terraform show

    image

    查看自定义事件总线和自定义事件源是否创建成功

    查看自定义事件总线和自定义事件源是否创建成功。

    1. 登录事件总线EventBridge控制台,在左侧导航栏,单击事件总线

    2. 在顶部菜单栏,选择地域。

    3. 事件总线页面,单击demo_event_yiyi

    4. 在左侧导航栏,单击事件源,在事件源页面,单击demo_event_yiyi查看详情。

    查看函数计算服务和函数是否创建成功。

    1. 登录函数计算控制台,在左侧导航栏,单击服务及函数

    2. 在顶部菜单栏,选择地域。

    3. 服务及函数页面,单击eb-fc-service,然后查看函数详情。

    触发事件。

    1. 登录事件总线EventBridge控制台,在左侧导航栏,单击事件总线

    2. 在顶部菜单栏,选择地域。

    3. 事件总线页面,单击demo_event_yiyi

    4. 概览界面单击发布事件,在发布事件至自定义事件总线demo_event_yiyi面板,从自定义事件源下拉列表,选择demo_event_yiyi,单击确认

    查看事件详情。

    1. demo_event_bus页面,单击事件追踪

    2. 找到发布的事件,在其操作列,单击事件轨迹,查看事件已经成功投递到函数eb-fc-function上。image

    删除创建资源

    本示例以介绍如何停用并删除资源。

    1. 在目标项目目录内执行以下命令,运行配置文件。

      terraform destroy
    2. 预期结果已成功停删除应用。image