Day 06-大 module 小 module,能够重复使用又好维护的就是好 module

大 module 小 module,能够重复使用又好维护的就是好 module

上一章介绍 module 的基本原理,然而并没有说明实务上如何实践。另外,本地 module 开发上还有一些问题,例如档案分享,与版本锁定。

本章会讲解远端的 module,以及实务上 module 的开发流程

课程内容与代码会放在 Github 上: https://github.com/chechiachang/terraform-30-days

赛後文章会整理放到个人的部落格上 http://chechia.net/

追踪粉专可以收到文章的主动推播

https://ithelp.ithome.com.tw/upload/images/20210901/20120327NvpHVr2QC0.jpg


Remote module

Terraform 支援许多类型的 module

上一章使用的范例,module source 都是本地档案的路径,透过路径去找到本机上的 module,称为 local-path

module "registry" {
  for_each = toset(local.environments) # convert tuple to set of string
  source = "../../..//azure/modules/container_registry"
  #source = "/Users/che-chia/my-workspace/terraform-30-days//azure/modules/contrainer_registry"
  ...
}

除了 local path 以外,最常使用的是 Git

Git remote module

官方文件在此

Git remote module 原理非常简单,在 init 的时候,使用 git 向远端的 git repository 取得 module .tf 档案,在本地的 .terraform 里头暂存一份,plan 的时候使用 .terraform 内的 module。source 设定参考 _poc/container_registry_module_remote

module "registry" {
  for_each = toset(local.environments) # convert tuple to set of string

  source = "git::ssh://[email protected]/chechiachang/terraform-30-days.git//azure/modules/container_registry?ref=main"

  #source = "git::https://[email protected]/chechiachang/terraform-30-days.git//azure/modules/container_registry?ref=main"
  #source = "[email protected]:chechiachang/terraform-30-days.git//azure/modules/container_registry?ref=v1.0.0"
  #source = "[email protected]:chechiachang/terraform-30-days.git//azure/modules/container_registry?ref=f1d8c86de3aebc40f16bc3a015f9a42b70dba209"
  ...
}
  • source 的格式 git::protocol://repo-url//path?ref=git-ref
    • git 支援使用 ssh / https,推荐使用 ssh
    • repo-url 就是 repository 完整 url,支援所有
    • 如果是私有的 repository 也可使用,使用 ssh key 存取十分方便
    • path 就是 module 在 repository 内的路径 //azure/modules/...
    • (optional) git reference,可以指向 branch / git commit / tag
  • 如果 repository 是使用 github.com / bitbucket,可以使用 github.com / bitcucket.org

Git remote module behaior

我们实际使用 _poc/container_registry_module_remote 来操作说明:

terraform init

Initializing modules...
Downloading git::ssh://[email protected]/chechiachang/terraform-30-days.git?ref=v0.0.1 for registry...
- registry in .terraform/modules/registry/azure/modules/container_registry
Downloading git::ssh://[email protected]/chechiachang/terraform-30-days.git?ref=v0.0.1 for test...
- test in .terraform/modules/test/azure/modules/container_registry

Initializing the backend...
...
Initializing provider plugins...
...

init 的时候,比起 local-path module,Terraform 额外执行 git clone,将 module 中的 source clone 到本地 .terraform 资料夹。照惯例进去开一下

tree -L 1 .terraform

.terraform
├── modules
├── providers
└── terraform.tfstate

2 directories, 1 file

cat .terraform/modules/modules.json | jq

{
  "Modules": [
    {
      "Key": "test",
      "Source": "git::ssh://[email protected]/chechiachang/terraform-30-days.git//azure/modules/container_registry?ref=v0.0.1",
      "Dir": ".terraform/modules/test/azure/modules/container_registry"
    },
    {
      "Key": "",
      "Source": "",
      "Dir": "."
    },
    {
      "Key": "registry",
      "Source": "git::ssh://[email protected]/chechiachang/terraform-30-days.git//azure/modules/container_registry?ref=v0.0.1",
      "Dir": ".terraform/modules/registry/azure/modules/container_registry"
    }
  ]
}

由於使用远端的 module ,每次对 module 内杜设定有更改,都需要重新执行 terraform init,例如:

  • 上一张提到的更改 module 名称等设定
  • 更改 source 使用其他 module
  • 版本升级,使用新版的 module,更改 ?ref=v0.0.1 变成 ?ref=v0.0.2

除了需要 init 下载以外,terraform plan && terraform apply 都与之前的使用完全一样。

Git module Pros & Cons

Pros

  • 版本锁定
  • 方便分享,便利使用社群维护的 module
  • 由於使用本地的 git 设定执行 git clone,自己电脑上有关 git 的设定与功能都会生效
    • i.e. private repository 也可以使用本地的 git credential 存取

Cons

  • 增加 terraform init 需要的时间
  • .terraform 使用更多硬碟空间
  • 查找原始码的时候,需要一层一层去搜寻多个 repository

目前我们的 module 结构简单,而且没有额外依赖其他 module,所以缺点感觉不太出来。实务上许多复杂的 module 内部都还会有更多曾依赖的 module,每个 module 自己还有依赖的 providers,每次下载都需要时间,.terraform 都会变一大包

虽然说了缺点,然而这些小缺点并不影响开发,我们还是会选择使用 remote module

