运维 用 Terraform 自动化构建基础设施

heroyct · 2018年12月12日 · 最后由 heroyct 回复于 2018年12月14日 · 6167 次阅读

目前为了更快的开发产品,现在很多项目都对基础设施进行了代码化 (Infrastructure as Code)。

现在的项目中使用 Terraform 对基础设施进行了代码化,分享下 Terraform 的使用。

为什么要让基础设施代码化

在使用 Terraform 之前,基本上是在 AWS 管理画面进行操作或者用 AWS CLI 写一些脚本来构建。

主要有以下一些问题

  • 在 AWS 的管理画面上面操作,比较费时间
  • 不容易管理每个人 AWS 的操作记录
  • 对操作的审查比较麻烦,容易误操作
  • 使用了哪些 AWS 的资源必须一个一个查看,不容易对整体进行把握

用 Terraform 可以比较好的解决以上问题,以下是用 Terraform 修改的流程

  1. 把需要修改的部分用 Terraform 代码写好,然后 Pull Request
  2. 相关人员进行代码审查 (Code Review)
  3. 没问题的话 merge,然后在 CI 自动执行

好处是修改流程类似 app 修改的流程,大家很容易上手。

操作时间短,所有的更改记录都进行了版本管理,容易对修改进行审查。

使用了什么资源,看代码一目了然。

什么是 Terraform

开发了 Vagrant 的hashicorp 公司开发的用代码来管理基础设施的一个工具,支持绝大多数的平台。查看支持的平台

我觉的最大的优点是学习成本低,非常简单

只需要了解三个概念就完全可以进行开发了。

开发文档可以在这里查看,很多 sample,很多时候稍微修改一下就可以用

1. resource

对应于 aws 的 resouce

# 建立VPC
resource "aws_vpc" "app" {
  cidr_block                       = "10.1.0.0/16"
  assign_generated_ipv6_cidr_block = "true"

  tags {
    Name = "sample-vpc"
  }
}

# 建立ecs cluster
resource "aws_ecs_cluster" "foo" {
  name = "white-hart"
}

2. data

有时候需要从 AWS 中获取信息的时候可以使用 data

比如获取目前操作中的 AWS 账号信息

data "aws_caller_identity" "current" {}

3. 变量

# 定义变量
variable "region" {
  default = "sample-region"
}
variable "access_key" {}
variable "secret_key" {}

# 使用变量
provider "aws" {
    access_key = "${var.access_key}"
    secret_key = "${var.secret_key}"
    region = "${var.region}"
}

执行 Terraform

Terraform 会执行当前文件夹下面的所有.tf 文件

预执行,不会对 AWS 作出任何改动,可以确认下下有哪些改变

$ terraform plan

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + module.shared_fluentd.aws_vpc.app
      id:                               <computed>
      arn:                              <computed>
      assign_generated_ipv6_cidr_block: "true"
      cidr_block:                       "10.1.0.0/16"
      tags.Name:                        "sample-vpc"

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

实际执行,这里会再次输出有哪些改变,然后输入 yes 就会在 AWS 上面进行构建

$ terraform apply

一些技巧总结

1. 使用 module

比如要同时创建 sandbox 和 production 的 fluentd 服务器,基本都是一样的,只是一些参数不同。

这时候就可以使用 module 来归类类似的代码,然后传入变量来构建。

比如要同时创建 sandbox 和 production 的的 fluentd 服务器。

# 文件结构
terraform
├── modules
│   ├── fluentd
│   │   ├── main.tf
├── production_instance.tf
├── sandbox_instance.tf
# terraform/sandbox_instance.tf
module "sandbox_fluentd" {
  source                   = "./modules/fluentd"
  vpc_id                   = "your sandbox vpc id"
}

# terraform/production_instance.tf
module "production_fluentd" {
  source                   = "./modules/fluentd"
  vpc_id                   = "your production vpc id"
  # 其他的变量
}

这时候可以指定执行的对象来缩小执行范围。

terraform plan -target module.shared_fluentd
terraform plan -target module.production_fluentd

2. 按照 resource 分类文件

写在一个文件里面虽然也可以执行,但是内容多的时候,阅读起来不太容易,这个时候可以分成几个文件。

比如按照 aws resource,变量,data 来分类。

