使用 atlantis 做 terraform automation,Terraform Remote Plan & Remote Apply
課程內容與代碼會放在 Github 上: https://github.com/chechiachang/terraform-30-days
賽後文章會整理放到個人的部落格上 http://chechia.net/
如果使用 github.com,完全可以使用 Github Action,來執行 terraform automation,除了本課程內有提供範例外,網路上已經有更多的範例可以參考
然而有些 version control system 是不方便使用 Github Action
這時可以考慮使用公司的 CI / CD 系統,自行寫 terraform 的 pipeline,然後整理前述課程使用到的 command 寫成 shell script 執行。只要是知名的 CI / CD 工具,都能找到許多 terraform 的 pipeline 範例,而這些範例多半是共通的。
如果不希望自己維護 terraform pipeline,現在已經有開源版本的整合工具,幫你做自動化,就是這張要介紹的 Atlantis: Pull Request Automation
參考 terraform-30-days 上 實際執行的 PR 範例
Atlantis 是一款開源免費的自動化 terraform 工具。基本工作流程很單純
Features
官方說明文件試跑 Atlantis Local Run,主要步驟為
Install atlantis
wget https://github.com/runatlantis/atlantis/releases/download/v0.17.2/atlantis_darwin_amd64.zip
unzip atlantis_darwin_amd64.zip
sudo mv atlantis /usr/local/bin/atlantis
atlantis -h
Install ngrok and run
wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip
unzip ngrok-stable-darwin-amd64.zip
sudo mv ngrok /usr/local/bin/ngrok
./ngrok http 4141
...
Forwarding http://41eb-123-194-159-122.ngrok.io -> http://localhost:4141
...
Config Github Webhook
Create Github Personal Access token
Local Run atlantis server
export URL="https://...................ngrok.io"
export SECRET="ep.................quh"
export TOKEN="ghp_..........................."
export USERNAME="chechiachang"
export REPO_ALLOWLIST="github.com/chechiachang/terraform-30-days"
atlantis server \
--atlantis-url="${URL}" \
--gh-user="${USERNAME}" \
--gh-token="${TOKEN}" \
--gh-webhook-secret="${SECRET}" \
--repo-allowlist="$REPO_ALLOWLIST"
...
{"level":"info","ts":"2021-08-31T23:03:31.616+0800","caller":"server/server.go:680","msg":"Atlantis started - listening on port 4141","json":{}}
在 Github terraform-30-days 的範例
comment atlantis help
atlantis
Terraform Pull Request Automation
...
comment atlantis plan -d azure/_poc/compute/
# atlantis log
# parse comment as command
{"level":"info","ts":"2021-08-31T23:47:23.483+0800","caller":"events/events_controller.go:417","msg":"parsed comment as command=\"plan\" verbose=false dir=\"azure/_poc/compute\" workspace=\"\" project=\"\" flags=\"\"","json":{}}
# acquired lock with id
{"level":"info","ts":"2021-08-31T23:47:24.378+0800","caller":"events/project_locker.go:80","msg":"acquired lock with id \"chechiachang/terraform-30-days/azure/_poc/compute/default\"","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
# terraform init
{"level":"info","ts":"2021-08-31T23:47:31.435+0800","caller":"terraform/terraform_client.go:280","msg":"successfully ran \"/Users/che-chia/.asdf/shims/terraform init -input=false -no-color\" in \"/Users/che-chia/.atlantis/repos/chechiachang/terraform-30-days/6/default/azure/_poc/compute\"","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
# terraform workspace
{"level":"info","ts":"2021-08-31T23:47:31.959+0800","caller":"terraform/terraform_client.go:280","msg":"successfully ran \"/Users/che-chia/.asdf/shims/terraform workspace show\" in \"/Users/che-chia/.atlantis/repos/chechiachang/terraform-30-days/6/default/azure/_poc/compute\"","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
# terraform plan
{"level":"info","ts":"2021-08-31T23:47:48.746+0800","caller":"terraform/terraform_client.go:280","msg":"successfully ran \"/Users/che-chia/.asdf/shims/terraform plan -input=false -refresh -no-color -out \\\"/Users/che-chia/.atlantis/repos/chechiachang/terraform-30-days/6/default/azure/_poc/compute/default.tfplan\\\"\" in \"/Users/che-chia/.atlantis/repos/chechiachang/terraform-30-days/6/default/azure/_poc/compute\"","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
# policy check
{"level":"info","ts":"2021-08-31T23:47:50.017+0800","caller":"events/plan_command_runner.go:214","msg":"Running policy check for command=\"plan\" verbose=false dir=\"azure/_poc/compute\" workspace=\"\" project=\"\" flags=\"\"","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
{"level":"info","ts":"2021-08-31T23:47:50.017+0800","caller":"events/policy_check_command_runner.go:36","msg":"no projects to run policy_check in","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
<= read (data resources)
Terraform will perform the following actions:
# module.linuxservers.data.azurerm_public_ip.vm[0] will be read during apply
# (config refers to values not yet known)
<= data "azurerm_public_ip" "vm" {
...
}
Plan: 9 to add, 0 to change, 0 to destroy.
Apply 也很單純,就是 apply
atlantis apply -d azure/_poc/compute/
注意:這邊 apply 下去就會自動 apply,沒有 double comfirm yes or no 了
{"level":"info","ts":"2021-08-31T23:38:43.963+0800","caller":"events/events_controller.go:417","msg":"parsed comment as command=\"apply\" verbose=false dir=\"azure/_poc/compute\" workspace=\"\" project=\"\" flags=\"\"","json":{}}
{"level":"info","ts":"2021-08-31T23:38:45.151+0800","caller":"events/apply_command_runner.go:110","msg":"pull request mergeable status: true","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
{"level":"info","ts":"2021-08-31T23:38:45.157+0800","caller":"runtime/apply_step_runner.go:38","msg":"starting apply","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
{"level":"info","ts":"2021-08-31T23:40:05.868+0800","caller":"terraform/terraform_client.go:280","msg":"successfully ran \"/Users/che-chia/.asdf/shims/terraform apply -input=false -no-color \\\"/Users/che-chia/.atlantis/repos/chechiachang/terraform-30-days/6/default/azure/_poc/compute/default.tfplan\\\"\" in \"/Users/che-chia/.atlantis/repos/chechiachang/terraform-30-days/6/default/azure/_poc/compute\"","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
{"level":"info","ts":"2021-08-31T23:40:05.868+0800","caller":"runtime/apply_step_runner.go:57","msg":"apply successful, deleting planfile","json":{"repo":"chechiachang/terraform-30-days","pull":"6"}}
實際運作的 gitflow,大約是這樣
使用 atlnatis 有底下優缺點
缺點是要多養一台或多台 atlantis server,然而 atlantis server 基本上是 stateless server,如果有 k8s 的話非常好養
上面只是在本地電腦測試一下 atlantis 的功能,實際上如果要讓 production 環境使用,還有以下代辦事項要處理
atlantis default 使用 terraform cmd,然而本課程有許多範例使用 terragrunt,atlantis 也支援,需要底下額外設定
(大家先自己研究,我有時間會來補的(汗))
Terraform Cloud 是 terraform 官方提供的 Terraform automation Saas 服務
需要收費,請見 terraform cloud pricing。然而也提供更多強大的功能,除了 atlantis 的 remote plan 與 remote apply 外,還有私有 module registry,state file 版本控管...等功能
目前不是本課程推薦的解決方案,但 terraform cloud 不斷推陳出新許多新功能,未來值得期待。本課程會依據後續參賽進度調整,有機會再分享 terraform cloud 內容。