模块重用资源介绍
Terraform 模块可以简化代码,减少代码重复的内容。使用 Terraform 模块可以重用基础设施资源。
在 Terraform 本身看来模块只不过是一个或多个资源的容器。通过 Terraform 的模块机制,对想要重用的资源进行封装,即可在别处像函数一样方便的调用。
模块代码结构
通过调用 modules 目录下的模块进行重用资源。
% tree modules
modules
|-- base-server // 基础服务器的模块
| |-- main.tf // 模块中用来管理一个或多个基础设施资源
| |-- outputs.tf // 模块的输出,相当于通用编程语言中的返回值。
| `-- variables.tf // 模块的输入,相当于通用编程语言中,函数的参数
`-- perp-ssh // ssh 相关的模块,包括添加 ssh 公钥,开放 22 端口。
|-- main.tf
|-- outputs.tf
`-- variables.tf
模块 main代码
基础服务模块 main代码
base-server/main.tf
内容
创建 EC2 实例,获取安全组ID,开放其他端口。
/*
* 基础设施模块
*/
# 数据源获取安全组ID
data "aws_security_groups" "default" {
filter {
name = "group-name"
values = ["default"]
}
}
# 创建EC2实例
resource "aws_instance" "server" {
ami = lookup(var.amis, var.region)
instance_type = var.instance_type
key_name = var.ssh_key_name
user_data = var.server_script
tags = {
Name = var.server_name
}
}
# 开放其他端口
resource "aws_security_group_rule" "other" {
type = "ingress"
from_port = var.server_port
to_port = var.server_port
protocol = "tcp"
cidr_blocks = [ "0.0.0.0/0" ]
security_group_id = data.aws_security_groups.default.ids[0]
}
Perp 设施模块 main代码
perp-ssh/main.tf
内容
获取安全组ID,创建 SSH 登陆密钥,开放22端口。
/*
* 准备 SSH
*/
# 数据源获取安全组ID
data "aws_security_groups" "default" {
filter {
name = "group-name"
values = ["default"]
}
}
# 添加 SSH 登陆密钥
resource "aws_key_pair" "ssh" {
key_name = "admin"
public_key = file(var.public_key)
}
# 开放 22 端口,允许 SSH 登陆
resource "aws_security_group_rule" "ssh" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [ "0.0.0.0/0" ]
security_group_id = data.aws_security_groups.default.ids[0]
}
模块输入
和通用编程语言中的函数具有参数相似,Terraform 模块也支持传递参数。为了使 Terraform 模块能够使用参数,只需利用 variables 文件为他什么数据变量即可。
下面代码中不包含默认的值,因而在调用模块的时候,才能传递参数。
基础服务模块 variables代码
base-server/variables.tf
内容
variable "region" {
type = string
description = "aws region"
}
variable "amis" {
type = map
description = "ami id"
}
variable "instance_type" {
type = string
description = "ec2 instance type"
}
variable "ssh_key_name" {
type = string
description = "ssh key name"
}
variable "server_name" {
type = string
description = "service name"
}
variable "server_port" {
type = string
description = "server port"
}
variable "server_script" {
type = string
description = "server post run script"
}
Perp 设施模块 variables代码
perp-ssh/variables.tf
内容
variable "public_key" {
type = string
description = "ssh public key"
}
模块输出
Terraform 模块输出的概念来自通用编程语言中函数具有返回值的想法。跟模块输入相似。只要为 Terraform 模块定义输出变量即可实现模块输出。
基础服务模块 outputs代码
base-server/outputs.tf
内容
输出基础设施的IP地址
output "ip" {
value = aws_instance.server.public_ip
description = "aws ec2 public ip"
}
Perp 设施模块 outputs代码
perp-ssh/outputs.tf
内容
方便其他地方引用该模块的输出属性。
output "key_name" {
value = aws_key_pair.ssh.key_name
description = "ssh key name"
}
模块调用
定义完成模块之后,调用模块需要使用 Terraform 提供的 module
代码块。
主服务 main代码
main.tf
内容
/*
* 使用基础设施服务调用
*/
# 供应商
provider "aws" { // 云供应商
region = var.region // 地域
}
# 调用模块,创建 ssh key
module "ssh-key-name" {
source = "./modules/perp-ssh"
public_key = var.public_key
}
#调用模块创建服务器 nginx
module "nginx-server" { // "nginx-server" 为模块名称
source = "./modules/base-server" // 指定本地模块路径,或者远程模块的地址
server_name = "nginx-server" // 服务器名称
server_port = 80 // 开放的服务器端口
server_script = templatefile("setup-nginx.sh", { time = timestamp()}) //服务器创建后执行的脚本
region = var.region
amis = var.amis
instance_type = var.instance_type
ssh_key_name = module.ssh-key-name.key_name
}
#调用模块创建服务器 ss
module "ss-server" {
source = "./modules/base-server"
server_name = "ss-server"
server_port = 8388
server_script = templatefile("setup-ss.sh", { password = var.ss_password})
region = var.region
amis = var.amis
instance_type = var.instance_type
ssh_key_name = module.ssh-key-name.key_name
}
主服务 variables代码
variables.tf
内容
variable "region" { // 变量名 region,不可用重复。花括号里面是参数
type = string // 输入变量的类型
default = "us-west-2" // 变量的默认值
description = "AWS region" // 变量的描述
}
variable "amis" {
type = map
default = {
us-west-2 = "ami-03f65b8614a860c29" // ubuntu ami
}
description = "AWS ID"
}
variable "instance_type" {
type = string
default = "t2.micro"
description = "EC2 instance type"
}
variable "public_key" {
type = string
default = "id_rsa.pub"
description = "SSH public key"
}
variable "ss_password" {
type = string
description = "ss password"
}
主服务 outputs代码
outputs.tf
内容
这里不再引用资源的属性,而是模块的输出。
output "WEB_IP" {
value = module.nginx-server.ip // 这里引用模块的输出
description = "nginx web server ip address"
}
output "SS_IP" {
value = module.ss-server.ip
description = "shadowsocks server ip address"
}
setup-ss.sh脚本
setup-ss.sh
内容
sudo apt update
sudo apt install -y docker.io
cat > /vat/tmp/ss-config.json <<EOF
{
"server": "0.0.0.0",
"server_port": 8388,
"local_port": 1080,
"password": "${password}",
"timeout": 600,
"method": "chacha20-ietf-poly1305",
"fast_open": true
}
EOF
sudo docker run \
-v /var/tmp:/var/tmp \
-e ARGS='-c /var/tmp/ss-config.json' \
-p 8388:8388 \
-p 8388:8388/udp \
-d \
shadowsocks/shadowsocks-libev
setup-nginx.sh脚本
setup-nginx.sh
内容
#!/bin/bash
sudp apt update
sudo apt install -y nginx
echo Cerated: ${time} | sudo tee /usr/share/nginx/html/index.html
exit 0
ubuntu 系统的index文件可能不是这个路径。
Terraform 部署
初始化 Terraform
首先执行命令 terraform init
初始化 terraform 以便让 terraform 下载或更新 模块。
% terraform init
Initializing the backend...
Initializing modules...
- nginx-server in modules/base-server
- ss-server in modules/base-server
- ssh-key-name in modules/perp-ssh
...
init 了上面上个服务调用的两个模块,
Apply 部署
% terraform plan
% terraform apply
Enter a value: Wsj@123456
Enter a value: yes
...
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
Outputs:
SS_IP = "35.91.219.161"
WEB_IP = "54.188.38.201"
验证
这里还需要验证一下nginx页面,和ss容器启动情况。
使用外部模块
虽然编写 Terraform 模块并不复杂,如果有人已经分享了我们想要使用的模块,那么可以直接使用。
Terraform 除了可以保存到代码仓库之外,Terraform本身也提供了 Terraform Registry ,这是一个用来公开分发 Terraform 模块的平台,有官方和社区分享的多种模块。包括AWS,Google Cloud,阿里云等。
搜索模块
搜索 ec2-instance
选择 Modules 。
模块首页:
查看示例代码:
使用远程模块
main.tf
代码如下:
/*
* 使用外部模块
*/
provider "aws" {
region = "us-west-2"
}
# 调用外部模块
module "ec2-instance" {
source = "terraform-aws-modules/ec2-instance/aws" // terraform registry 的地址
version = "5.5.0" // 模块版本
ami = "ami-03f65b8614a860c29" // ec2 参数
instance_type = "t2.micro"
name = "myec2"
vpc_security_group_ids = ["sg-572b3b6c"]
}
执行初始化部署
terraform init
terraform plan
terraform apply