衆所周知,Terraform 是一個開源的自動化的資源編排工具,支援多家雲服務提供商。阿裡雲作為第三大雲服務提供商, terraform-alicloud-provider
已經支援了超過 140 個 Resource 和 100 個 Data Source,覆寫30多個服務和産品,吸引了越來越多的開發者加入到阿裡雲Terraform生态的建設中。
随着 Resource 和 DataSource 的不斷增加和完善,業務架構的不斷發展,Terraform 模闆編寫的成本和複雜度也在不斷的增加。如何讓Terraform 模闆更加簡單和重用,就是本文所要解決的問題。
本文将通過一個典型的負載均衡架構,向大家介紹如何使用 Module 簡化 Terraform 的模闆。

将所有Resource放在一個模闆中進行統一管理
面對這樣的一個架構,模闆可以有多種寫法。通常的寫法是将架構中涉及到的所有資源寫到一個模闆中,并通過參數和關系型 resource 将這些資源關聯起來,如下所示:
// Images data source for image_id
data "alicloud_images" "default" {
...
}
// Instance_types data source for instance_type
data "alicloud_instance_types" "default" {
...
}
// Zones data source for availability_zone
data "alicloud_zones" "default" {
...
}
// A new VPC
resource "alicloud_vpc" "vpc" {
name = "default"
...
}
// Two new VSwitches
resource "alicloud_vswitch" "vswitches" {
count = 2
vpc_id = "${alicloud_vpc.vpc.id}"
...
}
// A new Security Group
resource "alicloud_security_group" "default" {
vpc_id = "alicloud_vpc.vpc.id}"
...
}
// Two Web Tier instances
resource "alicloud_instance" "web" {
count = 2
image_id = "data.alicloud_images.default.images.0.id"
instance_type = "data.alicloud_instance_types.default.instance_types.0.id"
security_groups = ["${ alicloud_security_group.default.id }"]
vswitch_id = "${element(alicloud_vswitch.vswitches.*.id, count.index)}"
...
}
// Two Application Tier instances
resource "alicloud_instance" "app" {
count = 2
image_id = "${data.alicloud_images.default.images.0.id}"
instance_type = "${data.alicloud_instance_types.default.instance_types.0.id}"
security_groups = ["${alicloud_security_group.default.id}"]
vswitch_id = "${element(alicloud_vswitch.vswitches.*.id, count.index)}"
...
}
// A SLB Instance for intranet
resource "alicloud_slb" "intranet" {
internet = false
vswitch_id = "${alicloud_vswitch.vswitches.0.id}"
...
}
// Attach Ecs instances
resource "alicloud_slb_attachment" "intranet" {
load_balancer_id = "${alicloud_slb.intranet.id}"
instance_ids = ["${alicloud_instance.web.*.id}", "${alicloud_instance.app.*.id}"]
}
// SLB Instance Resource for internet
resource "alicloud_slb" "internet" {
internet = true
...
}
// Attach Ecs instances
resource "alicloud_slb_attachment" "internet" {
load_balancer_id = "${alicloud_slb.internet.id}"
instance_ids = ["${alicloud_instance.web.*.id}"]
}
// Two RDS Instance
resource "alicloud_db_instance" "default" {
count = 2
vswitch_id = "${element(alicloud_vswitch.vswitches.*.id, count.index)}"
...
}
// Add a account for each RDS instance
resource "alicloud_db_account" "default" {
count = 2
instance_id = "${element(alicloud_db_instance.default.*.id, count.index)}"
...
}
// Add a database for each RDS instance
resource "alicloud_db_database" "default" {
count = 2
instance_id = "${element(alicloud_db_instance.default.*.id, count.index)}"
...
}
// A OSS Bucket
resource "alicloud_oss_bucket" "default" {
...
}
這樣寫的好處是,所有資源都在一個模闆中管理,編寫時可以很清楚了解資源之間的引用關系;但是,當資源不斷增加時,擴充非常不靈活,資源間關系越複雜,模闆越難以維護。
分類管理,目錄作為單元化資源
從架構圖和上文模闆中不難看出,并不是所有的Resource都有直接關聯關系,比如VPC隻和VSwitch和SecurityGroup有關,與其他資源的建立無直接關聯關系。是以,為了使整個架構的邏輯可以更加清楚的展示在模闆中,我們可以考慮,對資源進行分類,将每一類資源用一個單獨的目錄進行管理,最後用一個模闆來管理所有的目錄,進而完成對所有資源及資源關系的串聯,如下所示:
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ ├── vpc/
│ │ ├── variables.tf
│ │ ├── main.tf
│ │ ├── outputs.tf
│ ├── slb/
│ │ ├── variables.tf
│ │ ├── main.tf
│ │ ├── outputs.tf
│ ├── ecs/
│ ├── rds/
│ ├── oss/
将該架構中的資源分為網絡(VPC),負載均衡(SLB),計算(ECS),資料庫(RDS)和存儲(OSS)這幾類,然後将上文模闆中的資源分别在對應的目錄中予以實作。
接下來,用統一的模版
main.tf
将這些目錄關聯起來,如下所示:
// VPC module
module "vpc" {
source = "./modules/vpc"
name = "new-netwtok"
...
}
// Web Tier module
module "web" {
source = "./modules/ecs"
instance_count = 2
vswitch_ids = "${module.vpc.this_vswitch_ids}"
...
}
// Web App module
module "app" {
source = "./modules/ecs"
instance_count = 2
vswitch_ids = "${module.vpc.this_vswitch_ids}"
...
}
// SLB module(intranet)
module "slb" {
source = "./modules/slb"
name = "slb-internal"
vswitch_id = "${module.vpc.this_vswitch_ids.0.id}"
instances = "${concat(module.web.instance_ids, module.app.instance_ids,)}"
...
}
// SLB module(internet)
module "slb" {
source = "./modules/slb"
name = "slb-external"
internet = true
instances = "${module.web.instance_ids}"
...
}
// RDS module
module "oss" {
source = "./modules/rds"
name = "new-rds"
...
}
// OSS module
module "oss" {
source = "./modules/oss"
name = "new-bucket"
...
}
可以看出,
main.tf
中資源的結構更加清楚,更加接近于架構圖。
同時,大家已經注意到了,
main.tf
引入了一個
module
,通過module将資源目錄串聯起來。
什麼是Module
Module是 Terraform 為了管理單元化資源而設計的,是子節點,子資源,子架構模闆的整合和抽象。正如本文架構中提到的,在實際複雜的技術架構中,涉及到的資源多種多樣,資源與資源之間的關系錯綜複雜,資源模版的編寫,擴充,維護等多個問題的成本都會不斷增加。将多種可以複用的資源定義為一個module,通過對 module 的管理簡化模闆的架構,降低模闆管理的複雜度,這就是module的作用。
除此之外,對開發者和使用者而言,隻需關心 module 的 input 參數即可,無需關心module中資源的定義,參數,文法等細節問題,抽出更多的時間和精力投入到架構設計和資源關系整合上。
開源Module,使其更完善,更分享,更便捷
上文中,雖然已經實作了module,但是這個module隻能在自己本地機器上實作,無法實作與他人的實時分享,無法實作團隊内部的及時共享。
Terraform 提供了
Module 的注冊位址,将自己的module上傳到Github,并注冊為一個Terraform Module後,即可将遠端的Module應用到我們自己的模闆中。
利用開源 module,我們可對上文中的模闆進行完善:
// VPC module
module "vpc" {
source = "alibaba/vpc/alicloud"
...
}
// Web Tier module
module "web" {
source = "alibaba/ecs-instance/alicloud"
...
}
// Web App module
module "app" {
source = "alibaba/ecs-instance/alicloud"
...
}
// SLB module(intranet)
module "slb-intranet" {
source = "alibaba/slb/alicloud"
...
}
// SLB module(internet)
module "slb-internet" {
source = "alibaba/slb/alicloud"
...
}
// OSS module
module "rds" {
source = "terraform-alicloud-modules/rds/alicloud"
...
}
// OSS module
module "oss" {
source = "terraform-alicloud-modules/oss/alicloud"
...
}
Module 讓資源模闆架構更清楚,模闆管理更簡單;開源 Module 讓資源模闆更便捷,更分享。除此之外,開源 Module 可實作對模闆的版本控制,基于不同的版本,實作不同架構不斷更新的控制和完善。
歡迎加入 Terraform AliCloud Modules
目前我們已經在在 Terraform Module 上釋出了一些
常用的 Module,但這些 Module 遠遠無法滿足大家多種多樣的技術架構和複雜的應用場景,非常歡迎大家可以将自己的模闆Module注冊到官方 Module 上,借助社群的力量,不斷完善自己模闆,豐富我們的社群。