第 9 章:使用 Terraform 模組
前面練習過程中,我們寫了不少的 Terraform 組態檔,但都同樣是要建立網頁伺服器的,我想應該有辦法製作可重複使用的組態,減少一些重工的行為。
接下來要認識的 Terraform 模組 (Modules) 就可以解決這些問題。
Terraform 模組 Modules
模組 (Modules) 是在一個資料夾下的多個組態檔組合,可以被多次的呼叫,以達到重複使用組態資源的目的。
所有的 Terraform 組態都是以模組的型式在運作的,平常執行 terraform 指令所在的工作資料夾,叫做「根模組」(root module)。
模組的好處
如同其他程式語言一樣,模組化帶來很多的好處:
- 更容易整理組態
- 封裝組態
- 不用重複造輪子
- 提供一致的組態設計方式
呼叫模組
要呼叫模組時,可以在你的組態檔裡使用模組區塊 (module block) 來呼叫模組。Terraform 在遇到模組區塊時會自行載入該模組的組態檔。
module "name" {
source = "module_path"
}
模組區塊一定要有的引數 (argument) 是 source
,填入的值是要使用的模組路徑。
模組的來源可以是在本地的檔案,也可以是遠端的資源。
Terraform Registry 網址: https://registry.terraform.io/
HashiCorp 官方維運的服務,提供各種的供應商外掛跟模組,也可以上傳分享自己製作的模組。
今天我們不一點一點的打造基礎架構,而是要練習用現成的模組完成基礎架構。
你可以在 Terraform Registry 上搜尋適合的模組,Terraform 官方也有準備很多好用的模組,例如 AWS VPC 模組: https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/
打開網頁你會看到詳細的模組說明,右側會有一個快速使用範例。
接下來我們要來試著建立一個完整的基礎架構。完整檔案可以參考 Github 上的範例
建立 main.tf 檔案
main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
}
}
provider "aws" {
region = "ap-northeast-1"
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "example-vpc"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a", "ap-northeast-1d", "ap-northeast-1d"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
tags = {
Terraform = "true"
Environment = "dev"
}
}
module "web_server_sg" {
source = "terraform-aws-modules/security-group/aws//modules/http-80"
name = "web-server"
description = "sg for http ingress"
vpc_id = module.vpc.vpc_id
ingress_cidr_blocks = ["0.0.0.0/0"]
}
data "aws_ami" "ubuntu-focal" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/*ubuntu-focal-20.04-amd64-server-*"]
}
owners = ["099720109477"]
}
data "template_file" "user_data" {
template = file("user_data.yaml")
}
module "ec2_instances" {
source = "terraform-aws-modules/ec2-instance/aws"
name = "example-ec2-cluster"
instance_count = 2
ami = data.aws_ami.ubuntu-focal.id
instance_type = "t2.micro"
vpc_security_group_ids = [module.vpc.default_security_group_id, module.web_server_sg.this_security_group_id]
subnet_ids = module.vpc.public_subnets
#subnet_id = module.vpc.public_subnets[0]
user_data = data.template_file.user_data.rendered
tags = {
Terraform = "true"
Environment = "dev"
}
}
這次我們使用了三個模組:
module "vpc"
: 使用terraform-aws-modules/vpc/aws
模組,建立 aws VPCmodule "web_server_sg"
: 使用terraform-aws-modules/security-group/aws//modules/http-80
,建立 http 的安全群組module "ec2_instances"
: 使用terraform-aws-modules/ec2-instance/aws
,建立兩台虛擬伺服器
建立 root output.tf 檔案
想要取得模組的輸出資料,格式是 module.<MODULE NAME>.<OUTPUT NAME>
我們試著把 public subnet 跟 public ip 輸出,範例如下:
output.tf
output "vpc_public_subnets" {
description = "IDs of the VPC's public subnets"
value = module.vpc.public_subnets
}
output "ec2_instance_public_ips" {
description = "Public IP addresses of EC2 instances"
value = module.ec2_instances.public_ip
}
執行 init
每當使用到新的模組是就要執行指令 terraform init
,Terraform 會把模組下載到 .terraform/modules
資料夾裡。
terraform init
Initializing modules...
Downloading terraform-aws-modules/ec2-instance/aws 2.15.0 for ec2_instances...
- ec2_instances in .terraform/modules/ec2_instances
Downloading terraform-aws-modules/vpc/aws 2.51.0 for vpc...
- vpc in .terraform/modules/vpc
Downloading terraform-aws-modules/security-group/aws 3.16.0 for web_server_sg...
- web_server_sg in .terraform/modules/web_server_sg/modules/http-80
- web_server_sg.sg in .terraform/modules/web_server_sg
...
Terraform has been successfully initialized!
.terraform/modules
資料夾裡面大概的長相:
.terraform/modules folder
.terraform/modules
├── ec2_instances
├── modules.json
├── vpc
└── web_server_sg
執行 apply
執行指令 terraform apply
的方法是一樣的,確認執行計畫後輸入 yes
。
可以看到這些模組把我們要的 vpc, security-group, instance 都設定好,其他依賴的資源也一起準備好了。
terraform apply
Apply complete! Resources: 34 added, 0 changed, 0 destroyed.
Outputs:
ec2_instance_public_ips = [
"54.238.87.143",
"3.112.40.26",
]
vpc_public_subnets = [
"subnet-0f1fdfe4cf3d3bda0",
"subnet-09410b2bbd87c5876",
"subnet-0f89ceed33412208b",
]
執行 destroy
結束這一輪的練習,輸入指令 terraform destroy
,並輸入 yes
刪除剛剛建立的基礎架構。
嘗試過如果使用現成的模組後,接下來我們要試著製作自己的模組。
一個基本的模組 (module) 大概會有以下幾個檔案:
README.md
說明模組用途的文件main.tf
主要的組態設定檔variables.tf
定義模組的變數,變數會成為module
區塊的引數 (arguments)outputs.tf
定義模組的輸出,輸出會成為可以從模組外取得的資訊,可以用來傳遞資訊給其他組態
這次的自製模組,我們要在 AWS S3 建立託管的靜態網站。