在2022年我們終於完成了主要業務系統上K8s的計劃,在這裡總結下我們上K8s時候的模版工程。
前提條件
本文不討論K8s是什麼,什麼是容器化,為什麼需要容器化,什麼是微服務等這些基礎內容,這些到處說的爛大街了。此類內容有興趣可以看看微軟系的介紹:
本文假設你已經能對你應用進行docker打包,並正確推到docker倉庫裡。本文假設你docker打包是利用azure DevOps pipeline進行且有使用buildId作為tag。
這裡主要討論的是面向批次專案上K8s的時候使用的釋出模版,更多偏向於「管理」特性,不會過多解釋類似K8s等的相關概念。
為什麼需要模版化部署
如今,微服務或容器化逐漸成為主流,而使用K8s基本上已成為每個有志之士的應用現代化目標。然而,容器本身雖然在本地偵錯中比較方便,但一旦作為正式應用部署到遠端環境中,常常會出現各種問題。這些問題主要源於Dev和Ops之間的邊界,因此,DevOps的重要性日益凸顯。
運維提供了K8s環境,就認為自己的工作完成了;而開發只提供了在本地執行的容器應用,也認為自己的工作完成了。
然而,我注意到有一些人直接在各個環境中編寫yaml檔案並將其推播到線上。這是否意味著測試環境和線上環境是相同的?環境變數是否有統一控制機制?機密資訊是否得到了適當處理?資源分配如何確定?HPA的設定如何確定?等等。
因此,我認為解決自動化版本釋出的模板化問題是使用K8s的重要問題。我們需要有一個基礎的模版,裡面設定好了大多數預製情況,然後根據有限的引數,對個別變數標記的地方進行替換。
我們自己在進行該專案的時候也查詢了不少資料,許多資料更多討論的是每一個步驟的細節,如果是以有限的專案為目標的話,怎麼幹都行,但是如果是批次專案要上的話,那麼「統一管理」,「模版化部署」我認為還是很重要的。
最終實現的效果就是我需要釋出一個k8s的應用的時候,只需要填寫少數有關變數即可,如下圖
如果有什麼需要修改的基礎設定,只需要修改模版即可
如何設計模版
首先找到helm挺符合要求的,然後我們就基於helm作為模版進行操作。
注意:使用helm的話要麼需要你任務步驟裡需要新增helm installer步驟,要麼你預先在你的build agent裡安裝helm,然後通過demand標記使其能正確分配到有helm的agent裡,我們使用的後者,所以我們步驟裡沒有helm的安裝步驟,如果不進行此操作可能會導致bake步驟的失敗。
我們的專案模版可以參考github裡的地址:
https://github.com/virtualcca/k8s-template
其中為了區分本身helm的變數與法,我把需要進行一些替換操作的使用[[xxx]]標記,需要對這些自己處理下操作後理論上就可以拿來用或者視情況調整下values.yaml的值。
我們的模版主要根據以下幾個引數來進行區分和替換:
同時我們模版裡預設參照了一個叫default-conf的configmap設定,裡面設定了一定要有的一些預設設定資訊,比如時區要是東八區這種。
另外說到模版的話應用也是有一定程度需要配合,我們通過https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks 專案給我們每個站點都增加了健康檢查(通過我們內部的基礎底層框架)
分別定義了/heartbeat和/healtcheck,分別對映到Liveness和readiness,站點上一般會把這些對映到自己核心依賴的資料庫檢查(select 1),如果短暫錯誤先下線避免髒資料(readiness),如果持續性錯誤則嘗試重啟或者漂移到別的Node重啟(liveness)
如何使用Azure DevOps實現模版化部署
注:後續會使用到一個叫「任務組」的功能,詳情可以參考這裡對任務組的解釋 https://learn.microsoft.com/zh-cn/azure/devops/pipelines/library/task-groups?view=azure-devops
步驟1:建立倉庫並存入模版
首先需要在Azure Devops中建立一個Azure Repo,並將需要用於部署的Kubernetes模版存入該倉庫。
步驟2:建立管道實現自動打包
接下來需要建立一個管道,使用一個簡單的yaml做為管道實現模版的變化自動打包。
可以參考Github倉庫中的https://github.com/virtualcca/k8s-template/blob/main/azure-pipeline.yaml
這樣每次模版變動後就會產生Artifacts,可用於後續正式釋出流程使用。
步驟3:處理K8s釋出有關的操作
在釋出裡,隨便新建一個釋出,新增3個」部署到Kubernetes」的任務。
在「操作」裡,分別從上到下選擇create secret, bake, deploy
步驟4:上面3個步驟相關資訊填寫好
主要是Kubernetes服務連結,名稱空間,Docker登入檔服務連線等
注意create secret裡的機密型別選擇dockerRegistry,機密名稱隨意但是後續deploy裡有個ImagePullSecrets裡面也要填寫一樣的名稱
bake步驟裡的「重寫」可以把模版裡暴露的相關設定在這裡填寫上,格式如同 key1:value1的格式,一行一個設定
步驟5:選中剛才3個任務,組成任務組
步驟6: 將任務組裡的變數引數化
重新review下剛才填寫的東西,不少是重複的,比如名稱空間3個步驟裡都有,包括bake步驟裡重寫的資訊,類似這種我們應該統一變數控制。
具體操作是將這些資訊改為 $(變數名) 。
但是改了後會發覺參照這個任務組裡是沒有出現可設定的變數資訊(主要體現在bake步驟的「重寫」裡的那一部分)。
此時需要使用一個bash步驟相當於強制告訴Azure Devops我有這些變數。
然後你任務組裡就會有這些變數名稱,稍微完善下注釋和為了便捷性提供下大多數情況的預設值
步驟6: 將bake渲染的yaml給deploy步驟使用
在bake步驟後新建一個bash步驟,填入
echo "##vso[task.setvariable variable=mainfest]$KUBERNETESMANIFEST2_MANIFESTSBUNDLE"
然後deploy裡的「清單」填寫$(mainfest)
注:在任務組裡不能直接使用bake通過「輸出變數」的方式使用,這裡使用了一種曲線救國的辦法。
步驟9: 解決一個mainfest變數問題
到這裡K8s步驟核心的任務組基本設定完畢,我們儲存,然後新建一個釋出定義,參照這個任務組,我們來使用它吧。
然後使用的時候會發現莫名其妙多了一個叫mainfest的變數需要你輸入,而且還是必填項,不知道的你隨便輸入一點東西比如幾個空格,然後會發覺無法使用。
解決該問題需要對之前建立的任務組進行匯出下載,然後在其中尋找inputs節點的name為mainfest的變數,並將其刪除。之後再匯入即可。
不過這個操作方法挺繁瑣的,主要是匯入後它不是「更新」你原來有的,而是「新建」了一個任務組,導致如果你有參照原來那個任務組的話,都要重新操作設定,由於這個原因,所以建議K8s的那3個步驟作為一個單獨的任務組,把該暴露的變數設定都暴露出來,然後通過另外的任務組去參照這個,另外的任務組在去執行上面說的下載工件等操作(因為這個會有擴充套件的,比如我們後續用的Azure Function的部署步驟,下載的工件就是不一樣的)
整個調整後的匯出的模版可以參考github裡的我們的這個版本: https://github.com/virtualcca/k8s-template/blob/main/K8S-Internal.json
步驟10:拆分任務組
為避免繁瑣的操作,建議將K8s的三個步驟作為一個單獨的任務組,將該暴露的變數設定都暴露出來,然後通過另一個任務組去參照該任務組並執行下載工件等操作。
最終得到的任務組可以用於快速的K8s批次化部署模版。
步驟11: 新建最終版本任務組
新建一個新的任務組,在第一個步驟裡使用DownloadBuildArtifacts步驟,以下載Artifacts的形式獲取到我們最前面的模版。
最後
最終新構建的任務組就是片頭圖裡的那個,以後要部署K8s的應用只需要簡單的使用這個任務組並填寫有限幾個必填變數,即可完成應用線上部署需要,最大程度簡化流程並且也能實現流程統一化
未來如果有什麼需要調整的,也能基於模版的形式統一調整
流程解析