Continuous integration 使用Terraform时的最佳实践
我正在将我们的基础设施转换为地形。 实际管理地形文件和状态的最佳实践是什么? 我意识到它是作为代码的基础设施,我将把.tf文件提交到git中,但我是否也提交了tfstate?它应该驻留在S3这样的地方吗?我希望最终让CI来管理所有这些,但这远远不够,需要我找出文件的移动部分Continuous integration 使用Terraform时的最佳实践,continuous-integration,terraform,Continuous Integration,Terraform,我正在将我们的基础设施转换为地形。 实际管理地形文件和状态的最佳实践是什么? 我意识到它是作为代码的基础设施,我将把.tf文件提交到git中,但我是否也提交了tfstate?它应该驻留在S3这样的地方吗?我希望最终让CI来管理所有这些,但这远远不够,需要我找出文件的移动部分 我真的只是想看看那里的人们是如何在生产中实际使用这种类型的东西的我还处于将现有AWS基础设施迁移到Terraform的状态,因此我将在开发过程中更新答案 我一直严重依赖于官方的地形和多次尝试和错误来充实我一直不确定的领域 .
我真的只是想看看那里的人们是如何在生产中实际使用这种类型的东西的我还处于将现有AWS基础设施迁移到Terraform的状态,因此我将在开发过程中更新答案 我一直严重依赖于官方的地形和多次尝试和错误来充实我一直不确定的领域
.tfstate
文件
Terraform config可用于在不同的基础设施上配置多个箱子,每个箱子可能具有不同的状态。因为它也可以由多人运行,所以这个状态应该位于一个集中的位置(如S3),而不是git
这可以通过观察地形得到证实
开发者控制
我们的目标是为开发人员提供对基础设施的更多控制,同时维护完整审计(git日志)和健全检查更改(pull请求)的能力。考虑到这一点,我的目标是实现新的基础架构工作流:
stage
└ main.tf
└ vars.tf
└ outputs.tf
prod
└ main.tf
└ vars.tf
└ outputs.tf
global
└ main.tf
└ vars.tf
└ outputs.tf
data "aws_region" "current" {}
resource "aws_s3_bucket" "bucket" {
bucket = "my-tf-test-bucket-${data.aws_region.current.name}-${terraform.workspace}"
}
tree-l1。
结果:
├── README.md
├── aws-asg
├── aws-ec2
├── aws-elb
├── aws-rds
├── aws-sg
├── aws-vpc
└── templates
每一个都设置了一些合理的默认值,但将它们作为变量公开,这些变量可以被我们的“胶水”覆盖
胶水
我们还有第二个存储库,其中包含胶水
,它利用了上述模块。其布局符合我们的分类文件:
.
├── README.md
├── clientA
│ ├── eu-west-1
│ │ └── dev
│ └── us-east-1
│ └── dev
├── clientB
│ ├── eu-west-1
│ │ ├── dev
│ │ ├── ec2-keys.tf
│ │ ├── prod
│ │ └── terraform.tfstate
│ ├── iam.tf
│ ├── terraform.tfstate
│ └── terraform.tfstate.backup
└── clientC
├── eu-west-1
│ ├── aws.tf
│ ├── dev
│ ├── iam-roles.tf
│ ├── ec2-keys.tf
│ ├── prod
│ ├── stg
│ └── terraform.tfstate
└── iam.tf
在客户端级别,我们有AWS特定于帐户的.tf
文件,用于提供全局资源(如IAM角色);接下来是区域级,使用EC2 SSH公钥;最后,在我们的环境中(dev
、stg
、prod
等)存储了我们的VPC设置、实例创建和对等连接等
旁注:正如你所看到的,我违背了我自己的建议,将terraform.tfstate
保留在git中。这是一个临时措施,直到我转到S3,但适合我,因为我目前是唯一的开发人员
下一步
这仍然是一个手动过程,在Jenkins中还没有,但我们正在移植一个相当大、复杂的基础架构,到目前为止还不错。就像我说的,很少有虫子,但进展顺利
编辑2-更改
我写下这个最初的答案已经快一年了,地球和我自己的状态都发生了显著的变化。我现在在一个新的位置上使用Terraform来管理Azure集群,Terraform现在是v0.10.7
状态
人们一再告诉我,州政府不应该使用Git——他们是正确的。我们将此作为一个依靠开发人员沟通和纪律的两人团队的临时措施。有了一个更大的分布式团队,我们现在可以充分利用DynamoDB提供的S3中的远程状态。理想情况下,这将迁移到Concur,现在它是v1.0,以切断跨云提供商
模块
之前我们创建并使用了内部模块。这种情况仍然存在,但随着信息技术的出现和发展,我们尝试将其作为至少一个基础
文件结构
新职位的分类更加简单,只有两个infx环境——dev
和prod
。每个模块都有自己的变量和输出,重用上面创建的模块。提供程序还帮助在环境之间共享已创建资源的输出。我们的场景是将不同Azure资源组中的子域连接到一个全局管理的TLD
├── main.tf
├── dev
│ ├── main.tf
│ ├── output.tf
│ └── variables.tf
└── prod
├── main.tf
├── output.tf
└── variables.tf
规划
同样,由于分布式团队的额外挑战,我们现在总是保存terraform plan
命令的输出。我们可以检查并知道将运行什么,而不会在计划
和应用
阶段之间发生某些更改(尽管锁定有助于此)。请记住删除此计划文件,因为它可能包含纯文本“机密”变量
总的来说,我们对Terraform非常满意,并通过添加新功能继续学习和改进。以前的
远程配置
允许这样做,但现在已被“”取代,因此Terraform remote不再可用
terraform远程配置-
⁃ Modules
⁃ Environment management
⁃ Separation of duties
.
├── 1_tf-backend #remote AWS S3 + Dynamo Lock tfstate
│ ├── main.tf
│ ├── ...
├── 2_secrets
│ ├── main.tf
│ ├── ...
├── 3_identities
│ ├── account.tf
│ ├── roles.tf
│ ├── group.tf
│ ├── users.tf
│ ├── ...
├── 4_security
│ ├── awscloudtrail.tf
│ ├── awsconfig.tf
│ ├── awsinspector.tf
│ ├── awsguarduty.tf
│ ├── awswaf.tf
│ └── ...
├── 5_network
│ ├── account.tf
│ ├── dns_remote_zone_auth.tf
│ ├── dns.tf
│ ├── network.tf
│ ├── network_vpc_peering_dev.tf
│ ├── ...
├── 6_notifications
│ ├── ...
├── 7_containers
│ ├── account.tf
│ ├── container_registry.tf
│ ├── ...
├── config
│ ├── backend.config
│ └── main.config
└── readme.md
├── main.tf
├── dev
│ ├── main.tf
│ ├── output.tf
│ └── variables.tf
└── prod
├── main.tf
├── output.tf
└── variables.tf
├── deployment
│ ├── 01-network.tf
│ ├── 02-ecs_cluster.tf
│ ├── 03-ecs_service.tf
│ ├── 04-eks_infra.tf
│ ├── 05-db_infra.tf
│ ├── 06-codebuild-k8s.tf
│ ├── 07-aws-secret.tf
│ ├── backend.tf
│ ├── provider.tf
│ └── variables.tf
├── env
│ ├── dev
│ │ ├── dev.backend.tfvar
│ │ └── dev.variables.tfvar
│ └── prod
│ ├── prod.backend.tfvar
│ └── prod.variables.tfvar
├── modules
│ └── aws
│ ├── compute
│ │ ├── alb_loadbalancer
│ │ ├── alb_target_grp
│ │ ├── ecs_cluster
│ │ ├── ecs_service
│ │ └── launch_configuration
│ ├── database
│ │ ├── db_main
│ │ ├── db_option_group
│ │ ├── db_parameter_group
│ │ └── db_subnet_group
│ ├── developertools
│ ├── network
│ │ ├── internet_gateway
│ │ ├── nat_gateway
│ │ ├── route_table
│ │ ├── security_group
│ │ ├── subnet
│ │ ├── vpc
│ └── security
│ ├── iam_role
│ └── secret-manager
└── templates
region = "ap-southeast-2"
bucket = "dev-samplebackendterraform"
key = "dev/state.tfstate"
dynamo_db_lock = "dev-terraform-state-lock"
environment = "dev"
vpc_name = "demo"
vpc_cidr_block = "10.20.0.0/19"
private_subnet_1a_cidr_block = "10.20.0.0/21"
private_subnet_1b_cidr_block = "10.20.8.0/21"
public_subnet_1a_cidr_block = "10.20.16.0/21"
public_subnet_1b_cidr_block = "10.20.24.0/21"
variable vpc_create {
default = "true"
}
module "vpc" {
source = "../modules/aws/network/vpc"
enable = "${var.vpc_create}"
vpc_cidr_block = "${var.vpc_cidr_block}"
name = "${var.vpc_name}"
}
resource "aws_vpc" "vpc" {
count = "${var.enable == "true" ? 1 : 0}"
cidr_block = "${var.vpc_cidr_block}"
enable_dns_support = "true"
enable_dns_hostnames = "true"
}
terraform init -var-file=dev.variables.tfvar -backend-config=dev.backend.tfvar ../../deployment/
terraform apply -var-file=dev.variables.tfvar ../../deployment
terraform workspace new dev
resource "aws_s3_bucket" "bucket" {
bucket = "my-tf-test-bucket-${terraform.workspace}"
}
data "aws_region" "current" {}
resource "aws_s3_bucket" "bucket" {
bucket = "my-tf-test-bucket-${data.aws_region.current.name}-${terraform.workspace}"
}
TERRAFORM_IMAGE=hashicorp/terraform:0.11.7
TERRAFORM_CMD="docker run -ti --rm -w /app -v ${HOME}/.aws:/root/.aws -v ${HOME}/.ssh:/root/.ssh -v `pwd`:/app $TERRAFORM_IMAGE"