Dev Talks

在 Ruby on Rails 實現 Auto Scale 部署

5xRuby Rails Developer Johnson
Johnson, Rails 工程師 Mar 10, 2021

運行網站時,隨著網站的使用人數、功能還有架構設計不同,所需資源也大不同,高流量的網站背後會需要「更多資源」,「更多資源」指得可能是更多機器,或更大的資料庫。

如何為網站選擇適量資源是一門學問,配置過多資源會產生額外費用,太少資源則可能撐不起網站的流量,甚至導致服務不能正常運作。

然而,就算是同一個網站,根據狀態不同,它會需要的資源可能不盡相同,譬如深夜期間網站流量可能會比其他時間低,如果這時候使用的資源跟上午一樣,那就會造成浪費。而 Auto Scale 的架構正能解決這樣的問題,它能讓系統根據資源使用程度,自動調整系統需要的資源,譬如流量上升時就新增機器來分擔流量,以達成資源分配合理化的效果。

當 RUBY ON RAILS 遇到 AUTO SCALE 

Ruby on Rails 或大多數開發框架常用的部署工具,並不特別適合做 Auto Scale。譬如開發 Ruby on Rails 時常見的部署工具 Capistrano ,它的功能上主要是把部署腳本自動化,但要用它安裝系統套件,就會比較麻煩。因此,要開發出 Auto Scale 的架構,需要選擇合適工具,並將它們串接在一起。如何完成 Auto Scale,是非常值得研究的主題。

本文將介紹五倍紅寶石如何串連 AWS、Packer、Ansible 和 GitLab 等服務,在 Ruby on Rails 專案下完成 Auto Scale 的部署。我們會透過 Ansible 在伺服器上執行自動化腳本,安裝好需要的套件、程式碼還有設定系統環境,再透過 Packer 把環境打包成映像檔(AWS AMI),用 AWS 的 Systems Manager 將映像檔更新到機器群組完成 Auto Scale 的架構。

為了將以上流程「自動化」,讓工程師每次更新程式碼時,也能同時更新映像檔甚至完成部署,我們將使用 GitLab 程式碼倉庫服務的相關功能,讓系統可以達到一鍵部署效果。

在工作流程中增加自動化的覆蓋率,不僅提升開發效率,同時也降低了人為操作可能帶來的失誤。

ANSIBLE 自動化執行部署流程

Ansible 腳本以 role 為單位,將不同功能的腳本劃分開來,譬如有個 role 專門設定系統使用者,有的則是安裝網頁伺服器(Nginx)。五倍紅寶石內部有設計一套 Ansible 腳本公版,裡面所有的 role 能涵蓋一台機器要啟動 Ruby on Rails 所需的每個步驟。這套腳本都以 role 的格式整理好了,所以不同專案要使用時,都可以選擇或修改各自需要的 role ,如此一來可兼顧開發速度,也保留客製化彈性。

Ruby on Rails 運行時會需要數個環境變數,像是資料庫連線需要的密碼又或是第三方套件會需要的憑證等等,像以上這類有加密需求的環境變數,在這邊我們選擇 Ansible 的 Vault 功能來做加密。

Ansible Vault 透過將敏感資訊加密後放到版本控制系統中,透過這樣的方式避免直接將敏感資訊暴露和洩漏,在相對小規模的專案中可以減少額外搭建密鑰管理服務或者購置硬體的成本,是一個相對折衷又能有一定程度保護的方式。

PACKER 打包環境映像檔

Packer 是建置映像檔的工具,像是 AWS 的 EC2 和 GCP 的 Compute Engine 這些常見的雲端機器,都支援透過 Packer 來產生映像檔。我們需要產生出來的映像檔包含了 Ruby on Rails 環境,所以可使用 Packer 的 Provision 設定,Provision 指得就是映像檔產生前須要執行的腳本動作,可以選擇直接寫 Shell Script 又或是 Ansible 腳本等。

我們直接套用剛剛寫完的 Ansible 腳本讓映像檔開啟後,機器中就會包含 Ansible 安裝的套件、程式碼等,直接讓機器進入「準備好」的狀態,如此一來比開好機器才安裝套件的方式能快上五到二十分鐘不等。Auto Scale 能越快完成,機器就越能負荷突然上升的流量。如何有效縮短 Auto Scale 所需時間,也會是選擇部署工具的重要考量因素。

AWS 雲服務整合

有了映像檔(AWS AMI)後我們可以直接使用 AWS 的 Lambda 服務來將映像檔更新自機器群組。如果我們想要先檢查映像檔能否正常運作,再來作更新機器群組的話,這時候可以用 AWS Systems Manager 的服務,他能查看及控制 AWS 的多個服務。我們可以在它的自動化服務中設定先使用映像檔啟動一台機器,如果一切正常再匯出映像檔,最後呼叫 AWS Lambda 來更新機器群組。

AWS Systems Manager 執行步驟頁面

上圖為 AWS Systems Manager 執行步驟頁面

GITLAB 整合多工具程式碼

五倍大多數專案原始碼都使用 GitLab 管理,透過設定 GitLab 的自動化腳本(GitLab CI/CD),我們能在更新程式碼時自動執行程式碼測試、程式碼分析等工作,甚至完成程式碼部署,把最新的程式部署到機器上,以便進行人工測試或是更新到正式環境。

其中值得一提的是 GitLab 的 Trigger 功能,他能設定成在 Ruby on Rails 專案發送合併請求(Merge Request)時,去觸發 Packer 程式碼倉庫內的另一份 GitLab 自動化腳本。讓我們整合不同程式碼的自動化腳本一起完成部署的任務。

GitLab Trigger 功能設定頁面

上圖為GitLab Trigger 功能設定頁面

挑戰與優化

2019 年在為某知名電商平台操作雙十一活動時,五倍曾在 GCP 環境下透過 Packer 加 Ansible 實現 Auto Scale 功能部署。當時我有幸參與此專案,挑戰把客戶的專案從 GCP 換到 AWS 環境,並參考之前的設計,再次搭出 Auto Scale 功能的 Ruby on Rails 環境。

在 GCP 中,以指令的方式就可以直接把最新映像檔更新到機器群組上,但在 AWS 上,會需要有映像檔的序號(AMI ID)才能將映像檔更新到機器群組上。然而在 GitLab 自動化腳本中,Packer 產生映像檔還有 AWS Systems Manager 更新機器群組是不同階段的腳本,因此需要額外使用 GitLab CI 的 artifacts 功能將映像檔序號用環境變數的方式傳給下個階段的腳本。

在執行 Ansible 腳本的眾多步驟中,靜態檔案打包是相當花時間的一個項目。在測試和部署時,都需要各別打包靜態檔案一次。如果能只做一次靜態檔案打包就完成測試和部署,將能省下幾分鐘到幾十分鐘的時間。因此,我們將測試階段打包的靜態檔案上傳 AWS 物件儲存服務(S3),接著在部署階段直接下載打包好的靜態檔案下,如此一來可以省下不少自動化部署的時間。

總結

以上是我們如何在 Ruby on Rails 實現 Auto Scale 部署的,它能讓網站因應資源的使用,自動調節出最適合的資源配置。隨著專案規模增長,原本可行的系統架構常常不敷使用,這幾年網站技術日新月異,挑選並導入適合的工具成為一門複雜的學問,更成為開發公司的重要專業。

五倍紅寶石以專業知識與多年經驗,透過技術與顧問服務,能協助您調整與優化網站系統架構,為您的產品提出最佳解決方案。不再浪費企業資源,讓每一分成本,都花在最重要的地方。


分享