到昨天我們建立好最基本的 Gitlab + AWS ECS 的 CI/CD 流程跟 infrastructure 了~
這時候老闆突然說:「欸那可以在另一個帳號也建一個嗎?」
請問還記得所有設定怎麼按、參數要設什麼嗎?
筆者不記得 ._./ (也沒有想要記的意思
~~為了不用記得各種設定,~~今天開始我們要進入 Infrastructure as Code 的世界啦~這 30 天我們會用的工具是 Terraform!(本日程式碼)
Terraform 是個 Infrastructure as Code(IaC)工具,使用者可以用程式碼來定義、修改與管理雲端跟地端的各種 infrastructure resource。
既然是程式碼,當然可以對它做版本控制跟重複使用。因為能重複使用,我們可以用相同的 infrastructure resource 與流程建立在不同地方建立環境,如 stage 跟 production。用 IaC 管理 infrastructure 更可以避免各種 setup 與設定是人手動操作時很容易產生的遺漏跟錯誤。(像筆者金魚腦記不起一個星期前做過什麼安裝跟設定……)
我們會以「write ⇒ plan ⇒ apply」的流程使用 terraform——寫 terraform configuration,用 plan 指令檢查各種 resource 修改是不是我們要的,最後 apply 修改到 cloud。
terraform configuration 是用 HCL 這個語法寫的,檔案副檔名是 .tf
。configuration 也可以用 JSON 格式表示,副檔名是 .tf.json
(但 JSON 很難看,所以人類還是寫 HCL 吧)。
基本會有這些檔案:
main.tf
:主要設定檔,裡面會有各種 resource
variables.tf
:集中放變數(也可以說是 input)的地方
outputs.tf
:集中放 output 的檔案,output 可以印出需要的 resource 參數,像是 EC2 instance 的 IP
terraform.tfvars
:預設的變數值檔案,terraform 預設會讀這個檔案的變數值
依照 官方文件 安裝 terraform,以 Ubuntu/Debian 來說是:
$ wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
$ sudo apt update && sudo apt install terraform
接著開一個資料夾叫 tf/
,在裡面新增 main.tf
:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
required_version = "~> 1.5"
}
provider "aws" {
profile = "default"
region = "ap-northeast-1"
}
main.tf
有兩個 block,terraform
block 指定 terraform 的版本(required_version
)以及需要的 provider 們。provider 是 terraform 用來跟 cloud、SaaS 平台及其他 API 等等溝通的 plugin,像我們要管理 AWS 的 resource,就要安裝 aws provider。除了跟 cloud 溝通,provider 也可以用來提供一些如產生 random 字串的小功能。
provider
block 設定 AWS provider 的參數。我們用 AWS default profile 作為執行 terraform 的 credential(resource 會建立在這個 profile 的 AWS account 下)以及預設 region 東京 ap-northeast-1
。
main.tf
存檔後,初始化 terraform:
$ terraform init
這個指令會初始化目前的目錄供後續 terraform 使用,它會初始化 backend、安裝 module 跟 plugin 等等。初始化後會出現 .terraform.lock.hcl
檔案,這是 terraform 記錄使用的 provider 版本的 lock 檔案。要把 lock 檔案 commit 進 git,之後如果到其他地方重新 setup terraform 的工作目錄,terraform init
就會依照 lock 檔案記錄的版本安裝 provider。
完成初始化,我們對 cloud resource 的操作就進入「修改 .tf
⇒ terraform plan
⇒ terraform apply
」的循環。terraform 會在「某個地方」偷偷記錄「目前管理的 resource 狀態跟設定」,修改 .tf
後下 plan 指令,terraform 會列出即將進行的修改,如果確認無誤就能用 apply 指令進行 cloud 上的 resource 增加、刪除或修改。「目前 resource 的狀態」在 terraform 稱為 state,會存在 backend 裡。backend 有很多種,預設是 local 檔案 terraform.tfstate
。現在我們會先用最簡單的 local 檔案,之後再轉移到 Gitlab 上。
接下來我們用 terraform 建立個 ECR repository 玩玩~(動手做比較有感)
在 main.tf
加入:
resource "aws_ecr_repository" "repo" {
name = "my-app-created-by-tf"
}
resource block 是我們用來指定 infrastructure 要有哪些 resource 的 block,是由 provider 提供的,AWS provider 的文件在 這裡 。aws_ecr_repository
表示一個 ECR 的 repository,repo
是 terraform 用來識別這個 resource 的 id、跟實際 cloud 上的 resource 無關。block 內的 name
則是 ECR repository resource 的參數,表示 repository 的名稱。所以這個 block 是建立一個 ECR repository,名字叫 my-app-created-by-tf
。
來進行第一次 terraform plan
吧!
plan 後會看到這樣的畫面,terraform 會告訴你它預計會新增、修改及刪除哪些 resource(這只是預計,還不會真的建立),這裡就是新增一個 ECR repository。下面的 Note 是提醒你說:嘿!你沒有指定這個 plan 的 output 檔案,所以我不保證你執行 apply 的時候動作會跟現在看到的一樣喔!
我們可以在 plan 後面加 -out
參數,把這份 plan 存成 myplan
這個檔案:
$ terraform plan -out=myplan
接著就可以 apply、在 AWS 上建立我們想要的 resource:
$ terraform apply "myplan"
apply 就是更新遠端 cloud 上的 infrastructure 跟設定,讓它們跟 .tf
的設置一致,所以在 .tf
的新增、修改與刪除 resource 都會在 apply 的時候反應到 cloud 裡實際的 infrastructure。如果有手動修改 cloud 裡的 resource、不是透過 terraform 修改的情況,在之後 terraform apply 的時候一樣會顯示出 changes,terraform 會試圖它管理的 resource 都變成跟 .tf
設定的一致(就是把你手動調的東西再改回去!)。手動修改後不想 terraform 又把它改回去,就要把 .tf
改成手動修改後的設定。
apply 後會看到 resource 修改的結果:
登進 AWS ECR 可以看到建立的 repository:
也可以打開 terraform.tfstate
看看所謂的 state 長什麼樣子,這個檔案不建議 commit 到 git 裡!
前面從 plan 到 apply 的過程也可以直接下不帶參數的 apply:
$ terraform apply
terraform 會列出它會執行的動作,格式跟 plan 看到的一樣,問你是不是真的要做這些動作,確認這些修改都是要的之後,輸入 yes
,terraform 才會真的做動作。(必須打完整的 yes,只有 y 是不行的!)
最後,如果不再需要這些 resource,要刪掉所有 terraform 建立的 infrastructure resource,使用 destroy 指令:
$ terraform destroy
一樣會顯示出修改內容——把剛剛建立的 ECR repository 刪除,接著問你是不是真的要執行動作,確認的話一樣輸入 yes。一樣會有 resource 修改的結果:
再到 AWS ECR web console 檢查,就沒有這個 repository 了~
做實驗的時候我們會直接 destroy 掉所有 infrastructure,但是實際使用上通常 apply 上去之後不太會全部 destroy。如果只要刪除某個 resource,也是修改 .tf
,把那個 resource block 刪掉,再次 apply 時就會看到像上面 destroyed 的修改。