├── fluentd
│   ├── cloud_watch.tf
│   ├── data.tf
│   ├── ecs.tf
│   ├── security_group.tf
│   ├── task_role.tf
│   └── variable.tf

3. 使用 depends_on 来指定依赖

用的很少,基本不用指定,只有必须当某个操作依赖于另外一个操作时才用。

比如在使用 AWS Service Discovery 的时候,必须当 aws_service_discovery 构建以后,才可以获得被创建的 DNS,这个时候就可以使用 depends_on

data "aws_route53_zone" "fluentd" {
  name       = "${aws_service_discovery_public_dns_namespace.fluentd.name}"
  depends_on = ["aws_service_discovery_public_dns_namespace.fluentd"]
}

4. 从已有的环境生成 terraform 代码

官方没有提供这个功能,有人做了个 GEM,用了一下,AWS 基本都可以自动生成代码

terraforming

如果你已经构建好了环境,可以用这个来自动生成代码,避免打字手酸。

总结

简单介绍了 Terraform 的优点和基本使用方法。

我觉的它最大的优点是学习成本低,使用方便。

如果你想简单高效的构建你的基础设施,可以考虑使用 terraform。

很方便的工具,很好用

terraform apply vs terraform destroy 都得考虑, 团队上的话需要考虑好 terraform destroy 的问题, 所以有了 Terraform Collaboration for Everyone

@wppurking

Terraform Collaboration for Everyone 目前还没用过,还没感觉到使用的必要性 (以后也许会)

terraform apply 目前是在 sandbox 构建以后,merge 到 mater,然后自动在 CI 上面进行

也许有点多余了,让固定的一个人从本地执行也许就够了,毕竟更改不是那么频繁

terraform destroy 基本只在 sandbox 测试的时候用,production 目前还没用到

@heroyct 那现在核心是 "让一人负责基础设施" 的部署, 小团队没有问题, 再大一点的团队可能会有基础设施的构建权限或者基础设施的变化的问题.

terraform destroy 的存在心里还是很怕的, 基础设施越大这个担心越可怕, 所以如果有 Terraform Collaboration for Everyone 将 terraform 的最后执行在类似 github 那样允许的 merge 操作会放心很多. 有时候不是故意, 而是运维会"手抖 + tab 补全", 然后整个基础设施就全部通过 API destroy 掉了 - -||

我在测试部署 DO 的时候, terraform plan/apply 很便捷, terraform destroy 很恐怖....

虽然 destroy 指令 让我很恐怖, 但现在使用 terraform 我觉得时机非常不错, terraform 开源到现在 Infrastructure as Code 的概念在现在的不同公用云已经很多都落地并且成熟. 大多数云厂商都为 hashicorp/terraform 提供了自己 API 的兼容 resource, 这使得 Infrastructure as Code 的范围扩张可以扩张得很广:

  • 基础使用的服务器 (AWS, Alicloud, TencentCloud, HuaweiCloud, 青云, DO, vultr, Linode ....)
    • VPC, 防火墙, ssh key ... (只要对应公有云有 API, 并提供 terraform 的 resource 支持)
  • 网络上的 DNS (cloudflare, dnsimple ...)
  • 对象存储 (AWS S3, S3 compatible ...) ...

可以想象一下, 所有程序运营的基础设施无论是服务器还是中间件, 都可以通过 terraform 的 code 来定义, 再利用 ansible (或者其官方的 Packer) 来解决服务器本身的初始化构建问题. 项目越大, 这套管理方法带来的收益越高.

所以推荐 terraform 还是很赞的!

@wppurking

那现在核心是 "让一人负责基础设施" 的部署, 小团队没有问题, 再大一点的团队可能会有基础设施的构建权限或者基础设施的变化的问题.

多谢回复。

是的,目前不到 10 个人,IAM 权限没有分那么细,实际进行terraform plan限制成 2 个人来减少误操作。

从安全问题考虑的话,我觉的主要是在 IAM 对开发人员的权限进行分配。

比如一般的人员只可以执行获取 resource 的操作,无法删除,更改之类的

这样一般开发人员即使terraform destroy,并且输入 yes 以后,也不会被拉出去祭天。。

当然相应的开发就没那么方便了,如何取舍取决于你目前的团队

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册