Module 讓 Terraform 使用更簡單
眾所周知,Terraform 是一個開源的自動化的資源編排工具,支援多家雲服務提供商。阿里雲作為第三大雲服務提供商,terraform-alicloud-provider 已經支援了超過 90 多個 Resource 和 Data Source,覆蓋20多個服務和產品,吸引了越來越多的開發者加入到阿里雲Terraform生態的建設中。
隨著 Resource 和 DataSource 的不斷增加和完善,業務架構的不斷髮展,Terraform 模板編寫的成本和複雜度也在不斷的增加。如何讓Terraform 模板更加簡單和重用,就是本文所要解決的問題。
本文將通過一個典型的負載均衡架構,向大家介紹如何使用 Module 簡化 Terraform 的模板。
如圖所示,這個架構中,包含 ECS 例項,SLB 例項,RDS 例項,OSS 等資源和服務,同時所有的 ECS,RDS 和部分 SLB 在一個 VPC 網路環境中。
將所有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" {
source = "alibaba/slb/alicloud"
...
}
// SLB module(internet)
module "slb" {
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 上,藉助社群的力量,不斷完善自己模板,豐富我們的社群。
原文連結 本文為雲棲社群原創內容,未經允許不得轉載。