Infrastructure As Code Day 2 — Collaboration

smalltown
getamis
Published in
12 min readAug 3, 2019

--

背景介紹

隨著 1) 使用 Terraform 時間增加 2) 架構越來越龐大複雜 3) IaC 的生態逐漸完整,因此最近在組織內開始調整 Terraform 的開發準則,希望可以透過此系列文章 (共四篇 Unity, Testing, Collaboration, Productivity) 拋磚引玉,讓大家一起來交流在團隊內使用 Terraform 時如何克服一些常見的問題

而此系列文章有其先後順序,沒有照著閱讀不打緊;但實作的時候必須照著Unity -> Testing -> Collaboration -> Productivity 的順序,不然會導致最終結果不符合預期,文章中所使用到的 Terraform Script 都放在這邊

解決問題

單人使用 IaC 工具 terraform 其實很輕鬆,因為當要下 terraform apply 的時候,其執行結果就只需要對自己負責即可,但是假如有兩個人以上在開發同一個 IaC 專案呢?常常會發生一件事情

A: Dev 環境怎麼壞掉了?!

B: 我剛剛有用 terraform 小改一下東西 (然後 B 開始挽起袖子來查詢問題)

…過了 15 分鐘之後,另外一位同事發言了…

C: 你要先 merge 我的 PR 啦,不然有一個東西會沒有先建立出來, 導致..blablabla

在多人一起開發 terraform 的情況下,這是相當常見的問題,當撰寫的人變成 5 個人甚至是 10 個人的時候,只能透過幹架解決這個問題了(誤) 因此社群有人提供工具來彌平紛爭,也就是底下要介紹的 Atlantis

Atlantis 介紹

個人覺得 Atlantis 是一套可以讓 Terraform 達成 GitOps 的工具,使用過後也理解為什麼 Terraform 官方會將這個開源專案納入麾下,他有點像是Terraform 程式碼 & 人類 & 雲端資源三者之間的溝通橋樑一般的存在

他主要可以幫忙做到的事情有兩件 1) 將以前偷偷摸摸再開發者電腦執行的 Terraform plan/apply 跟 Git PR 整合在一起 2) 避免同一個 Terraform 內同一個資料夾或是 Workspace 同時有人去修改,底下會先從環境的設定開始,接著實際感受 Atlantis 的強大之處,最後再提一些細部的設定說明

事前準備

安裝必要元件

下面只有提到 Atlantis 和 Ngrok 的安裝步驟,有關於 Terraform 及 Terragrunt 的安裝方式請參閱此系列文章的第一篇

