私有Chart倉庫搭建)
前兩周剛幫某研發(fā)團(tuán)隊處理完一套部署流程改造他們線上服務(wù)每次發(fā)版都要手動維護(hù)二十多個YAML文件從deployment.yaml到configmap.yaml一長串改個鏡像版本號要精確到第幾個文件稍不注意就會遺漏。這種場景在K8s工程師的日常里太常見了而Helm的出現(xiàn)就是專門來解決這套配置地獄問題的。這篇文章是我在推進(jìn)企業(yè)項目K8s落地過程中關(guān)于Helm部署使用以及chart倉庫搭建的完整實踐總結(jié)從基礎(chǔ)概念講到企業(yè)私有倉庫適合已經(jīng)能熟練操作K8s、但還沒系統(tǒng)用過Helm的工程師或者正在為多服務(wù)多環(huán)境配置管理頭疼的同學(xué)。1. 為什么企業(yè)里的K8s工程師最終都會走到Helm1.1 手動維護(hù)YAML的崩潰瞬間先說說我看到的普遍現(xiàn)狀。很多人第一次接觸K8s時都是從kubectl apply -f xx.yaml開始的單服務(wù)單環(huán)境勉強能對付。但一旦服務(wù)數(shù)量到了兩位數(shù)問題就開始扎堆出現(xiàn)服務(wù)A和B共用一套部署邏輯只是鏡像tag不同于是你復(fù)制一份YAML改改名字繼續(xù)用線上環(huán)境加了一個環(huán)境變量測試環(huán)境也要同步加你開始對照著十幾個文件逐個檢查某個服務(wù)回滾你翻遍聊天記錄才找到三天前部署時用的鏡像版本配置混亂到?jīng)]人敢動新同事接手第一周全在考古。這些癥狀的本質(zhì)是K8s把運維復(fù)雜性從虛擬機轉(zhuǎn)移到了YAML文件里而你仍然在用文本復(fù)制粘貼的原始方式管理它們。企業(yè)里服務(wù)一多這根本不是人力能扛住的。Helm解決的就是這個問題——把一系列K8s資源文件打包成一個可配置、可版本化、可復(fù)用的整體這個整體就是chart。1.2 Helm三板斧打包、模板渲染、版本管理Helm的核心理念并不復(fù)雜把它拆解成三個能力就夠用了第一板斧是打包。你將一套服務(wù)需要的Deployment、Service、ConfigMap、Ingress等資源文件放進(jìn)一個固定結(jié)構(gòu)的目錄這個目錄就是一個chart。它與Docker鏡像的邏輯很像——Docker打包應(yīng)用運行環(huán)境Helm打包K8s部署資源。第二板斧是模板渲染。chart里的YAML文件不必寫死可以使用{{ .Values.replicaCount }}這類模板語法再配合values.yaml提供的默認(rèn)值。實際部署時不管是測試環(huán)境還是生產(chǎn)環(huán)境同一個chart通過傳入不同參數(shù)就能渲染出不同配置這解決了多環(huán)境差異管理的核心問題。第三板斧是版本管理。每次helm install或helm upgrade都會生成一個release記錄你隨時可以查看部署歷史一條命令回滾到任意歷史版本。這直接解決了線上回滾靠回憶的尷尬。另外有必要提一下Helm 3相對舊版本架構(gòu)上的變化。Helm 2時代有個叫Tiller的服務(wù)端組件它擁有集群權(quán)限負(fù)責(zé)執(zhí)行安裝操作這在多租戶集群里有安全隱患。Helm 3直接干掉了Tiller客戶端直接調(diào)用K8s API權(quán)限由你的kubeconfig決定邏輯上更清晰也更安全?,F(xiàn)在新項目建議直接上Helm 3不用再碰Tiller那套東西了。2. 環(huán)境準(zhǔn)備Helm 3的安裝與首次上手體驗2.1 安裝方式和版本確認(rèn)Helm的安裝很輕量本質(zhì)上就是一個下載到本地的二進(jìn)制文件。Linux和macOS環(huán)境下最省心的方式是通過官方安裝腳本curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh如果你對安全要求比較高不想執(zhí)行遠(yuǎn)程腳本也可以直接到Helm官方Release頁面下載對應(yīng)平臺的壓縮包解壓后把二進(jìn)制放到/usr/local/bin下。我自己習(xí)慣用這種方式步驟雖然多一步但可控性更強靈魂拷問起來能明確回答我安裝的到底是哪個版本的包。安裝完成后驗證一下helm version輸出類似這樣就可以了version.BuildInfo{Version:v3.15.0, GitCommit:..., ...}企業(yè)內(nèi)部一般還會做一次helm repo add把官方或者自己私有的chart倉庫配好。例如添加一個內(nèi)部chart倉庫的流程helm repo add internal-repo https://chartrepo.internal.example.com helm repo update這里有一個小提醒如果部分同學(xué)所在網(wǎng)絡(luò)環(huán)境訪問公共倉庫不穩(wěn)定企業(yè)內(nèi)部一般都會搭自己的代理倉庫或離線同步方案。實際工作里團(tuán)隊內(nèi)會很早就約定好這些基礎(chǔ)設(shè)施的獲取路徑而不是每個人各顯神通。2.2 核心概念實操化理解在敲第一條部署命令之前有三個詞必須徹底吃透后面所有操作都建立在它們之上Chart一個打包好的應(yīng)用模板包含了一組描述K8s資源的文件。Releasechart被部署到集群中的一個運行實例。同一個chart可以被部署多次每次部署就是一個獨立的release。Repository存放和分發(fā)chart的倉庫??匆粋€最直觀的例子假設(shè)我已經(jīng)添加了某個公開chart倉庫想快速部署一個nginxhelm install happy-nginx repo/nginx這條命令做了三件事讀取repo/nginx這個chart根據(jù)默認(rèn)配置渲染出K8s資源然后以happy-nginx這個名字部署到集群。這時候用kubectl get pod已經(jīng)能看到對應(yīng)的Pod了。用helm list可以看到當(dāng)前的所有release及其狀態(tài)。這是排查問題時第一個應(yīng)執(zhí)行的動作——確認(rèn)release存在與否、處于什么狀態(tài)、最近一次操作是什么。values的傳遞也很直觀helm install happy-nginx repo/nginx --set replicaCount3這條命令只覆蓋了replicaCount這一個參數(shù)其他配置全部走chart里的默認(rèn)值。文件級別的參數(shù)管理放到后面講多環(huán)境時再說記住--set與--values的差別即可一個適合快速調(diào)試一個適合保存整套環(huán)境配置。3. 從零手寫一個企業(yè)級Chart以某內(nèi)部訂單服務(wù)為例光會用現(xiàn)成chart還不夠企業(yè)內(nèi)部業(yè)務(wù)是五花八門的你需要能把自己服務(wù)的部署邏輯沉淀成chart。下面拿一個后端服務(wù)來完整走一遍這個服務(wù)有標(biāo)準(zhǔn)的HTTP接口、需要連接Redis還對外暴露Ingress。3.1 Chart標(biāo)準(zhǔn)結(jié)構(gòu)與每個文件的職責(zé)創(chuàng)建一個chart最規(guī)范的方式是用官方腳手架helm create order-service生成的目錄結(jié)構(gòu)是這樣的order-service/ ├── Chart.yaml ├── charts/ ├── templates/ │ ├── deployment.yaml │ ├── service.yaml │ ├── ingress.yaml │ ├── _helpers.tpl │ ├── hpa.yaml │ └── ... └── values.yaml幾個關(guān)鍵文件的職責(zé)先捋清楚Chart.yaml是chart的元數(shù)據(jù)包含名稱、版本、聯(lián)系方式等是chart的身份證values.yaml是默認(rèn)配置所有可能在部署時變化的參數(shù)都在這里給出默認(rèn)值templates/目錄存放真正的K8s資源模板支持Go模板語法charts/目錄用于存放依賴的子chart這屬于依賴管理范疇。我的習(xí)慣是刪掉腳手架生成的亂七八糟的測試資源按實際需要精簡文件結(jié)構(gòu)。這個東西不是生成的越多越好而是每個文件都有明確的存在理由。3.2 Chart.yaml和values.yaml的設(shè)計一個精簡、可直接用的Chart.yaml長這樣apiVersion: v2 name: order-service description: 內(nèi)部訂單查詢服務(wù) type: application version: 0.1.0 appVersion: 1.2.0注意apiVersion: v2這是Helm 3要求的格式v1是Helm 2的舊格式。values.yaml要按可配置項來組織我把常用結(jié)構(gòu)整理如下# 鏡像相關(guān)配置 image: repository: harbor.internal.example.com/backend/order-service tag: 1.2.0 pullPolicy: IfNotPresent # 副本數(shù)與資源配額 replicaCount: 2 resources: requests: cpu: 200m memory: 256Mi limits: cpu: 1000m memory: 1Gi # 環(huán)境變量配置 env: REDIS_ADDR: redis-service:6379 LOG_LEVEL: info # 服務(wù)端口與Ingress域名 service: port: 8080 ingress: host: order.example.internal設(shè)計values.yaml時有一個原則凡是因環(huán)境而異或可能隨時調(diào)整的值全部抽出來。鏡像tag、副本數(shù)、環(huán)境變量、域名這些基本必抽。而一些極少變化的Pod高級調(diào)度配置就沒必要全部外放否則values文件本身會變成新的維護(hù)負(fù)擔(dān)。3.3 模板語法與動態(tài)渲染詳解模板文件是Helm的靈魂。看一個完整且常見的deployment.yaml模板apiVersion: apps/v1 kind: Deployment metadata: name: {{ include order-service.fullname . }} labels: app.kubernetes.io/name: {{ include order-service.name . }} app.kubernetes.io/instance: {{ .Release.Name }} spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: app.kubernetes.io/name: {{ include order-service.name . }} template: metadata: labels: app.kubernetes.io/name: {{ include order-service.name . }} spec: containers: - name: {{ .Chart.Name }} image: {{ .Values.image.repository }}:{{ .Values.image.tag }} imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - containerPort: {{ .Values.service.port }} env: - name: REDIS_ADDR value: {{ .Values.env.REDIS_ADDR }} resources: {{- toYaml .Values.resources | nindent 12 }}這里有幾個語法點需要重點理解**.Values**是模板中訪問values.yaml參數(shù)的方式類似于當(dāng)前值上下文。image.tag的引用寫成{{ .Values.image.tag }}。注意如果參數(shù)沒定義Helm會渲染出一個空字符串而不是直接報錯。include函數(shù)用于復(fù)用_helpers.tpl中定義的有名字符串片段一般用來生成統(tǒng)一的資源名稱。推薦用include而不是template因為include的輸出可以被管道繼續(xù)處理用法更靈活。**toYaml與nindent**的組合很有趣。resources在values里是一個嵌套字典直接寫在模板里很難對齊縮進(jìn)這時用{{- toYaml .Values.resources | nindent 12 }}可以把整個字典序列化成YAML并縮進(jìn)12個空格完美嵌入模板。{{-和-}}的作用是去掉前后多余的空格和換行避免渲染出奇怪的空白行。寧可多用helm template檢查也不要憑肉眼猜渲染結(jié)果。這是唯一靠得住的校驗方式。3.4 lint、template與實際部署調(diào)試寫完模板文件后先做靜態(tài)檢查helm lint order-service/lint會檢查chart目錄結(jié)構(gòu)、YAML語法等基礎(chǔ)問題。它會提示從Chart.yaml到模板語法的一切可疑點先把這個錯誤全清掉再進(jìn)入下一步。接著最值得養(yǎng)成的習(xí)慣是用helm template做一次本地渲染直接看最終生成的K8s資源長什么樣helm template order-service/這樣渲染出來的YAML不會真正部署到集群適合在寫好模板后核對生成的Deployment是否符合預(yù)期。我第一次寫模板時清一色toYaml對齊錯誤導(dǎo)致的縮進(jìn)問題全靠這條命令一一抓出來的。確認(rèn)無誤后正式部署helm install order-prod order-service/如果想臨時覆蓋某個參數(shù)可以使用--set。比如緊急調(diào)小副本數(shù)helm upgrade order-prod order-service/ --set replicaCount13.5 依賴管理與公共庫復(fù)用隨著chart數(shù)量變多你會發(fā)現(xiàn)很多服務(wù)都在用幾乎相同的Ingress模板、數(shù)據(jù)庫連接配置邏輯代碼復(fù)制的情況越來越嚴(yán)重。這時就需要借助依賴管理把公共部分抽出來做成一個公共chart其他chart通過依賴引用來復(fù)用。在Chart.yaml中添加依賴的方式非常直接apiVersion: v2 name: order-service dependencies: - name: common version: 0.4.7 repository: https://chartrepo.internal.example.com然后執(zhí)行helm dependency update order-service/它會根據(jù)Chart.yaml聲明去倉庫拉取對應(yīng)版本的chart放到charts/目錄下。模板中的公共邏輯會用類似{{ include common.labels . }}這種方式調(diào)用。依賴管理引入的復(fù)雜度也不小比如傳遞依賴的版本沖突。我建議公共部分先從簡單的通用標(biāo)簽、健康檢查、鏡像拉取邏輯開始抽不要一上來就把所有業(yè)務(wù)邏輯都塞進(jìn)去。公共chart的變更要嚴(yán)格走版本發(fā)布流程避免某個服務(wù)升級依賴時被意外行為波及。4. 企業(yè)私有Chart倉庫搭建兩種落地方案的對比實踐4.1 為什么要自建倉庫以及Chart倉庫的機制也許有人會問chart直接放到Git倉庫每次部署用helm install ./本地目錄不行嗎只在個人開發(fā)場景下當(dāng)然沒問題但企業(yè)環(huán)境里至少有三個痛點解決不了多團(tuán)隊共享困難。A團(tuán)隊做好的通用chartB團(tuán)隊想用總不能把Git倉庫鏈接丟過去讓對方自己拉版本追溯沒有標(biāo)準(zhǔn)。chart的版本管理需要與K8s資源的變更一一對應(yīng)需要統(tǒng)一的版本存儲權(quán)限與審計能力缺失。誰能發(fā)布chart、誰在什么時候用了哪個chart都需要留痕。這里需要理解一個核心機制Helm chart倉庫本質(zhì)上不是Docker Registry那樣的二進(jìn)制鏡像倉庫而是一個帶索引的靜態(tài)文件服務(wù)器。倉庫里除了.tgz格式的chart包本身還需要一個index.yaml文件這個索引記錄了所有chart名稱、版本、校驗值和下載地址。執(zhí)行helm repo update時客戶端拉取的就是這個index.yaml文件之后根據(jù)索引里的URL去下載具體的chart包。明白了這個機制自己搭倉庫的思路就打開了只要能托管靜態(tài)文件、能更新索引就可以做chart倉庫。4.2 輕量方案對象存儲 ChartMuseum如果公司已經(jīng)有對象存儲如某內(nèi)部S3兼容存儲可以采用極簡方案。我把整個搭建過程記錄一下方便復(fù)現(xiàn)ChartMuseum本身是一個開源的chart倉庫服務(wù)端程序部署方式可以是二進(jìn)制、Docker鏡像或Helm chart。假設(shè)我們把它部署在一臺內(nèi)網(wǎng)機器上并配置使用S3兼容存儲保存chart包docker run -d \ --name chartmuseum \ -p 8080:8080 \ -e STORAGEamazon \ -e STORAGE_AMAZON_BUCKEThelm-charts \ -e STORAGE_AMAZON_PREFIXchartmuseum \ -e STORAGE_AMAZON_REGIONus-east-1 \ -e STORAGE_AMAZON_ENDPOINThttp://minio.internal.example.com:9000 \ -e STORAGE_AMAZON_S3_FORCE_PATH_STYLEtrue \ chartmuseum/chartmuseum:latest這里細(xì)講一下幾個配置的含義。STORAGEamazon表示使用S3兼容協(xié)議STORAGE_AMAZON_ENDPOINT指向內(nèi)網(wǎng)對象存儲地址STORAGE_AMAZON_S3_FORCE_PATH_STYLEtrue很關(guān)鍵某些兼容實現(xiàn)如MinIO需要路徑風(fēng)格訪問不設(shè)置會報簽名錯誤。部署完成后需要啟用chartmuseum的上傳API。默認(rèn)API是開啟的之后推送chart包可以借助helm cm-push插件helm plugin install https://github.com/chartmuseum/helm-push helm repo add order-repo http://10.24.5.10:8080 helm cm-push order-service/ order-repocm-push命令會把本地chart打包并上傳到ChartMuseumChartMuseum會自動更新index.yaml。這樣其他同事執(zhí)行helm repo update后就能搜索到這個新上傳的chart并部署了。這個方案的優(yōu)點是輕、快、成本低部署過程半小時內(nèi)能完成適合沒有現(xiàn)成制品管理平臺的小團(tuán)隊。4.3 一體化方案基于Harbor的Chart倉庫如果企業(yè)內(nèi)部已部署Harbor作為容器鏡像倉庫完全不需要額外部署ChartMuseum。Harbor從1.6版本開始原生支持chart倉庫功能和鏡像倉庫在同一個平臺統(tǒng)一管理天然支持權(quán)限控制、項目隔離和審計。啟用Harbor的chart倉庫后推送和拉取流程如下。先配置Helm倉庫地址。Harbor每個項目下都有獨立的chart倉庫端點helm repo add order-repo https://harbor.internal.example.com/chartrepo/order-project關(guān)于權(quán)限要注意Harbor在簽發(fā)Robot賬號時需要勾選對應(yīng)項目”的Helm Chart讀寫權(quán)限僅僅給鏡像權(quán)限是不夠的。這一步是最容易被忽略的我在落地時沒少見到同事卡在這里報401權(quán)限錯誤。上傳chart則同樣使用helm cm-push插件helm cm-push order-service/ order-repo也可以使用Harbor API直接上傳tgz包但我實測下來cm-push更順手一條命令完成打包上傳。使用Harbor方案的好處是明顯的chart版本與鏡像版本能在同一個平臺里關(guān)聯(lián)管理基于項目做訪問控制天然適合企業(yè)多團(tuán)隊多項目的安全合規(guī)訴求。代價是要部署和維護(hù)Harbor本身基礎(chǔ)服務(wù)越多運維負(fù)擔(dān)也越大。4.4 倉庫權(quán)限與安全設(shè)計無論哪種方案倉庫的權(quán)限控制都必須認(rèn)真設(shè)計。chart文件本質(zhì)上是一段可執(zhí)行的部署邏輯任何人都能修改chart內(nèi)容并部署到集群這是相當(dāng)危險的一件事。我見過一個真實的例子有同事為了圖方便把生產(chǎn)集群的kubeconfig放在共享目錄結(jié)果任何拿到這份kubeconfig的人都能對生產(chǎn)環(huán)境執(zhí)行任何操作。所以在企業(yè)落地時至少要落實三條安全基線chart倉庫賬號權(quán)限最小化發(fā)布chart用專門的機器人賬號不用個人賬號下載權(quán)限按項目隔離普通研發(fā)人員對生產(chǎn)項目只有拉取權(quán)限不能推送chart內(nèi)容變更要經(jīng)歷審核流程最好是打包上傳由CI系統(tǒng)執(zhí)行不給人肉操作入口。5. 企業(yè)項目落地經(jīng)驗版本管理、CI/CD集成與實測踩坑5.1 版本號管理與回滾的實操節(jié)奏chart的版本管理是落地的第一道基本功。Chart.yaml中的version字段是chart本身的版本而appVersion則是打包的應(yīng)用程序版本。兩者獨立變化。舉個例子應(yīng)用代碼從1.2.0升級到1.3.0但同時調(diào)整了chart里環(huán)境變量的寫法那么appVersion和version都應(yīng)該升級。如果只是改了chart的調(diào)度策略應(yīng)用版本沒變那只需遞增version。我采用的策略很簡單凡是改動chart內(nèi)容必須遞增version。哪怕只是改了一個默認(rèn)日志級別。否則后果是release歷史里兩條記錄顯示相同版本號實際內(nèi)容卻不同回滾時你根本不知道自己在回滾到什么狀態(tài)。每當(dāng)更新圖表后及時部署并記錄helm upgrade order-prod order-service/ --namespace backend查看部署歷史helm history order-prod回滾到上一個版本helm rollback order-prod 3配合helm history里展示的REVISION號回滾操作會變得非常可控、準(zhǔn)確。5.2 CI/CD集成時最容易出問題的環(huán)節(jié)真正到了企業(yè)級應(yīng)用chart的發(fā)布流程一定會被集成到CI/CD流水線里而不是靠人SSH到服務(wù)器手工執(zhí)行。一個標(biāo)準(zhǔn)的發(fā)布流水線可以設(shè)計為四個階段代碼構(gòu)建與鏡像推送應(yīng)用代碼編譯產(chǎn)物打包成Docker鏡像推送到Harbor或內(nèi)網(wǎng)鏡像倉庫更新chart包把新的appVersion同步更新到Chart.yaml和values.yaml發(fā)布chart到倉庫執(zhí)行helm cm-push把更新后的chart上傳觸發(fā)部署任務(wù)在目標(biāo)集群執(zhí)行helm upgrade --install。實際執(zhí)行中容易出問題的環(huán)節(jié)往往是第2步和第4步的銜接標(biāo)簽與鏡像版本不一致。某個服務(wù)升級鏡像tag已推送但values.yaml里引用的還是舊tag或者CI腳本里用動態(tài)生成的tag覆蓋了模板里的硬編碼值最終部署了錯誤版本。給一個更穩(wěn)健的參數(shù)傳遞方式不要在values.yaml里寫死鏡像tag而是用CI變量動態(tài)注入。在CI腳本中顯式傳入tag參數(shù)helm upgrade order-prod order-service/ \ --namespace backend \ --set image.tag${IMAGE_TAG} \ --set replicaCount${REPLICA_COUNT}這樣一次發(fā)版全鏈路更新避免多文件維護(hù)不同步的問題。5.3 多環(huán)境配置隔離的推薦做法企業(yè)在測試、預(yù)發(fā)、生產(chǎn)等多環(huán)境之間切換時硬編碼環(huán)境變量是最危險的。比如測試環(huán)境的Redis地址滲透到生產(chǎn)部署上等數(shù)據(jù)出問題再排查事情的起因就要花很長一段時間。推薦的做法是把環(huán)境差異全部收攏到values文件按環(huán)境分文件管理。創(chuàng)建三種環(huán)境的values文件order-service/ ├── values.yaml # 默認(rèn)配置 ├── values-test.yaml # 測試環(huán)境配置 ├── values-staging.yaml # 預(yù)發(fā)環(huán)境配置 └── values-prod.yaml # 生產(chǎn)環(huán)境配置部署測試環(huán)境使用helm install order-test order-service/ --values values-test.yaml --namespace test部署生產(chǎn)環(huán)境使用helm install order-prod order-service/ --values values-prod.yaml --namespace prod每個values文件定義自己的副本數(shù)、資源配置和域名。對于敏感的數(shù)據(jù)庫密碼或認(rèn)證Secret上述方式還有一個補充原則不要寫進(jìn)values.yaml明文中而是通過外部注入的Secret引用。在模板中盡量只支持Secret名稱和鍵名的配置具體內(nèi)容留到集群的Secret管理器中。5.4 真實踩坑記錄與排查鏈路最后分享一下落地Helm過程中印象比較深刻的兩個問題及其排查思路。問題一helm install卡在pending-install狀態(tài)某次部署一個服務(wù)release狀態(tài)一直是pending-installK8s資源沒起來。常規(guī)排查流程如下先用helm list -A確認(rèn)release的存在和狀態(tài)再通過kubectl describe查看關(guān)聯(lián)的資源對象。發(fā)現(xiàn)Pod本身拉取鏡像失敗——明明私有倉庫有該鏡像卻報ImagePullBackOff。進(jìn)一步排查發(fā)現(xiàn)是chart里的imagePullSecrets沒有配置。這個配置在values.yaml里是空數(shù)組集群拉取私有鏡像時沒有憑據(jù)。解決方案是先在命名空間創(chuàng)建好docker-registry類型的Secret再在template里引用它。排查這類問題的關(guān)鍵思路是先分清問題是Helm層還是K8s層。Helm層看渲染結(jié)果和release狀態(tài)K8s層看Pod狀態(tài)和事件。用.命令快速釘死問題所在而不是瞎猜。問題二滾動升級永遠(yuǎn)不結(jié)束升級某服務(wù)后新Pod一直處于CrashLoopBackOff狀態(tài)Deployment的滾動升級因此卡住。這個問題的觸發(fā)點是liveness探針配置不合理新版本由于環(huán)境變量缺少某些值健康檢查端口沒有正常監(jiān)聽探針永遠(yuǎn)失敗。排查時用kubectl get events看事件流很快發(fā)現(xiàn)探針失敗的具體時間戳和原因。之后回到values文件補上環(huán)境變量參數(shù)再執(zhí)行helm upgrade滾動升級才順利完成。這個案例提醒了我一件事模板寫得好不代表業(yè)務(wù)配置就正確。Helm只負(fù)責(zé)把變量渲染成K8s資源至于這些資源運行起來是否符合預(yù)期仍然需要強大的K8s排障能力兜底。最后一個經(jīng)驗分享不一定寫進(jìn)文檔但很實用。我們內(nèi)部現(xiàn)在要求所有chart的發(fā)布記錄都附帶一個部署前檢查清單渲染結(jié)果人工核對、版本號確認(rèn)、命名空間確認(rèn)、配置差異對比。這套習(xí)慣跑順之后線上部署出錯的概率至少降低了一半。Helm本身只是一個工具真正讓部署流程穩(wěn)定可控的是圍繞它建立起來的發(fā)布規(guī)范和團(tuán)隊協(xié)作方式希望這些內(nèi)容能幫你在自己的企業(yè)項目里少踩幾個坑。