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