《Terraform 101 从入门到实践》 第三章 Modules模块化

[复制链接]
发表于 2023-2-10 10:18:15 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
《Terraform 101 从入门到实践》这本小册在南瓜慢说官方网站和GitHub两个地方同步更新,书中的示例代码也是放在GitHub上,方便大家参考查看。
模块的概念

模块化是Terraform实现代码重用的方式。模块可以理解为一个包含多个资源的容器模板。封装好之后,可以给大家使用。也可以理解为代码中的函数或方法,它接收入参,经过一些声明式的调用后,输出一些结果变量。
从Terraform的代码层面来看,模块其实就是一个包含多个.tf或.tf.json文件的目录。任何一个Terraform项目,都是一个目录,所以也都是一个模块,我们把它称为根模块(Root Module)。而在它目录下的其它模块,都是子模块。我们可以调用多个模块,也可以多次调用同一个子模块。在子模块中,也可以调用其它模块。这些特点,与函数无异。
调用模块有两种方式,一种是在当前项目定义一个模块,另一种是引入外部的模块。而外部模块的方式也很多种,如Git的仓库、压缩文件等。
定义并使用模块

我们先来使用第一种方式,引用当前项目中的模块。
子模块的功能很简单,创建一个文件,文件名有随机字符串,以避免冲突。写入文件的内容可以通过参数指定。
子模块:
定义入参:创建一个文件叫variables.tf,专门用来定义入参:
  1. variable "prefix" {
  2.   type        = string
  3.   default     = "pkslow"
  4.   description = "File name prefix"
  5. }
  6. variable "content" {
  7.   type        = string
  8.   default     = "www.pkslow.com"
  9.   description = "File content"
  10. }
复制代码
这里输入有两个变量,都是字符串类型,分别是文件名前缀prefix和文件内容context。
定义模块功能,主要配置这个模块用管理的资源,一般会放在main.tf文件中,内容如下:
  1. resource "random_string" "random" {
  2.   length  = 6
  3.   lower   = true
  4.   special = false
  5. }
  6. resource "local_file" "file" {
  7.   content  = var.content
  8.   filename = "${path.root}/${var.prefix}.${random_string.random.result}.txt"
  9. }
复制代码
这里定义了两个resource,第一个是生成6位的随机字符串。第二个是生成一个文件,第二个resource使用了输入参数,还使用了第一个资源生成的结果。所以第二个resource是依赖于第一个的。输入的变量引用方式为var.xxx。
定义返回值:
可以不需要返回值,也可以定义一个或多个返回值。创建一个outputs.tf文件,内容如下:
  1. output "file_name" {
  2.   value = local_file.file.filename
  3. }
复制代码
它返回的是前面第二个resource中的值。
现在,模块random-file已经定义完成了。现在我们在根模块调用这个子模块。代码如下:
  1. module "local-file" {
  2.   source  = "./random-file"
  3.   prefix  = "pkslow"
  4.   content = "Hi guys, this is www.pkslow.com\nBest wishes!"
  5. }
复制代码
这个source是被调用模块的地址。prefix和content都是入参,之前已经定义了。
在根模块也可以定义输出变量:
  1. output "fileName" {
  2.   value = module.local-file.file_name
  3. }
复制代码
这里直接输出子模块的文件名,也就是子模块的返回变量file_name。
apply后通过terraform output查看输出:
  1. $ terraform output
  2. fileName = "./pkslow.B2UwmR.txt"
复制代码
多个block调用同一个module

我们说过模块是为了实现代码复用,Terraform允许一个模块被多次调用。我们修改根模块的调用代码:
  1. module "pkslow-file" {
  2.   source  = "./random-file"
  3.   prefix  = "pkslow"
  4.   content = "Hi guys, this is www.pkslow.com\nBest wishes!"
  5. }
  6. module "larry-file" {
  7.   source  = "./random-file"
  8.   prefix  = "larrydpk"
  9.   content = "Hi guys, this is Larry Deng!"
  10. }
复制代码
这里两个调用的source都是一样的,都调用了random-file这个模块,只是入参不同。
根模块的输出也修改一下:
  1. output "pkslowPileName" {
  2.   value = module.pkslow-file.file_name
  3. }
  4. output "larryFileName" {
  5.   value = module.larry-file.file_name
  6. }
复制代码
执行apply后output输出结果为:
  1. $ terraform output
  2. larryFileName = "./larrydpk.txoV34.txt"
  3. pkslowPileName = "./pkslow.WnJVMm.txt"
复制代码
循环调用一个module

count方式

多次调用一个模块还有另一种方式就是循环调用,通过count来实现,具体如下:
  1. module "pkslow-file" {
  2.   count   = 6
  3.   source  = "./random-file"
  4.   prefix  = "pkslow-${count.index}"
  5.   content = "Hi guys, this is www.pkslow.com\nBest wishes!"
  6. }
复制代码
这里会调用6次子模块random-file,下标索引为count.index,它是从0开始的索引。
因此,执行后,会生成以下6个文件:
  1. pkslow-0.JBDuhH.txt
  2. pkslow-1.Z6QmPV.txt
  3. pkslow-2.PlCK5u.txt
  4. pkslow-3.a70sWN.txt
  5. pkslow-4.UnxYue.txt
  6. pkslow-5.8bSNxg.txt
复制代码
这里根模块的输出就需要修改了,它成了一个List,通过*引用所有元素:
  1. output "pkslowPileNameList" {
  2.   value = module.pkslow-file.*.file_name
  3. }
复制代码
for each方式

通过for_each也可以实现循环调用:
Map的情况:
  1. resource "azurerm_resource_group" "rg" {
  2.   for_each = {
  3.     a_group = "eastus"
  4.     another_group = "westus2"
  5.   }
  6.   name     = each.key
  7.   location = each.value
  8. }
复制代码
Set的情况:
  1. resource "aws_iam_user" "the-accounts" {
  2.   for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
  3.   name     = each.key
  4. }
复制代码
引用外部模块

除了在本项目中定义并引用模块之外,还可以引用外部的模块。在官方的仓库中已经有非常多的可重用的模块了,可以到上面查找:https://registry.terraform.io/browse/modules
比如我引用了( https://registry.terraform.io/modules/matti/resource/shell/latest )这个模块:
  1. module "echo-larry-result" {
  2.   source  = "matti/resource/shell"
  3.   version = "1.5.0"
  4.   command = "cat ${module.larry-file.file_name}"
  5. }
复制代码
执行terraform get会从仓库下载模块:
  1. $ terraform get
  2. Downloading matti/resource/shell 1.5.0 for echo-larry-result...
  3. - echo-larry-result in .terraform/modules/echo-larry-result
  4. - larry-file in random-file
  5. - pkslow-file in random-file
复制代码
在.modules目录下可以查看模块内容。
这个模块可以执行shell命令,并返回结果。我这里执行的命令是读取之前生成文件的内容。输出调用结果:
  1. output "larryFileResult" {
  2.   value = module.echo-larry-result.stdout
  3. }
复制代码
执行结果如下:
  1. larryFileName = "./.result/larrydpk.GfgMyh.txt"
  2. larryFileResult = "Hi guys, this is Larry Deng!"
复制代码
模块来源

引入模块的来源很多:

  • 本地目录
  • Terraform官方仓库
  • GitHub或其它Git仓库
  • Bitbucket
  • HTTP URLs
  • S3 Buckets
  • GCS Bucket
非常方便。我们已经介绍过比较常用的前两种了,其它更多细节可以参考:https://www.terraform.io/docs/language/modules/sources.html
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表