上一講提到建置以及服務的定版,都是屬於 CI/CD 中的 CI 持續整合。我們今天接續著來聊 CI 中的測試,以及後半部 CD 中的環境。
首先是測試,在寫好程式之後,跑 Unit Tests 是最基本且重要的操作,有了 Unit Tests 才能讓你在開發上不怕改了 A 而壞了 B,給了你重構把程式碼改漂亮的勇氣,CI 的流程中,前提是一定要有自動化測試。
如果沒有了 Unit Tests、Integration Tests 之類的自動化測試,每次重複的繁瑣手動測試將會是個災難,你可能參數下錯了,也可能根本每次測試的方式都不同,這樣根本無法保證產品的品質。
如果有了自動化測試,可以說已經大大地減輕程式迭代的成本,但是少了 CI 幫你每次跑測試,依然蠻有機會發生人為的疏失。
像是上 Code 時忘了跑測試,同事抓下來的 Code 根本就是壞的;大家開發環境不同,例如我用 MacBook with ARM 架構,他用 Intel 的 x86 來開發,可能兩個環境中跑的測試結果就會有所不同。
因此,當寫完一段 Code 時,有個固定的編輯幫你和同事們統一校稿,就能避免了常見的遺忘、環境不同等變因所引發的錯誤。
雖然這些錯誤大多不嚴重,但是當你在專心開發程式時,持續不斷的有這種小小的麻煩要去處理,是極度影響效率的事情。
前面說的 Unit Tests 和 Integration Tests 通常是在 CI 階段所執行的,用來持續將新的程式碼整合到現有的產品當中。
而我們之前聊過的端到端測試(E2E Testing)則是在部署完成後所執行的,如果 E2E Tests 也已經做成自動化的型態,那麼在部署完畢後就能夠自動驗證以前的功能有沒有被改壞。
需要注意的是,我們不一定會在客戶使用的環境上跑 E2E Tests,因為若是這個測試是在客戶的環境上執行的話,有可能會造成測試資料污染了客戶的真實資料。真的要驗證的話,可以挑選一些以讀取為操作的測項即可。
總而言之,這些自動化測試在 CI/CD 中,最大的幫助就是維護你的「心理頻寬」,讓有限的心智資源去處理更重要的事,而非不間斷且不重要的雜事。
再來則是部署在哪的問題,最基本的環境當然就是 Local 以及 Production。在本機開發稱為 Local、而交付的目標環境就稱作 Production(生產環境)。
除了這兩個環境,當團隊規模大一些,可能還會有 Alpha、Staging 等等,Alpha 通常是開發團隊的測試環境,Staging 或 Beta 則是交付前的驗證環境,會由 QA 的團隊使用,而不同公司可能會有不同環境的設定及稱呼。
撇除硬體的物理位置和規格不同,不同環境的主要差異在於一些設定檔和其他服務的位置。例如 Token Expire 的時間在 Local 可能為了方便將其調成永久、但在 Production 則因為資安的原因要調短一些;又或是資料庫的位置在 Local 設定成 localhost:5432 但在 Production 是另外一台機器的 IP 位置。
*Local vs Production configs
因此,在不同的環境就需要提供不同的設定檔(Config),我們接下來需要考慮的因素就是如何將這些設定檔餵給不同的環境了。
比較常見的做法就是透過**環境變數(Environment Variables)**了,之所以被稱作環境變數,就是因為這是個根據環境不同而儲存不同資訊的變數,例如在 Linux 中輸入 echo $PATH
就會列出了作業系統在執行 Command 會去哪些路徑尋找執行檔。
第一個會用到的環境變數就是「現在處於的環境」,當我們在本機的時候,就設定 ENV=local
,在 Production 時就設定 ENV=production
。我們能在程式碼中提供不同的設定檔,像是 config.local.yml
和 config.production.yml
,然後在不同的環境讀取不同的設定檔。
但是這樣做會有一個問題,這些設定檔要存在哪裡?如果是透過 Git 版控而存到 Repo 裡面,一些機敏的資料如 API Key、預設 Admin 帳號密碼則會以明碼的方式存在 Repo 裡面。所以除了沒那麼機密的資料可以用 config.{environment}.yml
的方式上 Code 之外,其他訊息應該也透過環境變數的方式提供。
既然要避免機敏資訊被直接寫死在 Code 當中,我們就需要更安全的方式來儲存他們。
最陽春的方式是當手動部署的時候,直接在目標 VM 中設定所有機密的環境變數,例如 API_KEY=my-secret-api-key
,並且在程式中讀取此環境變數。
另一些方式是搭配 CI/CD 的工具,如 Ansible、GitHub Actions、Travis CI 等,他們都有提供所謂的 Secret Manager 來儲存機敏資訊,但本質上也是在幫你部署的時候,將這些加密儲存在其服務內的資料,導入目標 VM 的環境變數。
但總而言之,在考慮儲存機敏資訊時,最重要的就是避免直接寫入程式碼中,如果在部署時寫入環境變數,也要最小化能讀取此變數的帳號,減少被洩露的風險。