学习

如何在 AWS 上使用 Terraform 部署和管理 Redis 数据库

Ajeet Raina
作者
Ajeet Raina, Redis 前开发人员增长经理
Prasan Kumar
作者
Prasan Kumar, Redis 技术解决方案开发人员

如今的开发团队越来越多的采用 DevOps 原则,例如持续集成和持续交付 (CI/CD)。因此,管理基础设施即代码 (IaC) 已成为任何云服务的必备功能。 IaC 工具允许您使用配置文件而不是图形用户界面来管理基础设施。IaC 通过定义可以版本化、重用和共享的资源配置,使您能够以安全、一致且可重复的方式构建、更改和管理基础设施。

HashiCorp Terraform 是 IaC 领域的一款领先工具,它通过其提供商和模块云基础设施自动化生态系统支持主要的云提供商和服务,用于任何云、基础设施和服务的供应、合规性和管理

什么是 Terraform?#

Terraform 是一款开源的 IaC 软件工具,它提供一致的 CLI 工作流来管理数百个云服务。Terraform 将云 API 编纂成声明性配置文件,这些配置文件可以与团队成员共享,作为代码对待,进行编辑、审查和版本控制。它使您能够安全且可预测地创建、更改和改进基础设施。

Terraform 的功能#

  • Terraform 不仅仅是一个配置管理工具。它还侧重于数据中心的更高级别抽象以及相关服务,同时允许您在单个系统上使用配置管理工具。
  • 它支持多个云提供商,例如 AWS、GCP、Azure、DigitalOcean 等。
  • 它提供一个统一的语法,而不是要求操作员对每个平台和服务使用独立且互不兼容的工具。
  • 管理现有的服务提供商和定制的内部解决方案。
  • Terraform 很容易移植到任何其他提供商。
  • 提供不可变基础设施,配置更改平稳进行。
  • 支持仅客户端架构,因此无需在服务器上进行额外的配置管理。
  • Terraform 非常灵活,使用基于插件的模型来支持提供商和供应程序,使其能够支持几乎所有公开 API 的服务。
  • 它不是为了提供对提供商的低级编程访问,而是提供了一个高级语法来描述如何创建、供应和组合云资源和服务。
  • 它提供一个简单统一的语法,允许以几乎任何方式管理资源,而无需学习新的工具。

HashiCorp Terraform Redis Cloud 提供商#

Redis 为 Redis Cloud 开发了一个 Terraform 提供商。 HashiCorp Terraform Redis Cloud 提供商允许客户轻松地以代码形式在任何云提供商上部署和管理 Redis Cloud 订阅、数据库和网络对等。它是 Terraform 的一个插件,允许 Redis Cloud Flexible 客户管理其订阅和相关 Redis 数据库的整个生命周期。

Redis Cloud 提供商用于与 Redis Cloud 支持的资源进行交互。在使用该提供商之前,需要使用正确的凭据进行配置。使用左侧的导航阅读有关可用提供商资源和数据源的信息。

在我们开始实现之前,让我们花点时间更好地理解 Terraform 配置。Terraform 配置是在 Terraform 语言中的完整文档,它告诉 Terraform 如何管理给定的基础设施集合。一个配置可以包含多个文件和目录。Terraform 分为三个主要部分

  • 提供商
  • 数据源
  • 资源

提供商#

提供商是在任何项目中在 Terraform 配置文件中需要定义的第一个资源。该提供商使您可以访问您将与之交互的 API 以创建资源。一旦提供商被配置并经过身份验证,大量资源现在可供创建。Terraform 为其提供的 100 多个云提供商提供服务。

提供商定义特定基础设施(例如 AWS)的资源和数据。如下所示,terraform 块 {} 包含 terraform 设置,包括 Terraform 用于配置基础设施所需的提供商(例如,rediscloud 提供商)。

 terraform {
 required_providers {
  rediscloud = {
    source = "RedisLabs/rediscloud"
    version = "0.2.2"
  }
 }
 }

provider {} 块配置特定提供商。在以下示例中,它是 AWS。

 cloud_provider {

   provider = "AWS"
   cloud_account_id = 1
   region {
     region = "us-east-1"
     networking_deployment_cidr = "10.0.0.0/24"
     preferred_availability_zones = ["us-east-1a"]
   }
 }

资源#

资源是 Terraform 语言中最重要的元素。在这里,您描述要创建的基础设施部分,这可以从计算实例到定义特定权限等等。

