Terraform Infrastructure as Code: Example repository
This article is part of 從零開始的 Infrastructu as Code: Terraform
- Get-started examples / SOP on Github
- Introducation to Terraform Iac: Speaker transcript
- Presentation
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
tree
├── README.md
├── SOP.md
├── aws/
├── azure/
└── gcp/
TL;DR
選擇使用的雲平台,這邊提供三家範例,例如我這邊使用 gcp,當然你就要準備 GCP 的帳號,並且下載有執行權限的用戶 credential json key 等等。
雖然我沒收 gcp 錢,這邊還是推廣一下 gcp 的 free credit 試用。阿要用 Azure Cloud 的 free credit 來執行這個範例也是完全沒問題,非常夠用。唯有 AWS 的試用方案跟剩下兩家不太一樣,這個 repository 起的服務可能會超過 AWS 的免費額度涵蓋範圍,總之請自己注意。
git clone https://github.com/chechiachang/terraform-playground
cd gcp
DIR=my-new-project make project
cd my-new-project
vim *tf
terraform init
terraform plan
terraform 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 也是其他的專案,先忽略他。
gcp
├── README.md
├── Makefile
├── my-new-project/
├── gke-playground/
├── national-team-5g/
├── templates/
└── modules/
cd my-new-project
進入 my-new-project 下,可以看到裡面已經有一些檔案,我們首先要編輯的是這個 terraform.tf
my-new-project
├── Makefile
├── provider.tf
├── terraform.tf
└── variables.tf
vim terraform.tf
terraform.tf 是 terraform 本身的設定
這邊是 Terraform Backend 的設定,如果不知道什麼是 terraform backend 這個我們明天的文章會講。這邊使用的 backend 是 terraform 官方自家的 terraform cloud,可以在網站上
- 註冊使用者,填到底下
organization
這裡 - 創建一個 workspace,填到
workspace.name
這裡
terraform {
# Create a remote organization on https://app.terraform.io
backend "remote" {
# Provide terraform credential by
# - terraform login (suggested)
# - use User API Token
#token = ""
hostname = "app.terraform.io"
organization = "chechia"
workspaces {
name = "terraform-playground"
}
}
}
provider.tf 是 provider 的設定
terraform client 會把 tf 檔案拿來運算,透過 Provider ,將需求實際轉化成 API call ,然後送到公有雲或是其他目標。這邊就只講到這樣。
provider 為了工作,可能會需要提供一些參數,例如 google 的 provider 會需要在這裡提供 credential_json 的路徑,請把它放在適合的地方,然後用絕對路徑指向 google
NOTE: 不要 commit credential key 到 git repository 裡面。可以放到外層資料夾,或至少要 gitignore 掉。
provider "google" {
version = "~>v3.25.0"
credentials = file(var.credential_json)
project = var.project
region = var.region
}
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。
# Global
variable "project" {
type = string
default = "myproject"
}
variable "credential_json" {
type = string
default = "../credentials/gke-playground-0423-aacf6a39cc3f.json"
}
variable "region" {
type = string
default = "asia-east1"
}
Create
這裡我們試著創建一台 GCE,使用下列指令,會發現多了一個檔案 compute_instance.tf。
NAME=my-new-gce make gce
my-new-project
├── Makefile
├── compute_instance.tf
├── provider.tf
├── terraform.tf
└── variables.tf
內容大概是
module "my-new-gce" {
source = "../modules/compute_instance"
providers = {
google = google
}
project = var.project
name = "my-new-gce"
image = "https://www.googleapis.com/compute/v1/projects/centos-cloud/global/images/centos-7-v20200429"
machine_type = "n1-standard-1"
network = "projects/${var.project}/global/networks/myproject"
subnetwork = "projects/${var.project}/regions/asia-east1/subnetworks/myproject"
}
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,這邊沒有什麼特別的。
terraform plan
terraform apply
小結
- 有規律地整理 project 可以降低維護成本
- 善用 module 封裝,可以提高整體的重用性與易用姓,提高開發效率
- 使用 template tf 可以加速重複的資源產生步驟
問題: 此時的資料夾中還是充滿大量重複的 code,例如到處都需要 provider、重複的 module,一大堆重複的東西。有沒有可能再讓我們的程式碼更 DRY 一點呢?
Terragrunt 幫我們實現這點,非常值得使用的工具。請見下篇分享。