Terraform多环境创建实战

举报
kaliarch 发表于 2023/07/16 10:52:27 2023/07/16
【摘要】 一 背景Don’t repeat yourself (DRY) 使用Terraform在多个environments/regions/cloud-providers中创建您的基础设施Terraform简化了我们在云中提供基础设施并将其作为代码进行管理的方式。但是像将基础架构分离到多个环境(试运行/QA/生产)这样的最佳实践不会改变。甚至根据您的业务需求,您需要跨多个地理区域扩展基础架构。也...

一 背景

Don’t repeat yourself (DRY) 使用Terraform在多个environments/regions/cloud-providers中创建您的基础设施

Terraform简化了我们在云中提供基础设施并将其作为代码进行管理的方式。但是像将基础架构分离到多个环境(试运行/QA/生产)这样的最佳实践不会改变。甚至根据您的业务需求,您需要跨多个地理区域扩展基础架构。也许你甚至在考虑采用多云策略。
如果您处于这种情况,这意味着您需要能够在代码中创建多个环境。这里的挑战是尽可能地将代码分解为DRY(不要重复自己)原则。使用Terraform有许多方法可以实现它。

二 创建多种环境的策略

在这两种策略中,为了方便起见,我们都使用了项目中包含的模块。它们可以在不同的GIT存储库中进行版本控制。每个模块在特定的层中被调用,terraform远程状态存储在版本化的S3后端。分离的层提高了一致性,使回滚更容易。

2.1 分离目录

在这个项目结构中,每个环境都有包含层的目录。您可以在下面看到登台环境的网络配置:

terraform {
  backend "s3" {
    bucket = "terraform-remote-states"
    # The key definition changes following the environment
    key    = "environments/staging/network.tf"
    region = "us-east-1"
  }
}

module "network" {
  source               = "../modules/network"
  region               = "us-east-1"
  network_cidr         = "10.0.0.0/16"
  private_subnet_cidrs = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
  public_subnet_cidrs  = ["10.0.3.0/24", "10.0.4.0/24", "10.0.5.9/24"]
}

如前所述,我们使用后端来持久化远程状态。密钥定义,即存储远程状态的位置,根据环境和层而变化。在模块块中,不同的值可以根据环境而有所不同。
层之间的依赖关系可以通过数据源来解决。可以获取云中的现有资源或远程状态的输出:

data "terraform_remote_state" "network" {
  backend = "s3"

  config = {
    bucket = "terraform-remote-states"
    key    = "environments/staging/network.tf"
    region = "us-east-1"
  }
}

locals {
  vpc_id = data.terraform_remote_state.network.outputs.vpc_id
}

对于部署,您必须执行terraform初始化并按以下顺序应用于各层:

$ terraform -chdir="./environments/staging/network" init
$ terraform -chdir="./environments/staging/network" apply

$ terraform -chdir="./environments/staging/database" init
$ terraform -chdir="./environments/staging/database" apply

$ terraform -chdir="./environments/staging/application" init
$ terraform -chdir="./environments/staging/application" apply

2.2 Workspaces

在我们使用S3后端存储远程状态之前。最初,只有一个名为default的工作区,并且只有一个与状态相关联。一些后端如S3支持多个工作区。它们允许多个状态与单个Terraform配置相关联。
我们将使用这个特性来定义多个环境。每个环境都是一个工作区。在后端定义中,我们添加了workspace_key_prefix参数。它特定于S3后端,它将S3状态路径定义为/workspace_key/workspace_key_prefix/workspace_name:

terraform {
  backend "s3" {
    bucket               = "terraform-remote-states"
    workspace_key_prefix = "environments"
    key                  = "network"
    region               = "us-east-1"
  }
}

远程状态在S3中如下所示:

网络层与以前相同:

terraform {
  backend "s3" {
    bucket = "terraform-remote-states"
    # The key definition changes following the environment
    key    = "environments/staging/network.tf"
    region = "us-east-1"
  }
}

module "network" {
  source               = "../modules/network"
  region               = "us-east-1"
  network_cidr         = "10.0.0.0/16"
  private_subnet_cidrs = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
  public_subnet_cidrs  = ["10.0.3.0/24", "10.0.4.0/24", "10.0.5.9/24"]
}

Terraform命令管理工作区。第一步是创建新的工作区:

$ terraform -chdir="./network" workspace new staging

然后你必须选择它:

$ terraform -chdir="./network" workspace select staging

上图中显示的vars目录包含用于自定义环境的变量文件。应用配置时,必须加载好的配置:

$ terraform init -chdir="./network"
$ terraform apply -chdir="./network" -var-file="./vars/staging.tfvars"

另一种方法是使用本地人来代替terraform.workspace:

terraform {
  backend "s3" {
    bucket               = "terraform-remote-states"
    workspace_key_prefix = "environments"
    key                  = "network"
    region               = "us-east-1"
  }
}

variable "network_cidr" {
  type    = list(string)
  default = {
    staging    = "10.0.0.0/16"
    qa         = "10.1.0.0/16"
    production = "10.2.0.0/16"
  }
}

variable "private_subnet_cidrs" {
  type = list(string)
  default = {
    staging    = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
    qa         = ["10.1.0.0/24", "10.1.1.0/24", "10.1.2.0/24"]
    production = ["10.2.0.0/24", "10.2.1.0/24", "10.2.2.0/24"]
  }
}

variable "public_subnet_cidrs" {
  type = list(string)
  default = {
    staging    = ["10.0.3.0/24", "10.0.4.0/24", "10.0.5.0/24"]
    qa         = ["10.1.3.0/24", "10.1.4.0/24", "10.1.5.0/24"]
    production = ["10.2.3.0/24", "10.2.4.0/24", "10.2.5.0/24"]
  }
}

locals {
  network_cidr          = lookup(var.network_cidr, terraform.workspace, null)
  private_subnet_cidrs  = lookup(var.private_subnet_cidrs, terraform.workspace, null)
  public_subnet_cidrs   = lookup(var.public_subnet_cidrs, terraform.workspace, null)
}

module "network" {
  source                = "../modules/network"
  region                = "us-east-1"
  network_cidr          = local.network_cidr
  private_subnet_cidrs  = local.private_subnet_cidrs
  public_subnet_cidrs   = local.public_subnet_cidrs
}

三 策略对比

3.1 分离目录

3.1.1 优点

  • 环境是分离的和可识别的
  • 更细粒度:您可以自定义环境层
  • 在恶劣环境中应用配置的可能性更小

3.1.2 不足

  • 需要复制一段文件结构来创建新环境
  • 项目中的几个目录级别

3.2 workspaces

3.2.1 优点

  • 可重复环境的可伸缩性
  • 简单

3.2.2 不足

  • 更容易因选择错误的工作区而出错
  • 环境层的定制不太明显

四 结论

在一个Terraform项目中,没有单一的解决方案来管理多个环境。我们讨论的两种方法各有优缺点。这取决于你的项目期望。
您需要快速扩展还是环境创建的速度在时间上更长?您希望在环境之间实现文件隔离还是依赖工作区抽象机制?
在任何情况下,您都可以用其他解决方案来弥补这种选择的缺点。通过使用连续部署管道,您可以大大降低选择错误工作区的错误率。可以使用模板在文件结构中动态生成新环境的创建

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。