前言
在「分階(tiered)與分層(layered)的雲端系統架構」這篇文章中,可以清楚「平台(platform)」屬於分層架構中的中間層,其目的便在於將基礎設施(infrastructure)封裝,提供一組標準的抽象化給應用層來使用。山姆鍋在過去的文章中提過「應用平台」這個名詞好幾次,但好像都沒有對這個名詞有較詳細的說明。本文就來聊聊山姆鍋所謂的「應用平台」吧!
目錄
展開目錄
何謂應用平台?
平台工程(Platform engineering)是最近很夯的軟體開發運維趨勢,平台工程的目的便在於建構一個開發者友善的(內部)工程平台,讓開發人員可以不用了解太多底層細節便可以自助式地完成應用元件的建置、交付以及運行要求。既然是一個平台,開發人員作為消費者(consumers),自然就要有生產者(producers),運維人員(只是統稱,可以涵括平台工程師、SRE等不同角色)便是此平台的生產者,負責建置與維護平台。
顧名思義,應用平台是以應用為中心(application-centric)。意思是說,以應用作為關注對象貫穿整個應用交付週期。以應用為中心的好處在於:
- 底層的基礎設施資源伴隨應用產生以及消滅,每個資源有明確的需求對象。如此每個資源可以追朔其需求源頭,確保不會有空置的資源浪費同時也方便成本追蹤。
- 應用包含需要一起發佈的元件,簡化相依性描述。例如:微服務可以視為一個應用,用以同時發布微服務的工作負載以及資料庫元件。平台可以透過元件間的相依關係在部署或者運行階段自動進行資源綁定。
交付週期 (Delivery Cycle)
相較於完整的應用生命週期管理工具,這裏所謂的「應用平台」,或者說「自動化應用平台」主要專注在應用生命週期的三個階段:「建置(build)」、運送(ship)、以及「運行(run)」(如下圖所示)。可以簡單理解成:自動化應用平台負責從提交代碼到使用者可以存取該代碼功能的這個過程的所有自動化要求。為什麼只專注這三個階段呢?因為即使是一人開發團隊,這些工作的自動化也是遲早要面臨的問題。而山姆鍋幾乎都是在新創公司工作,主要經驗也是以這三個階段為主。
過去山姆鍋在團隊內部常使用「DevOps 平台」來表示這裡的「自動化應用平台」這個概念。但因為一直無法如何正確解釋何謂 “DevOps”,加上山姆鍋認為作為軟體開發團隊使用的平台,應該以「應用(Application)」為中心;而「自動化」是 DevOps 原則的重要實踐。慢慢地就改以「應用平台」或者「自動化應用平台」來稱呼。
山姆鍋將應用元件的「建置」、「運送」以及「運行」稱為「交付週期(delivery cycle)」。眼尖的讀者應該發現山姆鍋這是借用 Docker 的 “Build, Ship, Run” 口號。底下稍微說明在上述不同階段,應用元件經歷哪些活動以及相關工具。
建置 (Build)
「建置(build)」階段將「原始碼(code)」轉換成「製品(artifacts)」。任何需要包裝成「製品」的文本、圖檔、初始資料都可以算是「原始碼」,不管在過程中是否經過轉換(例如:編譯、壓縮等)。
「製品」是軟體元件方便用於交付的形式,根據語言、目標平台而異。常見的「製品」如「執行檔(executables)」、封存檔(archives)、容器映像(container image)等。
採用 DevOps 原則的團隊會使用 CI 系統,如 Jenkins, GitHub Actions 等來實現持續整合管道(CI pipeline)。山姆鍋習慣將負責建置階段的自動管道稱為「建置管道(build pipeline)」。建置管道除了編譯、也會進行單元、整合等測試。
建置好並通過測試的「製品」會放置到 「製品存儲庫(Artifact Repository)」。例如:Docker 容器映像會放在 Image registry 中。 其他如 Maven repository、Artifactory 都是常見的製品存儲庫。
關聯文章:容器化應用持續交付
運送 (Ship)
「運送(ship)」階段將「製品」部署到指定的環境,讓使用者可以存取或下載。為了達成持續交付的目的,交付也會由 CD 系統管道來實作。山姆鍋習慣將負責(持續)部署的管道稱為「部署管道(deployment pipeline)」。
「元件」在本文是最小的可部署單元(deployable unit),同一個應用的元件可以部署到不同的目的地。例如:微服務的工作負載元件部署到 K8s 叢集,但資料庫使用 AWS RDS。由此可知:應用元件的運送或部署會根據元件的種類以及目標環境有多種不同的工具或方法可以選擇。例如:Kubernetes 工作負載容器可以使用 kubectl, helm 等不同工具。
根據元件的特性(e.g. 是否有對外端口,是否可以同時有一個以上的副本存在),會選用不同的部署策略。為了減少部署過程對在線使用者的衝擊,團隊也許會選用漸進式交付(Progressive Delivery)部署策略。常見的部署策略有:
- Recreate:最簡單的策略,直接刪除舊版本後運行新版本元件。
- Rolling Update:新舊版本共存一段時間,過程中將舊版本元件慢慢替換成新版本。在切換期間,不同使用者可能存取到新舊版本。
- Blue-Green Release:新版本部署時,流量全部導到新版本元件,但舊版本暫時不刪除,如果新版本有問題可以快速回滾(rollback)。
- Canary Release:比 Blue-Green 策略更彈性,使用者流量逐漸按指定比例轉向新版本,沒出現問題就持續直到所有流量都由新版本處理為止。發生問題同樣自動回滾。
運行 (Run)
軟體元件運送到目標環境後,沒意外應該按照計畫正常運行。但軟體運行是一個持續性的活動,一開始沒問題不代表後續都可以正常運作。隨著使用者對於軟體服務的期待越來越高,除了功能正確外,尚有許多要求要符合。例如下列是對於運行環境的常見需求:
- 服務發現(Service Discovery):在雲原生架構,元件依賴的服務所在位置並非一成不變。因此,需要藉由服務發現機制來動態定位提供所依賴服務的元件。
- 自動擴展(Automatic Scaling):隨著使用者用量的增加,平台要能夠根據負載來自動擴展元件,不管是透過垂直(增加 CPU/記憶體)或者水平(增加節點以及元件副本數量)方式。
- 高可靠性(High Reliability):當元件或其所在節點出現問題時,平台要能夠在其它節點重啟元件副本以確保服務的可用性(availability)。
- 可觀測性(Observability):平台提供追蹤(traces)、日誌(log)以及指摽(metrics)等資訊用以協助找出問題源頭或者效能瓶頸。
Kubernetes 作為容器調度系統,將底層基礎設施抽象化外,能夠大致滿足上述的需求。不足的部分,生態系中眾多的廠商也多有解決方案可以選擇。作為事實上的標準,目前如果要自建一個應用運行平台,Kubernetes 應該是不二選擇。
平台的價值
自助自管
在符合公司資源使用政策以及角色權限允許的範圍內,開發人員可以透過平台自行執行軟體建置、部署、快速建立環境等活動,不再需要運維人員的協助。透過抽象化,平台讓開發人員不需要了解底層細節,便可以完成日常發布工作。例如:透過一個應用描述檔(Application manifest),開發人員可以描述如何部署一個應用相關的元件以及運行時的需求。平台在實際部署時,會動態套用運維人員預先定義好的實務作法。透過這樣的關注點分離(Separation of Concerns)方式,運維人員可以確保應用符合公司資訊安全、成本管理等政策。
隨著部署環境的數量以及需求增高,要求開發人員除了開發外,還要同時掌握與管理應用所需環境的設置會越來越不可行。讓開發人員理解少量的概念就可以完成軟體交付任務,應該要是平台最主要的目標。
協同合作
軟體元件需要新增的一個設定,開發人員往往需要透過 Jira Ticket 或者其他方式讓運維人員知道如何修改。如果這樣的設定值是存取服務所需要的憑證(credentials, 例如:密碼),那問題會更加地複雜。平台提供標準規格描述與自動化機制來解決這樣的問題。例如:提供服務綁定(service binding)機制,將動態產生的連線與密碼資訊,透過檔案或者環境變數提供給依賴的元件。
可以理解成團隊成員之間的工作交互都遵守一定的守則(protocols),而平台作為中間者確保成員間都確實遵守工作守則。一旦有自動的標準的作業流程,就可以減少成員之間溝通時間。
權限控管
平台可以根據使用者的角色決定其擁有的權限,例如:可以進行哪些操作,使用哪些資源以及上限。山姆鍋不知道讀者的經驗,但山姆鍋過去加入的團隊曾經發生開發人員直接在生產環境的主機修改程式,但全公司沒人知道他正在這樣做;以為刪除資料的對象是測試環境,其實是正式環境的資料庫等等。
透過平台,可以賦予開發人員必要的最小權限,而不是像過往給予整個主機或叢集的管理權限以完成任務。
平台的四大支柱
作為一個開發團隊的協作系統,不管在交付週期的哪個階段,應用平台都展現一些共同的特性。有人將這些特性稱為平台的支柱,山姆鍋沿用這個說法。底下是山姆鍋認為平台的重要特性。
抽象化 (Abstraction)
抽象化隱藏跟當前任務無關的訊息,減少使用者的認知負擔(cognitive load)進而提升生產力。抽象化讓開發人員不用知道太多具體細節就可以描述需求規格,而需求規格可以交由平台來執行。例如:在建置階段,藉由 CI/CD 的管道以及其中的步驟(step)定義來描述元件如何編譯、測試以及部署。「管道」、「步驟」就是一種抽象化。同樣地,Kubernetes 提供 Deployment, ReplicaSet, Service 等抽象化用於描述應用的運行需求。
標準化 (Standardization)
抽象化讓開發人員可以不用管底層的細節描述建置、部署以及運行需求。但如果不同團隊對於同樣的問題,採用不同的抽象化,不同的詞彙來描述,這就會導致需求描述沒有辦法跨團隊/角色共用。就跟「領域驅動設計(DDD)」使用一組相同的抽象化/語言詞彙用以描述問題領域的設計需求一樣,平台也需要提供標準的抽象化/語言詞彙來讓開發人員描述應用需求。
除了標準化的溝通詞彙,團隊也會決定共用的的工具、技術以及工作流程。如此,可以有效減少技能分歧以及支援負擔。
自動化 (Automation)
平台應該代替團隊成員完成重複、單調的任務。藉由自動化,讓成員的時間可以用於其它更有價值的任務上。為了實現自動化,需要其它平台支柱才能成真。沒有標準的抽象化規格語言,平台無法明確理解使用者的意圖,就不用說代為執行。而沒有一體化的系統整合,將限制平台的任務執行能力(capabilities)。
一體化 (Integration)
平台並不是一體適用(one-for-all)的工具,意思是說:一個平台無法滿足所有團隊需求。所以,平台要能夠整合現有的工具或系統,而不是要求使用者從頭熟悉一個全新的產品。例如:在軟體建置上,很多團隊已經有使用 CI/CD 系統,平台需要自帶 CI/CD 功能,還是選擇跟現有系統整合?同樣地,基礎設施的整備,常常使用 Terraform、Pulumi、Ansible 甚至是客製的腳本,如何重用這些已經存在的“資產”是平台無可避免的挑戰。
小結
本文所謂的「自動化應用平台」只是山姆鍋習慣的稱呼。不管名稱是什麼,重要的是平台所帶來的價值:提高工作效率、減少資源浪費、降低溝通成本等等。之後的文章,山姆鍋會說明為何要選用 Kubernetes 作為自動化應用平台的通用控制平面(Universal Control Plane)元件。