設(shè)施即代碼與落地避坑)
簡(jiǎn)介《DevOps for Digital Leaders》中文可理解為“數(shù)字領(lǐng)導(dǎo)者的DevOps”是一份PDF格式的英文原版電子書聚焦如何通過DevOps實(shí)踐加速企業(yè)數(shù)字化轉(zhuǎn)型。該書面向企業(yè)領(lǐng)導(dǎo)者、技術(shù)管理者與架構(gòu)師系統(tǒng)闡述DevOps在現(xiàn)代軟件開發(fā)中的戰(zhàn)略價(jià)值并結(jié)合實(shí)例講解縮短開發(fā)周期、提升產(chǎn)品質(zhì)量以及實(shí)現(xiàn)持續(xù)交付和部署的方法書中覆蓋微服務(wù)架構(gòu)、API管理、自動(dòng)化測(cè)試等關(guān)鍵技術(shù)也針對(duì)移動(dòng)應(yīng)用與物聯(lián)網(wǎng)開發(fā)的挑戰(zhàn)給出建議。資源打包為單個(gè)PDF文件壓縮包大小僅13.24MB適合在電腦、平板等設(shè)備上隨時(shí)查閱。目前已獲得122人學(xué)習(xí)適合正在規(guī)劃或推進(jìn)DevOps轉(zhuǎn)型的團(tuán)隊(duì)借鑒。讀者可以從中獲得完整的原版論述參考作者提出的現(xiàn)代軟件工廠構(gòu)建思路用于設(shè)計(jì)研發(fā)流水線并優(yōu)化技術(shù)管理。1. 軟件工廠不是新名詞而是數(shù)字化轉(zhuǎn)型里決定交付速度的那道分水嶺很多團(tuán)隊(duì)做 DevOps 賦能數(shù)字化轉(zhuǎn)型時(shí)最容易犯的錯(cuò)是把工具買齊當(dāng)成工廠建成流水線有了、鏡像倉庫有了、一鍵發(fā)布也有了可需求從提測(cè)到上線仍然要按天計(jì)算。真正的現(xiàn)代軟件工廠不是一堆工具的拼裝而是把代碼提交、質(zhì)量校驗(yàn)、構(gòu)建、制品管理、環(huán)境準(zhǔn)備、部署與度量全部標(biāo)準(zhǔn)化成一條可以重復(fù)執(zhí)行的流水線讓每一次發(fā)布都走同一條路。軟件工廠回答的核心問題是平臺(tái)能否讓一個(gè)普通工程師不靠運(yùn)氣、不看前輩臉色就能把變更安全地送到生產(chǎn)。這條路適合正在做研發(fā)效能改造的團(tuán)隊(duì)、負(fù)責(zé)流水線和運(yùn)維平臺(tái)的工程師以及想評(píng)估 DevOps 投入值不值的管理者。2. 從手工作坊到流水線軟件工廠的四層模型與選型邊界傳統(tǒng)交付慢慢在太多環(huán)節(jié)靠人肉承擔(dān)。開發(fā)改完代碼要等運(yùn)維配環(huán)境、等測(cè)試準(zhǔn)備數(shù)據(jù)、等管理員開權(quán)限每一步都是等待。軟件工廠要把這些等待變成機(jī)器的并行執(zhí)行前提是先看清整個(gè)交付過程的分層結(jié)構(gòu)再?zèng)Q定每一層用什么工具、什么規(guī)范來承載。2.1 四層結(jié)構(gòu)需求到交付的標(biāo)準(zhǔn)化流水線軟件工廠可以拆成四層。第一層是接入層解決“代碼怎么進(jìn)來”的問題包括代碼托管、分支策略、合并請(qǐng)求審查和提交信息規(guī)范。這一層決定了工廠收什么樣的原料。很多團(tuán)隊(duì)忽視接入層的治理任何分支、任何提交都能觸發(fā)流水線工廠就會(huì)癱瘓?jiān)跓o效構(gòu)建里。第二層是流水線層負(fù)責(zé)把代碼從提交帶到可部署的制品包括靜態(tài)檢查、單元測(cè)試、構(gòu)建、制品上傳。這一層定義了“怎么加工”。第三層是制品層把版本號(hào)、依賴清單、鏡像摘要、構(gòu)建日志這些不可變信息綁在一起是回滾與審計(jì)的依據(jù)。沒有制品層的規(guī)范流水線跑得再快出了事故也說不清線上跑的是哪份代碼。第四層是環(huán)境層用基礎(chǔ)設(shè)施即代碼定義開發(fā)、測(cè)試、生產(chǎn)環(huán)境讓“在哪里運(yùn)行”這件事可以重復(fù)、可以重建。四層之間是一層層往下服務(wù)的接入層管原料流水線層管加工制品層管產(chǎn)出標(biāo)記環(huán)境層管車間。理解這一結(jié)構(gòu)的意義在于任何一層如果靠人手工補(bǔ)位都會(huì)成為整條交付鏈的瓶頸。軟件工廠的交付速度不是由最快環(huán)節(jié)決定的而是由最慢的那個(gè)手工環(huán)節(jié)決定的。這也是很多團(tuán)隊(duì)的自動(dòng)化程度看著很高、實(shí)際交付速度卻沒變化的根本原因自動(dòng)化只是在原有手工流程外面套了一層殼主干道上的手工等待一點(diǎn)沒減少。2.2 選型參考按交付形態(tài)選工具鏈而不是按熱度選工具鏈選型沒有絕對(duì)的“最好”只有“適合當(dāng)前交付形態(tài)”。我一般會(huì)先問三個(gè)問題交付物是什么形態(tài)、團(tuán)隊(duì)多少人維護(hù)平臺(tái)、失敗時(shí)能不能看到過程。把這三個(gè)問題問完再去看具體方案基本不會(huì)選錯(cuò)。交付形態(tài)典型場(chǎng)景流水線重點(diǎn)環(huán)境策略后端服務(wù)微服務(wù)、定時(shí)任務(wù)、接口平臺(tái)編譯、單元測(cè)試、鏡像構(gòu)建、滾動(dòng)發(fā)布容器化多環(huán)境常駐前端應(yīng)用Web 站點(diǎn)、小程序、后臺(tái)管理依賴安裝、靜態(tài)構(gòu)建、資源上傳 CDN動(dòng)態(tài)預(yù)覽環(huán)境優(yōu)先嵌入式/桌面固件、驅(qū)動(dòng)程序、客戶端交叉編譯、靜態(tài)檢查、版本簽名模擬器加真實(shí)設(shè)備數(shù)據(jù)項(xiàng)目報(bào)表、模型訓(xùn)練、數(shù)據(jù)同步數(shù)據(jù)質(zhì)量校驗(yàn)、模型版本管理沙箱環(huán)境加預(yù)生產(chǎn)選型的另一個(gè)原則是統(tǒng)一。流水線平臺(tái)、制品倉庫、密鑰管理這三樣?xùn)|西每一樣只選一個(gè)主方案避免不同項(xiàng)目各玩各的。我見過太多團(tuán)隊(duì)把工具選型做成技術(shù)嘗鮮今天這個(gè)新出的引擎明天那個(gè)社區(qū)熱門的調(diào)度器最后平臺(tái)沒人會(huì)維護(hù)。工具鏈要能支持命令行驅(qū)動(dòng)、能自定義質(zhì)量門禁、能在失敗時(shí)保留完整日志。避免選那種只能在界面上點(diǎn)點(diǎn)點(diǎn)的黑匣子系統(tǒng)排障時(shí)看不到過程就是災(zāi)難。一個(gè)常見的錯(cuò)誤是照搬大廠的工具列表。大型團(tuán)隊(duì)的數(shù)千條流水線方案很難復(fù)制到只有幾個(gè)工程師的團(tuán)隊(duì)因?yàn)槿松倭司S護(hù)模板的時(shí)間就沒了。選型要按團(tuán)隊(duì)的實(shí)際運(yùn)維承受力來而不是按熱搜詞來。2.3 軟件工廠的成熟度分級(jí)你在哪一級(jí)往哪走判斷一個(gè)團(tuán)隊(duì)處于軟件工廠的哪個(gè)階段不需要看 PPT看日常怎么發(fā)布就行。我習(xí)慣把成熟度分成四級(jí)。級(jí)別特征典型狀態(tài)下一步L0 手工作坊人工編譯、人工上傳、人工跑環(huán)境發(fā)布靠個(gè)人經(jīng)驗(yàn)先建一條最小流水線L1 腳本化每個(gè)項(xiàng)目各自寫了構(gòu)建腳本能構(gòu)建但不能復(fù)用抽公共流水線模板L2 流水線化統(tǒng)一模板、統(tǒng)一制品、質(zhì)量門禁多數(shù)項(xiàng)目能自助發(fā)布補(bǔ)環(huán)境基礎(chǔ)設(shè)施代碼化L3 平臺(tái)化自助申請(qǐng)環(huán)境、自服務(wù)發(fā)布研發(fā)獨(dú)立完成日常發(fā)布做度量和治理判斷標(biāo)準(zhǔn)很樸素一個(gè)新同事加入兩周能不能獨(dú)立把一個(gè)需求從提測(cè)部署到測(cè)試環(huán)境。如果答案是不能說明團(tuán)隊(duì)還在 L1 以下先別談宏大的平臺(tái)建設(shè)把 L2 補(bǔ)上比什么都重要。另一個(gè)參考指標(biāo)是發(fā)布平均耗時(shí)L2 以上的團(tuán)隊(duì)主干分支從提交到測(cè)試環(huán)境部署應(yīng)該控制在半小時(shí)以內(nèi)超過兩小時(shí)基本說明中間有手工環(huán)節(jié)在排隊(duì)。3. 用一條最小價(jià)值流水線跑通軟件工廠的核心閉環(huán)分層的模型講清楚之后接下來要落地。我建議不要一開始鋪開幾十條流水線先跑通一條最小價(jià)值閉環(huán)再復(fù)制成模板。這條閉環(huán)需要覆蓋從代碼提交到測(cè)試環(huán)境部署的全過程讓團(tuán)隊(duì)第一次感受到“代碼合并后環(huán)境自己更新了”。3.1 最小閉環(huán)的構(gòu)成五件事缺一不可最小價(jià)值流水線不用考慮太多場(chǎng)景先跑通五件事靜態(tài)檢查、單元測(cè)試、構(gòu)建并生成不可變制品、推送到制品倉庫、自動(dòng)部署到測(cè)試環(huán)境。這五件事跑通后代碼只要合到主干測(cè)試環(huán)境就會(huì)自動(dòng)更新到最新版本。團(tuán)隊(duì)可以在這個(gè)閉環(huán)上慢慢加覆蓋率門禁、加部署策略、加安全掃描。有兩點(diǎn)是初期就要立下的規(guī)矩不然后面返工成本非常高。第一制品不與源碼綁定就不允許進(jìn)入部署環(huán)節(jié)。每次構(gòu)建生成的鏡像或安裝包必須帶有能反查到源碼提交的版本號(hào)。第二流水線失敗必須喊出聲來通知到寫代碼的人和值班的人而不是默默失敗第二天才發(fā)現(xiàn)測(cè)試環(huán)境還是昨天的版本。這兩條規(guī)矩會(huì)直接影響后面避坑章里講的可追溯性。3.2 從提交到部署的流水線參考定義下面給一份最小價(jià)值流水線的參考寫法。這是 pipeline-as-code 的通用 YAML 示例字段名在不同的 CI 平臺(tái)上略有差異但結(jié)構(gòu)是通用的。# 模擬項(xiàng)目X 的最小價(jià)值流水線 stages: - test - build - publish - deploy test: stage: test image: maven:3-jdk-21 script: - mvn test rules: - if: $CI_PIPELINE_SOURCE merge_request_event when: always build: stage: build image: maven:3-jdk-21 script: - mvn package -DskipTests artifacts: paths: - target/*.jar rules: - if: $CI_COMMIT_BRANCH main publish: stage: publish image: docker:24 script: - docker build -t ${REGISTRY_IMAGE}:${COMMIT_SHORT_SHA} . - docker push ${REGISTRY_IMAGE}:${COMMIT_SHORT_SHA} needs: [build] rules: - if: $CI_COMMIT_BRANCH main deploy: stage: deploy image: docker:24 script: - kubectl set image deployment/demo demo${REGISTRY_IMAGE}:${COMMIT_SHORT_SHA} environment: name: testing needs: [publish] rules: - if: $CI_COMMIT_BRANCH main這段配置的流向是test 階段只在合并請(qǐng)求事件中執(zhí)行保證代碼合入主干前先跑完單元測(cè)試build 階段只在主干分支執(zhí)行把 Maven 項(xiàng)目打成 jar 包并通過 artifacts 把產(chǎn)物傳遞給后續(xù)階段publish 階段依賴 build 的產(chǎn)物構(gòu)建出帶提交短哈希標(biāo)簽的鏡像并推送到制品倉庫deploy 階段依賴 publish 的產(chǎn)物把 testing 環(huán)境里的 deployment 鏡像更新到剛推送的版本。參數(shù)說明里有幾個(gè)點(diǎn)值得留意。artifacts.paths指定了構(gòu)建產(chǎn)物路徑這個(gè)產(chǎn)物只在當(dāng)前流水線內(nèi)部有效正式環(huán)境要設(shè)置對(duì)應(yīng)的保留策略needs的作用是讓 publish 不必等 test 和 build 全部跑完再開始而是只等 build 完成這對(duì)縮短流水線總耗時(shí)非常關(guān)鍵COMMIT_SHORT_SHA這類變量由 CI 平臺(tái)在運(yùn)行時(shí)自動(dòng)注入不要手寫在文件里。image字段表示每個(gè)任務(wù)運(yùn)行在獨(dú)立的臨時(shí)容器中這保證任務(wù)之間的環(huán)境互不污染是軟件工廠“可重復(fù)”的基礎(chǔ)。3.3 參數(shù)怎么改從參考實(shí)現(xiàn)到團(tuán)隊(duì)模板的三個(gè)改造方向第一處要改的是質(zhì)量門禁。上面的示例只跑了測(cè)試沒有檢查覆蓋率。常見做法是接入覆蓋率閾值低于閾值就直接失敗例如要求單元測(cè)試覆蓋率不低于 80%。這一步會(huì)讓測(cè)試從“跑了”變成“跑過且達(dá)標(biāo)”質(zhì)量門禁的語義完全不同。第二處要改的是部署策略。deploy 階段直接用 kubectl 更新鏡像適合小團(tuán)隊(duì)的測(cè)試環(huán)境但生產(chǎn)環(huán)境應(yīng)該改成滾動(dòng)更新或藍(lán)綠發(fā)布并用 Helm 這類發(fā)布工具管理版本這樣回滾時(shí)可以快速回到上一個(gè)版本。用 kubectl 直接 set image 的缺點(diǎn)是發(fā)布記錄分散在命令行歷史里缺少統(tǒng)一審計(jì)。發(fā)布工具能把版本、時(shí)間、操作人集中記錄審計(jì)和回滾都方便。第三處要改的是觸發(fā)規(guī)則。上面的示例只在 main 分支上觸發(fā)實(shí)際項(xiàng)目還需要支持版本標(biāo)簽發(fā)布。常見觸發(fā)策略可以按下面這張表來規(guī)劃。觸發(fā)場(chǎng)景規(guī)則條件流水線內(nèi)容合并請(qǐng)求merge_request_event只跑測(cè)試和靜態(tài)檢查主干分支main完整流水線并自動(dòng)部署測(cè)試環(huán)境版本標(biāo)簽v1.2.0走發(fā)布流程人工審批后部署生產(chǎn)不要一開始就把所有環(huán)境都塞進(jìn)一條流水線。測(cè)試環(huán)境、預(yù)發(fā)布環(huán)境、生產(chǎn)環(huán)境應(yīng)該拆成獨(dú)立的部署任務(wù)分別配置不同的權(quán)限和審批人。一個(gè)階段的失敗不能影響另一個(gè)環(huán)境的發(fā)布這是 L2 階段就應(yīng)該形成的肌肉記憶。4. 基礎(chǔ)設(shè)施即代碼工廠的設(shè)備與車間管理流水線把代碼變成制品但制品最終要跑在環(huán)境里。如果環(huán)境還是靠運(yùn)維手工搭出來的那么流水線再標(biāo)準(zhǔn)交付鏈路仍有一大段在工廠之外。環(huán)境一致性是軟件工廠最容易忽視、卻最影響信心的部分。4.1 環(huán)境一致性是軟件工廠的隱形支柱最常見的一句話是“我本地跑得好好的怎么測(cè)試環(huán)境就掛了”。這種問題通常不是代碼問題而是環(huán)境差異本地依賴了某個(gè)系統(tǒng)庫測(cè)試環(huán)境的操作系統(tǒng)版本不一樣本地環(huán)境變量配過測(cè)試環(huán)境沒配數(shù)據(jù)庫初始化腳本只在一臺(tái)機(jī)器上執(zhí)行過。環(huán)境與代碼一樣需要納入版本管理這就是基礎(chǔ)設(shè)施即代碼的核心價(jià)值。軟件工廠的目標(biāo)是環(huán)境即代碼所有環(huán)境由倉庫中的聲明式配置構(gòu)建而不是由運(yùn)維手工配置。環(huán)境可以重建是基本要求。如果一臺(tái)開發(fā)機(jī)崩了要手動(dòng)恢復(fù)三天工廠就沒資格談產(chǎn)能。判斷環(huán)境是否做到了代碼化方法很簡(jiǎn)單把當(dāng)前環(huán)境刪掉按照倉庫里的說明從零搭建如果還能還原出一模一樣的環(huán)境就算及格了。這條標(biāo)準(zhǔn)看起來很基礎(chǔ)但很多團(tuán)隊(duì)連這點(diǎn)都做不到。4.2 用容器和聲明式工具定義可復(fù)現(xiàn)環(huán)境的參考實(shí)現(xiàn)我一般從兩套配置入手。第一套是面向本地開發(fā)和測(cè)試環(huán)境的容器編排文件第二套是面向云上資源的聲明式配置。容器編排文件解決“應(yīng)用跑起來需要什么”聲明式資源解決“環(huán)境在云上長什么樣”。# 本地與測(cè)試環(huán)境通用編排文件 docker-compose.yml services: api: build: context: ./app environment: SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev} ports: - ${API_PORT:-8080}:8080 depends_on: db: condition: service_healthy db: image: postgres:16-alpine environment: POSTGRES_DB: ${POSTGRES_DB:-demo} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-demo} volumes: - db_data:/var/lib/postgresql/data healthcheck: test: [CMD-SHELL, pg_isready -U ${POSTGRES_DB} -d ${POSTGRES_DB}] interval: 5s retries: 10 volumes: db_data:這段配置的關(guān)鍵點(diǎn)有三個(gè)。 environment 里的變量都支持外部傳參本地用默認(rèn)值測(cè)試環(huán)境通過環(huán)境變量文件覆蓋同一份文件可以跑出兩套環(huán)境。depends_on 配合 healthcheck 讓 api 服務(wù)在數(shù)據(jù)庫還未就緒前不會(huì)啟動(dòng)解決容器編排里最常見的啟動(dòng)順序問題。數(shù)據(jù)卷把數(shù)據(jù)庫文件持久化避免容器重建后數(shù)據(jù)丟失。這條文件在本地和測(cè)試環(huán)境通用減少了“本地環(huán)境和測(cè)試環(huán)境不一致”的第一大來源。注意上面的配置里有默認(rèn)密碼只適合本地開發(fā)。測(cè)試環(huán)境和生產(chǎn)環(huán)境必須使用密鑰管理系統(tǒng)注入密碼不能依賴默認(rèn)值。第二套配置是面向云上資源的聲明式寫法下面是用 Terraform 管理 Kubernetes Namespace 的示例。# 軟件工廠環(huán)境資源聲明示例 variable environment { type string default test } variable namespace { type string default factory-demo } resource kubernetes_namespace factory { metadata { name ${var.namespace}-${var.environment} } }這里用變量把環(huán)境名和命名空間名拆開是為了同一個(gè)目錄可以通過-var environmentprod生成另一套資源避免復(fù)制粘貼整個(gè)目錄。就像軟件工程的函數(shù)一樣抽參數(shù)而不是復(fù)制代碼。需要先配置對(duì)應(yīng)的云端 provider 和認(rèn)證信息這里略去賬號(hào)相關(guān)內(nèi)容。聲明式資源的好處是環(huán)境版本可以進(jìn) Git每次變更都留下記錄出問題可以對(duì)比前后差異。4.3 環(huán)境策略長期環(huán)境與動(dòng)態(tài)預(yù)覽環(huán)境怎么搭配不是每個(gè)需求都需要一套完整環(huán)境環(huán)境太多會(huì)吃掉大量運(yùn)行成本。我一般按下面這張表來規(guī)劃環(huán)境策略。環(huán)境生命周期流水線觸發(fā)使用場(chǎng)景本地環(huán)境需求開發(fā)期間無開發(fā)者自測(cè)靠容器編排模擬測(cè)試環(huán)境長期存在主干分支測(cè)試團(tuán)隊(duì)日常驗(yàn)證預(yù)覽環(huán)境短時(shí)存在合并請(qǐng)求評(píng)審、聯(lián)調(diào)、UI 走查生產(chǎn)環(huán)境長期存在版本標(biāo)簽發(fā)布流程需審批與審計(jì)動(dòng)態(tài)預(yù)覽環(huán)境是軟件工廠里性價(jià)比很高的一項(xiàng)投入。每個(gè)合并請(qǐng)求自動(dòng)拉起一套獨(dú)立環(huán)境分支合并或關(guān)閉后自動(dòng)銷毀評(píng)審人員可以直接訪問預(yù)覽環(huán)境看效果。這比截圖評(píng)審靠譜得多。預(yù)覽環(huán)境的成本可以通過配置精簡(jiǎn)來控制比如只啟動(dòng)應(yīng)用服務(wù)和緩存不掛完整的數(shù)據(jù)集群。5. 軟件工廠落地避坑5個(gè)讓流水線翻車的典型問題實(shí)踐過的團(tuán)隊(duì)基本都踩過這些坑。每一條都是現(xiàn)象、原因、解決三個(gè)環(huán)節(jié)按這個(gè)順序排查定位最有效。下面的五個(gè)問題如果只記住一個(gè)那也是第五個(gè)超八成環(huán)境事故和它有關(guān)。5.1 自動(dòng)化率拉滿交付速度卻幾乎沒變現(xiàn)象流水線跑得很快從代碼提交到構(gòu)建完成只要十分鐘但需求從提測(cè)到上線整體耗時(shí)沒有變化甚至更慢了。原因是自動(dòng)化只覆蓋了編碼到構(gòu)建這一段環(huán)境申請(qǐng)、測(cè)試數(shù)據(jù)準(zhǔn)備、聯(lián)調(diào)協(xié)調(diào)仍然靠人肉溝通。自動(dòng)化部分在空轉(zhuǎn)瓶頸在系統(tǒng)之外。解決先畫一張從需求到上線的全流程時(shí)間線把等待超過十分鐘的環(huán)節(jié)全部標(biāo)出來。環(huán)境準(zhǔn)備用基礎(chǔ)設(shè)施即代碼解決測(cè)試數(shù)據(jù)用腳本和固定數(shù)據(jù)集解決聯(lián)調(diào)通知靠自動(dòng)推送解決。不要在一個(gè)環(huán)節(jié)上過度優(yōu)化整體交付時(shí)間才是度量。流水線只是生產(chǎn)環(huán)節(jié)訂單來了還要有人接單、排產(chǎn)、質(zhì)檢工廠才算完整。5.2 質(zhì)量門禁形同虛設(shè)現(xiàn)象覆蓋率閾值配了靜態(tài)檢查也加了但流水線照樣綠制品照常部署。門禁存在但沒有任何約束力更像給管理者看的一件裝飾品。原因是門禁配置成了軟門禁任務(wù)失敗只告警、不阻斷或者閾值低到?jīng)]有任何意義形同虛設(shè)。假門禁比沒有門禁更糟因?yàn)樗鼤?huì)消耗團(tuán)隊(duì)對(duì)質(zhì)量體系的信任。解決要么做硬阻斷流水線內(nèi)質(zhì)量任務(wù)失敗就停止后續(xù)階段發(fā)布不出去倒逼研發(fā)重視要么就別配門禁。上線初期先選兩個(gè)真正有效的檢查單元測(cè)試失敗阻斷、鏡像高危漏洞阻斷。覆蓋率這類指標(biāo)可以放在第二階段作為趨勢(shì)看板而不是一開始就設(shè)門檻否則會(huì)引發(fā)大量的“為了覆蓋率寫測(cè)試”的造假式努力。5.3 制品不可追溯“能跑”和“知道跑的是什么”是兩回事現(xiàn)象線上出了故障找到對(duì)應(yīng)源碼版本號(hào)對(duì)不上要回滾發(fā)現(xiàn)上一次生產(chǎn)用的鏡像全被 latest 覆蓋找不到舊版本。原因是制品與源碼沒有強(qiáng)綁定鏡像 tag 用時(shí)間戳或 latest 覆蓋了歷史版本。沒有不可變版本號(hào)的制品回滾就是碰運(yùn)氣。解決統(tǒng)一制品版本規(guī)則用構(gòu)建號(hào)或提交短哈希作為鏡像 tag像第 3 章示例里的COMMIT_SHORT_SHA那樣。發(fā)布記錄與源碼提交、流水線運(yùn)行 ID 綁定能從一次運(yùn)行 ID 查出源碼 commit、依賴清單、鏡像摘要。這個(gè)約定要在搭建流水線的第一天就立好后面補(bǔ)救成本是初期的十倍。5.4 把密鑰寫進(jìn)流水線現(xiàn)象流水線配置文件里直接寫了數(shù)據(jù)庫密碼、云訪問密鑰。掃描工具掃出明文密鑰后需要輪換整個(gè)環(huán)境的憑據(jù)影響一大片服務(wù)。原因是圖省事或者沒有意識(shí)到流水線文件通常能被團(tuán)隊(duì)里大部分成員看到。倉庫的可見范圍遠(yuǎn)大于生產(chǎn)服務(wù)器明文密鑰就相當(dāng)于把保險(xiǎn)柜鑰匙掛在公司門口。解決密鑰放進(jìn)專門的密鑰管理服務(wù)流水線運(yùn)行時(shí)通過變量引用日志里禁止打印環(huán)境變量。輪換要有固定周期不能只等出事再換。任何寫進(jìn)代碼庫的明文密鑰一律視為已泄露。已發(fā)現(xiàn)的明文密鑰立刻輪換不要抱有“先跑著找時(shí)間再處理”的僥幸心理。5.5 測(cè)試環(huán)境與生產(chǎn)環(huán)境漂移部署成功靠玄學(xué)現(xiàn)象測(cè)試環(huán)境一百次部署都成功生產(chǎn)一部署就掛。排查原因永遠(yuǎn)都是“配置不一樣”生產(chǎn)環(huán)境手工改過配置文件、安全組規(guī)則不同、數(shù)據(jù)庫參數(shù)不一樣。環(huán)境漂移是所有偶發(fā)問題的溫床它讓流水線在一個(gè)環(huán)境上驗(yàn)證通過的結(jié)論在另一個(gè)環(huán)境上完全失效。解決把環(huán)境差異全部收斂為環(huán)境變量與配置文件差異不允許登錄服務(wù)器手工改配置。生產(chǎn)配置也要進(jìn)版本庫出現(xiàn)漂移能用腳本比對(duì)并告警。每一次手工變更都要作為事故復(fù)盤的第一步被審視。這一條是五個(gè)坑里最難補(bǔ)的因?yàn)榄h(huán)境通常已經(jīng)漂移了很久補(bǔ)起來需要逐項(xiàng)核對(duì)但也是最值得補(bǔ)的。6. 用度量體系判斷軟件工廠的成效再把工廠升級(jí)為內(nèi)部開發(fā)者平臺(tái)流水線和環(huán)境都跑通之后下一步是把軟件工廠變成“可度量、可治理”的系統(tǒng)最終向內(nèi)部開發(fā)者平臺(tái)演進(jìn)。沒有度量所有改造都只能憑感覺判斷做決策就沒有依據(jù)。DORA 四指標(biāo)是業(yè)界公認(rèn)的交付效能度量框架我用的就是這四個(gè)部署頻率、變更前置時(shí)間、變更失敗率、故障恢復(fù)耗時(shí)。它們要合起來看不能單看部署頻率部署多但失敗率高說明質(zhì)量門禁在失效自動(dòng)化只是加速了錯(cuò)誤的上線。指標(biāo)怎么統(tǒng)計(jì)健康參考部署頻率每周生產(chǎn)成功發(fā)布次數(shù)高績效團(tuán)隊(duì)按天甚至按小時(shí)計(jì)變更前置時(shí)間代碼合入到生產(chǎn)發(fā)布通過的耗時(shí)小時(shí)級(jí)到一天以內(nèi)變更失敗率失敗發(fā)布次數(shù)占總發(fā)布次數(shù)比例低于 15%故障恢復(fù)耗時(shí)從生產(chǎn)故障到恢復(fù)的時(shí)長小時(shí)級(jí)數(shù)據(jù)要從流水線自動(dòng)采集不要人工填報(bào)。多數(shù)流水線平臺(tái)都提供運(yùn)行記錄導(dǎo)出下面這條 SQL 是一個(gè)很輕量的統(tǒng)計(jì)示例。-- 從流水線運(yùn)行記錄表按周統(tǒng)計(jì)生產(chǎn)部署次數(shù) SELECT date_trunc(week, finished_at) AS week, count(DISTINCT run_id) AS deploy_count FROM pipeline_runs WHERE environment production AND status success GROUP BY 1 ORDER BY 1 DESC;假設(shè)流水線平臺(tái)把運(yùn)行記錄同步到了數(shù)據(jù)倉庫這條 SQL 就能直接回答“部署頻率”這個(gè)指標(biāo)。變更前置時(shí)間需要關(guān)聯(lián)源碼提交時(shí)間和發(fā)布完成時(shí)間數(shù)據(jù)模型會(huì)復(fù)雜一些。先把這個(gè)簡(jiǎn)單的跑起來有了數(shù)據(jù)基礎(chǔ)再逐步加維度比一開始就建一個(gè)大而全的度量平臺(tái)穩(wěn)妥得多。度量穩(wěn)定運(yùn)行之后團(tuán)隊(duì)通常已經(jīng)具備 L2 到 L3 的平臺(tái)能力這時(shí)候瓶頸往往不再是流水線本身而是“等平臺(tái)回答問題”的時(shí)間。內(nèi)部開發(fā)者平臺(tái)的方向是把軟件工廠的能力進(jìn)一步封裝成自助服務(wù)研發(fā)可以自己申請(qǐng)環(huán)境、自己發(fā)布、自己查看運(yùn)行鏈路平臺(tái)團(tuán)隊(duì)從“替研發(fā)操作”轉(zhuǎn)變?yōu)椤熬S護(hù)能力本身”。我自己的習(xí)慣是接手一個(gè)新平臺(tái)時(shí)只問四件事流水線能不能重復(fù)跑制品能不能追溯環(huán)境能不能重建失敗能不能被統(tǒng)計(jì)。這四件事立得住再談度量治理和平臺(tái)化立不住其他都是裝飾。軟件工廠這條路沒有捷徑把一條流水線做好、做扎實(shí)、做成模板比鋪開一百條跑不動(dòng)的流水線更有價(jià)值靠一條高質(zhì)量流水線建立團(tuán)隊(duì)信心才是數(shù)字化轉(zhuǎn)型里最劃算的投資。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取