Terraform Infrastructure as Code: Example repository

Share on:

This article is part of 從零開始的 Infrastructu as Code: Terraform

Check my website chechia.net for other blog. Follow my page to get notification. Like my page if you really like it :)


上面講了很多 terraform 的操作範例,應該看到這裡,對於 terraform 基本上是什麼東西,應該有些概念了。然而這樣還不能算是學會 terraform,這種工具的東西一定要有實際操作過的經驗才算是學會。

可以直接參考 Terraform 官方的 Get-started 文件來操作學習,我這邊也提供一個 Git repository 讓大家上手,當作初次操作的框架。

提供做為範例的原始碼

這個 Github Repository 是我給社群演講所使用的範例,第一次使用的可以參考

https://github.com/chechiachang/terraform-playground

1tree
2├── README.md
3├── SOP.md
4├── aws/
5├── azure/
6└── gcp/

TL;DR

選擇使用的雲平台,這邊提供三家範例,例如我這邊使用 gcp,當然你就要準備 GCP 的帳號,並且下載有執行權限的用戶 credential json key 等等。

雖然我沒收 gcp 錢,這邊還是推廣一下 gcp 的 free credit 試用。阿要用 Azure Cloud 的 free credit 來執行這個範例也是完全沒問題,非常夠用。唯有 AWS 的試用方案跟剩下兩家不太一樣,這個 repository 起的服務可能會超過 AWS 的免費額度涵蓋範圍,總之請自己注意。

 1git clone https://github.com/chechiachang/terraform-playground
 2cd gcp
 3DIR=my-new-project make project
 4
 5cd my-new-project
 6vim *tf
 7
 8terraform init
 9terraform plan
10terraform apply

這樣應該就會跑完。然後我們講解幾個地方。

工作目錄

Terraform 預設是以當下執行的目錄作為基準,掃描資料夾中的 .tf 檔案。所以可以把一個一個獨立的專案先用資料夾裝好,彼此內容互不干涉。

我們這邊創建新的 subdirectory,這邊是以 my-new-project 為範例。這邊指的 project 只是一個 terraform resource 範圍,可以但不用是一個真實的 gcp project。terraform 執行是以一個 directory 為範圍,不同 project directory 可以透過不同 terraform 指令控制。如果是獨立的服務希望獨立管理也可以切開。

我寫了一個簡單的 Makefile,進一步封裝基本的指令,基本上不需要 Makefile 以外的操作。 make project 是其中一個指令,幫忙創建資料夾、布置 Makefile 與基本的 terraform 設定等等。

如果團隊有多人協作,非常推薦使用統一 Makefile / 或是 bash script 封裝,統一這些編輯的雜事,降低不同人編輯出錯的風險。

目錄結構

總之我們現在 cd 到 my-new-project 的工作目錄下,這個目錄代表一個專案。其他的 gke-playgound 與 national-team-5g 也是其他的專案,先忽略他。

 1gcp
 2├── README.md
 3├── Makefile
 4├── my-new-project/
 5├── gke-playground/
 6├── national-team-5g/
 7├── templates/
 8└── modules/
 9
10cd my-new-project

進入 my-new-project 下,可以看到裡面已經有一些檔案,我們首先要編輯的是這個 terraform.tf

1my-new-project
2├── Makefile
3├── provider.tf
4├── terraform.tf
5└── variables.tf
6
7vim terraform.tf

terraform.tf 是 terraform 本身的設定

這邊是 Terraform Backend 的設定,如果不知道什麼是 terraform backend 這個我們明天的文章會講。這邊使用的 backend 是 terraform 官方自家的 terraform cloud,可以在網站上

  • 註冊使用者,填到底下 organization 這裡
  • 創建一個 workspace,填到 workspace.name 這裡
 1terraform {
 2  # Create a remote organization on https://app.terraform.io
 3  backend "remote" {
 4    # Provide terraform credential by
 5    # - terraform login (suggested)
 6    # - use User API Token
 7    #token        = ""
 8    hostname     = "app.terraform.io"
 9    organization = "chechia"
10
11    workspaces {
12      name = "terraform-playground"
13    }
14  }
15}