如下所示,resource {} 块用于定义基础设施的组件。资源可能是物理或虚拟组件,例如 EC2,也可能是逻辑组件,例如 Heroku 应用程序。

 resource "random_password" "passwords" {
 count = 2
 length = 20
 upper = true
 lower = true
 number = true
}

resource {} 块在块之前有两个字符串:资源类型和资源名称。类型的首字母缩写映射到提供商的名称。例如,资源类型“random_password”和资源名称“passwords”形成了资源的唯一标识符。Terraform 使用此 ID 来识别资源。

数据源#

数据源允许 Terraform 使用在 Terraform 之外定义的信息,由另一个独立的 Terraform 配置定义,或由函数修改。每个提供商可能在其资源类型集合旁边提供数据源。数据源通过一种特殊类型的资源访问,称为数据资源,使用 data 块声明。

 data "rediscloud_payment_method" "card" {
 card_type = "Visa"
 last_four_numbers = "XXXX"
 }

data 块请求 Terraform 从给定的数据源 (“rediscloud_payment_method”) 读取并将结果导出到给定的本地名称 (“card”) 下。该名称用于从同一个 Terraform 模块中的其他地方引用此资源,但在模块的范围之外没有任何意义。

在块主体({ 和 } 之间)中,由数据源定义的查询约束。本节中的大多数参数取决于数据源,实际上在本例中,card_type 和 last_four_numbers 都是专门为 rediscloud_payment_method 数据源定义的参数。

配置 Redis Cloud 程序化访问#

为了设置与 Redis Cloud 提供商的身份验证,必须为 Redis Cloud 生成一个编程 API 密钥。Redis Cloud 文档包含创建和管理密钥以及 IP 访问的最新的说明。

提示

