学习

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

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

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

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

什么是 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.

进一步参考:#