provider.tf 是 provider 的設定

terraform client 會把 tf 檔案拿來運算,透過 Provider ,將需求實際轉化成 API call ,然後送到公有雲或是其他目標。這邊就只講到這樣。

provider 為了工作,可能會需要提供一些參數,例如 google 的 provider 會需要在這裡提供 credential_json 的路徑,請把它放在適合的地方,然後用絕對路徑指向 google

NOTE: 不要 commit credential key 到 git repository 裡面。可以放到外層資料夾,或至少要 gitignore 掉。

1provider "google" {
2  version = "~>v3.25.0"
3
4  credentials = file(var.credential_json)
5
6  project = var.project
7  region  = var.region
8}

variable.tf 做參數的存放點

雖然上面 tf 檔案使用了 terraform / provider / variable ,但 terraform 掃描檔案時,檔名本身並不會影響。也就是說,參數你想擺哪就擺哪。不過上面是常見的命名慣例,這樣擺人類比較容易找得到。

variable 這邊設定的參數,比較像是 arguments,也就是當其他位置的 tf 檔案,引用這個資料夾作為 module 的時候,作為參數輸入的 placeholder,其他 tf 檔案可以使用 variable 關鍵字定義的參數,例如: var.project,或是 provider.tf 裡的 var.credential_json。

variable 關鍵字也可以定義 default 預設值,如果沒有定義 default,也沒有從外部傳入 argument,會在 validate 時造成 error。

 1# Global
 2variable "project" {
 3  type    = string
 4  default = "myproject"
 5}
 6
 7variable "credential_json" {
 8  type    = string
 9  default = "../credentials/gke-playground-0423-aacf6a39cc3f.json"
10}
11
12variable "region" {
13  type    = string
14  default = "asia-east1"
15}

Create

這裡我們試著創建一台 GCE,使用下列指令,會發現多了一個檔案 compute_instance.tf。

1NAME=my-new-gce make gce
2
3my-new-project
4├── Makefile
5├── compute_instance.tf
6├── provider.tf
7├── terraform.tf
8└── variables.tf

內容大概是

 1module "my-new-gce" {
 2  source = "../modules/compute_instance"
 3  providers = {
 4    google      = google
 5  }
 6
 7  project      = var.project
 8  name         = "my-new-gce"
 9  image        = "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-7-v20200429"
10  machine_type = "n1-standard-1"
11
12  network    = "projects/${var.project}/global/networks/myproject"
13  subnetwork = "projects/${var.project}/regions/asia-east1/subnetworks/myproject"
14}

module 關鍵字定義一組資源,具體的內容是這裡,簡單來說可以把一堆 tf 檔案放在一塊,然後把需要的參數使用 variable.tf 拉出去,讓其他地方引用。

source = "" 是實際引用的 module 來源

底下是這個 module 需要用到的參數,例如 project, name, image, machine_type,… 等是 gce 這個 module 需要的參數。

Makefile

NAME=my-new-gce make gce 這行指令與 terraform 無關,只是一個快速生成 compute_instance.tf 的小腳本。使用這個腳本可以

  • 快速產生 tf 檔案
  • 產生標準化的 tf 檔案,所有 project 的 compute_instance 都長一樣
  • 抽換名子 name

使用 symbolic link 讓所有 project 資料夾使用同一個 Makefile,keep your code DRY。

最後就是常規的 plan 與 apply,這邊沒有什麼特別的。

1terraform plan
2terraform apply

小結

  • 有規律地整理 project 可以降低維護成本
  • 善用 module 封裝,可以提高整體的重用性與易用姓,提高開發效率
  • 使用 template tf 可以加速重複的資源產生步驟

問題: 此時的資料夾中還是充滿大量重複的 code,例如到處都需要 provider、重複的 module,一大堆重複的東西。有沒有可能再讓我們的程式碼更 DRY 一點呢?

Terragrunt 幫我們實現這點,非常值得使用的工具。請見下篇分享。