灵活和年度 Redis Cloud 订阅可以利用 RESTful API,该 API 允许对各种资源(包括服务器、服务和相关基础设施)进行操作。REST API 不支持固定或免费订阅。

 provider "rediscloud" { } # Example resource configuration
 resource "rediscloud_subscription" "example" { # ... }

先决条件:#

  • 在 macOS 上安装 Terraform。
  • 创建一个免费的 Redis Cloud 帐户。
  • 创建你的第一个订阅。
  • 启用 API

步骤 1:在 macOS 上安装 Terraform#

使用 Homebrew 在 macOS 上安装 Terraform,如下所示

 brew install terraform

步骤 2:注册免费的 Redis Cloud 帐户#

按照本教程 注册免费的 Redis Cloud 帐户。

步骤 3:启用 Redis Cloud API#

如果你有灵活(或年度)Redis Cloud 订阅,你可以使用 REST API 以编程方式管理你的订阅。Redis Cloud REST API 仅对灵活或年度订阅可用。它不支持固定或免费订阅。

出于安全原因,Redis Cloud API 默认情况下处于禁用状态。要启用 API

  • 以帐户所有者的身份登录到你的 Redis Cloud 订阅。
  • 从菜单中选择“访问管理”。
  • 当“访问管理”屏幕出现时,选择“API 密钥”选项卡。

如果 API 帐户密钥右侧出现“复制”按钮,则表示 API 已启用。此按钮会将帐户密钥复制到剪贴板。

如果你看到“启用 API”按钮,请选中它以启用 API 并生成你的 API 帐户密钥。

要对 REST API 调用进行身份验证,你需要将 API 帐户密钥与 API 用户密钥结合起来才能进行 API 调用。

步骤 4:创建一个 main.tf 文件#

现在是时候创建一个空的“main.tf”文件并开始添加提供程序、资源和数据源,如下所示

 terraform {
 required_providers {
   rediscloud = {
     source = "RedisLabs/rediscloud"
     version = "0.2.2"
   }
  }
 }
# Provide your credit card details
data "rediscloud_payment_method" "card" {
card_type = "Visa"
last_four_numbers = "XXXX"
}
# Generates a random password for the database
resource "random_password" "passwords" {
count = 2
length = 20
upper = true
lower = true
number = true
special = false
}
resource "rediscloud_subscription" "rahul-test-terraform" {
name = "rahul-test-terraform"
payment_method_id = data.rediscloud_payment_method.card.id
memory_storage = "ram"
cloud_provider {

  provider = "AWS"
  cloud_account_id = 1
  region {
    region = "us-east-1"
    networking_deployment_cidr = "10.0.0.0/24"
    preferred_availability_zones = ["us-east-1a"]
  }
}
database {
  name = "db-json"
  protocol = "redis"
  memory_limit_in_gb = 1
  replication = true
  data_persistence = "aof-every-1-second"
  module {
      name = "RedisJSON"
  }
  throughput_measurement_by = "operations-per-second"
  throughput_measurement_value = 10000
  password = random_password.passwords[1].result
}
}

步骤 5:创建一个执行计划#

Terraform plan 命令会创建一个执行计划,它允许你预览 Terraform 计划对你的基础设施进行的更改。默认情况下,当 Terraform 创建计划时,它会读取任何已存在的远程对象的当前状态以确保 Terraform 状态是最新的。然后它将当前配置与先前状态进行比较,然后提出应使远程对象与配置匹配的一组更改操作。

 % terraform plan


Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
 + create

Terraform will perform the following actions:

 # random_password.passwords[0] will be created
 + resource "random_password" "passwords" {
   + id     = (known after apply)
   + length   = 20
   + lower    = true
   + min_lower  = 0
   + min_numeric = 0
   + min_special = 0
   + min_upper  = 0
   + number   = true
   + result   = (sensitive value)
   + special   = false
   + upper    = true
  }

 # random_password.passwords[1] will be created
 + resource "random_password" "passwords" {
   + id     = (known after apply)
   + length   = 20
   + lower    = true
   + min_lower  = 0
   + min_numeric = 0
   + min_special = 0
   + min_upper  = 0
   + number   = true
   + result   = (sensitive value)
   + special   = false
   + upper    = true
  }

 # rediscloud_subscription.rahul-test-terraform will be created
 + resource "rediscloud_subscription" "rahul-test-terraform" {
   + id              = (known after apply)
   + memory_storage        = "ram"
   + name             = "rahul-test-terraform"
   + payment_method_id       = "XXXX"
   + persistent_storage_encryption = true

   + cloud_provider {
     + cloud_account_id = "1"
     + provider     = "AWS"

     + region {
       + multiple_availability_zones = false
       + networking_deployment_cidr  = "10.0.0.0/24"
       + networks           = (known after apply)
       + preferred_availability_zones = [
         + "us-east-1a",
        ]
       + region            = "us-east-1"
      }
    }

   + database {
     # At least one attribute in this block is (or was) sensitive,
     # so its contents will not be displayed.
    }
  }

Plan: 3 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

:::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.

:::

步骤 6:执行操作#

Terraform apply 命令会执行 Terraform 计划中提出的操作。

 terraform apply


Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
 + create

Terraform will perform the following actions:

 # random_password.passwords[0] will be created
 + resource "random_password" "passwords" {
   + id     = (known after apply)
   + length   = 20
   + lower    = true
   + min_lower  = 0
   + min_numeric = 0
   + min_special = 0
   + min_upper  = 0
   + number   = true
   + result   = (sensitive value)
   + special   = false
   + upper    = true
  }

 # random_password.passwords[1] will be created
 + resource "random_password" "passwords" {
   + id     = (known after apply)
   + length   = 20
   + lower    = true
   + min_lower  = 0
   + min_numeric = 0
   + min_special = 0
   + min_upper  = 0
   + number   = true
   + result   = (sensitive value)
   + special   = false
   + upper    = true
  }

 # rediscloud_subscription.rahul-test-terraform will be created
 + resource "rediscloud_subscription" "rahul-test-terraform" {
   + id              = (known after apply)
   + memory_storage        = "ram"
   + name             = "rahul-test-terraform"
   + payment_method_id       = "XXXX"
   + persistent_storage_encryption = true

   + cloud_provider {
     + cloud_account_id = "1"
     + provider     = "AWS"

     + region {
       + multiple_availability_zones = false
       + networking_deployment_cidr  = "10.0.0.0/24"
       + networks           = (known after apply)
       + preferred_availability_zones = [
         + "us-east-1a",
        ]
       + region            = "us-east-1"
      }
    }

   + database {
     # At least one attribute in this block is (or was) sensitive,
     # so its contents will not be displayed.
    }
  }

Plan: 3 to add, 0 to change, 0 to destroy.

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

random_password.passwords[0]: Creating...
random_password.passwords[1]: Creating...
random_password.passwords[1]: Creation complete after 0s [id=none]
random_password.passwords[0]: Creation complete after 0s [id=none]
rediscloud_subscription.rahul-test-terraform: Creating...
rediscloud_subscription.rahul-test-terraform: Still creating... [10s elapsed]
rediscloud_subscription.rahul-test-terraform: Still creating... [20s elapsed]
rediscloud_subscription.rahul-test-terraform: Creation complete after 8m32s [id=1649277]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

步骤 7:验证数据库#

你现在可以验证在名为“db-json”的订阅下创建的新数据库。

使用 Terraform 在 AWS 上部署包含 JSON 和 [其他](Redis Stack ) 功能的 Redis 数据库

terraform {
required_providers {
  rediscloud = {
    source = "RedisLabs/rediscloud"
    version = "0.2.2"
  }
}
}
# Provide your credit card details
data "rediscloud_payment_method" "card" {
card_type = "Visa"
last_four_numbers = "XXXX"
}
# Generates a random password for the database
resource "random_password" "passwords" {
count = 2
length = 20
upper = true
lower = true
number = true
special = false
}
resource "rediscloud_subscription" "rahul-test-terraform" {
name = "rahul-test-terraform"
payment_method_id = data.rediscloud_payment_method.card.id
memory_storage = "ram"
cloud_provider {

  provider = "AWS"
  cloud_account_id = 1
  region {
    region = "us-east-1"
    networking_deployment_cidr = "10.0.0.0/24"
    preferred_availability_zones = ["us-east-1a"]
  }
}
database {
  name = "db-json"
  protocol = "redis"
  memory_limit_in_gb = 1
  replication = true
  data_persistence = "aof-every-1-second"
  module {
      name = "RedisJSON"
  }
  throughput_measurement_by = "operations-per-second"
  throughput_measurement_value = 10000
  password = random_password.passwords[1].result
}
}

步骤 8:清理#

Terraform destroy 命令是销毁特定 Terraform 配置管理的所有远程对象的便捷方法。虽然你通常不希望在生产环境中销毁长期存在的对象,但 Terraform 有时用于管理用于开发目的的临时基础设施,在这种情况下,你可以使用 terraform destroy’ 来方便地清理所有这些临时对象,一旦你完成了工作。

% terraform destroy
random_password.passwords[0]: Refreshing state... [id=none]
random_password.passwords[1]: Refreshing state... [id=none]
rediscloud_subscription.rahul-test-terraform: Refreshing state... [id=1649277]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # random_password.passwords[0] will be destroyed
  - resource "random_password" "passwords" {
      - id          = "none" -> null
      - length      = 20 -> null
      - lower       = true -> null
      - min_lower   = 0 -> null
      - min_numeric = 0 -> null
      - min_special = 0 -> null
      - min_upper   = 0 -> null
      - number      = true -> null
      - result      = (sensitive value)
      - special     = false -> null
      - upper       = true -> null
    }

  # random_password.passwords[1] will be destroyed
  - resource "random_password" "passwords" {
      - id          = "none" -> null
      - length      = 20 -> null
      - lower       = true -> null
      - min_lower   = 0 -> null
      - min_numeric = 0 -> null
      - min_special = 0 -> null
      - min_upper   = 0 -> null
      - number      = true -> null
      - result      = (sensitive value)
      - special     = false -> null
      - upper       = true -> null
    }

  # rediscloud_subscription.rahul-test-terraform will be destroyed
  - resource "rediscloud_subscription" "rahul-test-terraform" {
      - id                            = "1649277" -> null
      - memory_storage                = "ram" -> null
      - name                          = "rahul-test-terraform" -> null
      - payment_method_id             = "XXXX" -> null
      - persistent_storage_encryption = true -> null

      - cloud_provider {
          - cloud_account_id = "1" -> null
          - provider         = "AWS" -> null

          - region {
              - multiple_availability_zones  = false -> null
              - networking_deployment_cidr   = "10.0.0.0/24" -> null
              - networks                     = [
                  - {
                      - networking_deployment_cidr = "10.0.0.0/24"
                      - networking_subnet_id       = "subnet-0055e8e3ee3ea796e"
                      - networking_vpc_id          = ""
                    },
                ] -> null
              - preferred_availability_zones = [
                  - "us-east-1a",
                ] -> null
              - region                       = "us-east-1" -> null
            }
        }

      - database {
          # At least one attribute in this block is (or was) sensitive,
          # so its contents will not be displayed.
        }
    }

Plan: 0 to add, 0 to change, 3 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

rediscloud_subscription.rahul-test-terraform: Destroying... [id=1649277]
rediscloud_subscription.rahul-test-terraform: Destruction complete after 1m34s
random_password.passwords[0]: Destroying... [id=none]
random_password.passwords[1]: Destroying... [id=none]
random_password.passwords[0]: Destruction complete after 0s
random_password.passwords[1]: Destruction complete after 0s

Destroy complete! Resources: 3 destroyed.

进一步参考:#