Good Practices

  • 本地的开发与测试,可以使用 local-path,方便且加速流程
  • 让其他环境使用的 module 务必推到远端,并且打上 version tag
  • 永远使用锁定 git module 版本, tag > commit > branch
    • 避免远端 branch 推进改变,影响本地
    • 使用 commit 的可读性极差,会造成以後维护 pull 新版本的麻烦

Terraform Registry

Terraform 官方提供了 module 分享库,称为Terraform Registry,上面储存许多 provider 与 modules

是的,当我们使用 provider {},预设都会到 Terraform Registry 上去下载 provider 的档案。Terraform 官方在上头维护许多 remote module,可以直接使用。

直接看例子:

我们可以使用 Terraform Registry: Azure/compute,来创建 Azure Compute VM,这个 module 除了 vm 以外,还包含常与 vm 共用的资源,例如 network interface,security group,public ip...等,贴近常见使用情境

azurerm_availability_set.vm
azurerm_network_interface.vm
azurerm_network_interface_security_group_association.test
azurerm_network_security_group.vm
azurerm_network_security_rule.vm
azurerm_public_ip.vm
azurerm_storage_account.vm-sa
azurerm_virtual_machine.vm-linux
azurerm_virtual_machine.vm-windows
random_id.vm-sa

使用上也非常方便,Terraform Registry 上多半会提供 Readme,范例,以及 input 的参数。

笔者个人比较少使用 Registry,笔者习惯直接看 Github 上的 .tf 程序码,毕竟 provider 除了会将 module 上传至 Terraform Registry 外,也会上传到 Github,例如Github: Azure compute

各位可以依照自己使用习惯选择。也许之後 Terraform Registry 会推出更多新功能,期待之後的改进会变得更好用。

Other

Terraform 仍支援其他 remote module 如:s3, gcs...,笔者认为 git 还是最常使用的,而且其他类型 module 概念都类似,有需求的朋友可以依据需求尝试使用其他 module。

development with multiple environments

理解 module 的基本原理与使用,接下来要说明实务中如何开发 module。

  • 先 Google / Github 上找看看有没有社群维护,写好的 module 可以直接使用
  • 为 module 与 .tf 准备测试环境,例如:
    • 先在 dev/southeastasia/container_registry 编辑 local-path module
    • 稳定了,推上 branch / release candidate tag,让 stag 使用。也会将 app 丢到环境中去测试 (stag/southeastasia/container_registry)
    • QA 都测试完了,表示 module 已经稳定,打上 release tag,供 prod 使用(prod/southeastasia/container_registry)
    • prod infrastructure 使用到的 tag 都会是稳定版本,依照稳定版本更新,避免不正确的 infrastructure 出现在 prod

module 是持续修改,很难一开始就写出完美的 module。使用 terraform 来落实 infrastructure as code,可以在 infrastructure 中导入软件开发流程,透过 gitflow,让 instructure 方便测试,让环境更稳定。

更多 Terraform IaC 的好处,我们在後面章节实际带各位体会。

Homework

  • _poc/compute
    • 基本背景知识:需要对 Azure compute VM 有一定了解
    • 设定参数,参数的说明在Github: azure/compute variables.tf,注意 default 值
    • 参考 Github: azure/compute main.tf,调整参数
    • init && plan && apply
    • plan 产生较多 resource,请把它看完看清楚,养成好习惯
      • 不清楚的资源请在 google terraform + resource,查一下 resource 文件
    • 尝试处理过程中的错误,一般来说设定正确的 variable 可以解决
    • 成功 apply 後,到 azure web portal 上看一下产生出来的资源
    • 修改参数,调整成自己喜欢的样子
  • 找另外一个 github 上的 remote module,尝试参考 compute 的架构完成

NOTE:

  • 请尽量使用 Standard_B1s 免费的 vm size,详请请见 Azure Free Plan 清单
  • 完成後执行 terraform destroy,清除所有资源,以节省费用

Can it be more DRY

  • 每个 root module 都有 provider.tf
  • 重复的 locals 参数,例如:resource_gropu_namelocationenvironment...
  • provider.tf 中需要手动指定 backend key = "xxx.tfstate",才能将各自的 state 保存在远端独立的路径
  backend "azurerm" {
    resource_group_name  = "terraform-30-days"
    storage_account_name = "tfstatee903f2ef317fb0b4"
    container_name       = "tfstate"
    key                  = "container_registry_module.tfstate"
  }

有没有可能在更精简,更方便? 我们介绍 Terragrunt


<<:  Spring Framework X Kotlin Day 1 Introduction

>>:  Halcon (机器视觉)的介绍

RISC-V on Rust 从零开始(5) - RISC-V 指令集分析

有了基本档案架构後,开始动工指令的部分。RISC-V将指令分成数个子集,其中包括RV32I、RV32...

Day 05 - 行前说明 — UI 元件分类你知多少?

今天是行前说明的最後一篇了,前面几篇都是很架构面的知识,而今天要讲的就是真的很贴近 UI 元件的分...

创建App-厂商合作提案

创建App-厂商合作提案 本界面的背景依然使用处理过的图片,界面非常简单,只有主题「如何与TeenM...

[Day 2] -『 GO语言学习笔记』- GO语言简介

GO语言简介 Go(Golang)是Google开发的一种语言。2007年,Google设计Go原先...

[Day30] 完赛心得

30天完赛心得 今年是第一次参赛,在八月初的时候开始查资料跟写草稿,等於提前了一个多月准备,时间上其...