# 安裝 Atlantis 
(從官方下載最新版 https://github.com/runatlantis/atlantis/releases)
~$ atlantis version
atlantis 0.8.3
~$ atlantis version
atlantis 0.8.3
# 安裝 Ngrok
~$ brew cask install ngrok
# 啟動 ngrok
~$ ngrok http 4141
# 應該可以看到類似如下的輸出,然後這個 Terminal Tab 請不要關閉,就讓其在前景執行...
Session Status online
Version 2.3.34
Web Interface http://127.0.0.1:4040
Forwarding http://6613da45.ngrok.io -> http://localhost:4141
Forwarding https://6613da45.ngrok.io -> http://localhost:4141
...
# 接著請開啟第二個新的 Terminal Tab 把 ngrok 幫你建立的公開通道加到環境變數中
~$ export URL="https://{YOUR_HOSTNAME}.ngrok.io"

因為 Atlantis 跟 Git Service 需要整合在一起才能夠發揮效用,而本篇文章選擇 GitHub 當作示範平台,因此接著會提到如何設定 GitHub 的 Webhook 和 Access Token 給 Atlantis 使用

創建 Repository

首先請先 Folk smalltown/iac-day-2 repository 到自己的 GitHub 帳號下,然後使用第二個 Terminal Tab 將其下載到本機端

~$ git clone git@github.com:${YOUR_GITHUB_ACCOUNT}/iac-day-2.git

建立 GitHub Webhook Secret

GitHub 的 Webhook Secret 的功用是讓 Client 知道此請求是真的從 GitHub 而來,換句話說,就是要讓 Atlantis 驗證請求是從 GitHub 來的;可以使用此網站 (http://www.unit-conversion.info/texttools/random-string-generator/) 產生任意長度的隨機字串來當成 Webhook Secret

# 然後將此字串加入到環境變數當中
~$ export SECRET="{YOUR_RANDOM_STRING}"

新增 GitHub Webhook

接著去剛剛 Folk 的 Repository 設定頁面

  • 然後點選側欄的 Webhook,接著按下 Add webhook
  • Payload URL 的地方填上剛剛 Ngrok 產生的網址加上 /events,例如:https://c5004d84.ngrok.io/events (請確定有加上 /events 在後面喔!)
  • Content type 的欄位選擇 application/json,把剛剛產生的 Secret 填入
  • 選擇 Let me select individual events,然後把這四個事件勾起來: Pull request reviews, Pushes, Issue comments, Pull requests
  • 確定 Active 有勾起來後,按下 Add webhook

新增 GitHub Access Token

根據 GitHub 官方文件來新增 Access Token 給 Atlantis 使用,Scope 選擇 repo 即可,然後將該 Token 也加到環境變數中

~$ export TOKEN="{YOUR_TOKEN}"

準備 Atlantis Server repo.yaml

因為此系列文的架構是比照真實環境所設計,因此相對複雜一些,所以這邊需要另外新增一個 repo.yaml 組態檔案在本機端給 Atlantis 使用,將所要管理 Repository 的某些行為進行客製化,畢竟使用了不少個 AWS Account,又跑去另外多使用了 Terragrunt,後面會再詳細提檔案裡面偷做了什麼事情

啟動 Atlantis Server

設定了一堆東西之後,總算可以準備來把 Atlantis Server 跑起來了 (累)

# 把你的 GitHub 帳號名稱加入環境變數
~$ export USERNAME="{YOUR_GITHUB_ACCOUNT}"
# 把想要被 Atlantis 管理的 Repository 也加入環境變數,就是剛剛 Folk 的 Repository
~$ export REPO_WHITELIST=github.com/{YOUR_GITHUB_ACCOUNT}/iac-day-2
# 需要的組態都已經放置到環境變數後,就可以正式啟動 Atlantis
~$ atlantis server \
--atlantis-url="$URL" \
--gh-user="$USERNAME" \
--gh-token="$TOKEN" \
--gh-webhook-secret="$SECRET" \
--repo-whitelist="$REPO_WHITELIST" \
--repo-config="{REPO_YAML_PATH}/repo.yaml"
2019/08/03 14:39:19+0800 [INFO] server: Atlantis started - listening on port 4141

實際演練

太棒了!恭喜已經將 Atlantis Server 端設定完畢且啟動成功, Terminal 應該已經有兩個不能被關掉的 Tab 正在分別執行著 Ngrok 及 Atlantis,接著再打開第三個 Tab 開始體驗 Atlantis 的功能!

首先試著修改剛剛 Folk 回來的 Repository 檔案 demo-atlantis/password/terragrunt.hcl,這個 terraform 專案並不會去修改任何 AWS 的資源,他只會產生一個自訂長度的密碼回傳

# 隨便修改密碼長度變數值,譬如像我把它改成 30
inputs = {
password_length = 24
}

接著提交一個 PR 到此 Folk 的 Repository,然後神奇的事情馬上發生了!(參考用 PR 連結),從下圖可以看出來 Atlantis Server 幫忙執行完 terraform plan 並且將結果自動輸出至 PR 的 Comment 當中,所以幫忙 Code Review 的同事不像以前只能單看程式碼想像,而是可以在 PR 中得知有哪些東西會被 Terraform 新增/修改/刪除,而且也知道被執行了沒有

接著我照上面 Atlantis 提示的在 PR Comment 留下 atlantis apply,Atlantis Server 就幫忙 apply 好了!

細節解說

第一次整合 Atlantis 成功的時候,覺得這樣的流程好棒,配合公司內部在 GitHub Status Check 整合 RFC (ITIL 的 Request For Change 流程),好像以前在個人電腦執行 Terraform 時見不得人的一切都赤裸裸被揭露在眾人面前XD 接著讓我們來看一些設定上的細節

Atlantis Server 的 repo.yaml

在這個檔案中定義了在 PR 中什麼時候才能夠被 apply,像我這裡是設定只有當這個 PR 可以被 Merge 的時候才可以執行 apply,也可以設定被 approved 之後才能夠 apply,更多設定方式請參考官方文件,並且允許讓 repository 可以選擇預先設定的 Workflow,還有設定預設的 Workflow 要使用哪一個

# 訂定什麼什麼情況下才能夠執行 terraform apply
apply_requirements: [mergeable]
# 允許 Repository 可以選擇 Server 預先定義好的 Workflow
allowed_overrides: [workflow]
# 預設的 Workflow
workflow: terragrunt

而因為我使用了 Terragrunt,所以我定義了自己的 Workflow,其實就是當 Atlantis Server 要去執行 plan/apply 的時候,希望他真正要執行的指令是什麼,可以看到下面就是把一般的 plan/apply 改成 terragrunt 的指令,更多細節請參考官方文件

# workflows lists server-side custom workflows
workflows:
terragrunt:
plan:
steps:
- run: terragrunt plan -no-color -out $PLANFILE
apply:
steps:
- run: terragrunt apply -no-color -auto-approve

Repo 層級的 atlantis.yaml

而在 iac-day-2 這個 Repository 內有一個 atlantis.yaml 檔案用來控制什麼資料夾該使用哪一個 Workflow,可以看到下面設定說假如在資料夾 demo-atlantis/password 偵測到某些類型的檔案有修改時,就會在 PR 內自動執行 plan,而這個 Project 並沒有特別指定 Workflow 類型,所以就會使用剛剛上面預設的 Terragrunt Workflow

version: 3

projects:
- name: demo-atlantis
dir: demo-atlantis/password
autoplan:
when_modified: ["**/*.hcl", "**/*.tf*"]

Locking 機制

除了讓偷偷摸摸的作業見光死之外,使用 Atlantis 還會有 Locking 機制,也就是說當該 PR 還沒有被 Merged 或是 Closed 的話,該 Terraform 的資料夾跟其 Workspace 將會被鎖定,假如有另外一個使用者想要發一個使用到相同的資料夾或是 Workspace 的 PR,就會看到類似如下錯誤,如此一來便可以避免兩個人改到同樣的東西

而在 Atlantis Server 頁面也可以看到目前有什麼東西是被上鎖的,也可以在這邊或是剛剛的 PR 內進行 Unlocking 的動作,更多說明請參閱官方文件

結論

雖然設定的過程有點麻煩,但是整合完成之後,讓 Terraform 被修改過後會對雲端資源所做的任何新增/修改/刪除的資訊都可以在 PR 中一目了然;而且還有 Locking 的功能,使得管理同樣雲端資源的 Terraform 在同一時間只有一個人能夠修改,同事間感情和睦不再爭吵XD 實作完第三篇系列文之後,應該解決掉不少使用 Terraform 時會遭遇到的管理問題,並且降低管理雲端資源的風險性,也使 Terraform 達成了 GitOps,下一篇將會進一步探討如何降低同事間 Code Review 的負擔,並且同時提升 Terraform 程式碼的品質

參考資料

--

--

原來只是一介草 QA,但開始研究自動化維運雲端服務後,便一頭栽進 DevOps 的世界裏,熱愛鑽研各種可以提升雲端服務品質及增進團隊開發效率的開源技術