DevOps最佳實踐之應用開發和部署

關於最佳實踐

本系列內容是我們在不同項目的維護過程中總結的關於DevOps/SRE方面的最佳實踐,我們將致力於在項目上盡最大的努力來推行這些最佳實踐。我們希望這些最佳實踐能對項目的穩定運營提供幫助,也希望剛接觸DevOps/SRE的新人能通過學習這些最佳實踐來提升自己在這方面的水平。

因爲DevOps/SRE涉及到的方方面面比較多,一次性完成的工作量太大,所以我們決定分階段來完成,這一次發佈的是“應用開發和部署”這個部分的內容,後續我們將逐步發佈“雲平臺與網絡”,“操作系統和服務”,“用戶與權限”,“監控與可視化”,“數據與備份”,“敏感數據”,“故障與應急響應”這幾部分的內容。

所謂“最佳實踐”應該是最適合自己的實踐,而不一定是最先進的,而且每一種實踐本身也存在一定的侷限性,所以我們在描述了對應實踐的優點的同時,也把可能存在的缺點寫了出來,就是希望大家在看到它的好處的時候,也能知道可能存在的風險在那裏,理性地去評估到底是不是要採用相應的實踐,所以這裏總結的最佳實踐請適度取用,不要爲了“最佳”而實踐。

我們深知自己在諸多方面存在一定的侷限性,相關的內容可能存在一些不足,而且最佳實踐本身會隨着技術更新等因素不停地變化,我們將會把藍皮書內容同步發佈在Github上(https://github.com/toc-lib/DevOps-SRE-best-practice) ,希望引發更廣範圍的傳播和討論。也請使用PR或Issue的方式來提出你的不同的觀點和更好的建議,謝謝。

應用開發和部署

使用牲口模式

在傳統的運維環境中,由於條件的限制無法快速的提供新的基礎設施和環境,所以通常在業務的依賴環境如操作系統內核,服務,類庫,運行時版本等需要變化時,我們會根據需要在現有的環境上做持續性變更。而且我們還可能會在機器上運行一些臨時任務,做調試和排錯等,很多的時候,這些操作對應的變化並不具有可追溯性,甚至不可以恢復到之前的狀態。這樣,剛開始統一配置的無差別的一批機器隨着時間的推移慢慢的就會變得各自具有一些獨有的特性。另外還有一些類型的服務,比如數據庫,存儲等,其業務本質就導致了集羣中的每一臺機器具有獨特的屬性。當我們在維護這些服務的時候,需要根據每臺機器的特性來做不同的管理和配置,而且一旦機器出現故障的時候,也很難去創建出一樣的機器來替代。因爲這種情形和養寵物類似,比如我們會給寵物起一個名字,它也需要悉心照料,生病的時候要帶去看病,所以我們稱這種服務模式爲寵物模式。

而在具有云原生能力的平臺上,我們可以按需定製基礎鏡像,也能快速的從這個基礎鏡像中創建出運行環境,我們的變更就可以基於基礎鏡像來做更新和版本迭代。這樣當某一臺機器發生了故障,我們可以快速的複製出一臺一模一樣的機器來替代。如果需要做一些臨行性的操作和變化,在任務結束之後,也可以銷燬這臺已經發生了變化的機器,使用一臺新的機器來替代,使整個集羣恢復到一個最初的收斂狀態。這個場景和我們現實生活中的規模化牲口養殖類似,對應的我們稱這種服務模式爲牲口模式。

大家所熟知的無狀態應用,就是牲口模式的最常用的一種實現方式。在業務的設計和實施過程中,我們建議把邏輯和數據分離,在邏輯運行環境不要兼顧數據存儲工作,比如請求的session相關的數據,不要保存在本地,而是把它放在一個共享數據服務中,從而達到無狀態的目的,這樣就可以對邏輯運行環境進行牲口化的管理方式。

優點:

  1. 可隨時被銷燬或替換,結合自動化基礎設施和監控,自動完成對故障機器或節點的替換。
  2. 配合自動化基礎設施和監控,可實現自動水平伸縮,從容應對業務峯谷,節約成本。
  3. 在不影響服務穩定性的前提下可部署所需要版本的應用、進行系統升級或者打補丁。
  4. 監控和管理的重心不再是具體的單一資源的使用率,而是整體的承載能力和更深層次的性能關注點。

缺點:

  1. 需要基礎設施平臺具有相應的能力支撐,否則很難實現。
  2. 不是所有的業務類型都能做牲口模式設計,比如數據庫。

實施要點:

  1. 除計算和業務處理過程中的臨時產生的數據,數據的來源和最終的持久化應由外部服務來提供,如獨立的內存型數據庫或者關係型數據庫。
  2. 可以使用客戶端Cookie、cache取代外部數據服務。如果有敏感數據,服務器端可以加密後交由客戶端存儲,在之後的請求時發回服務器解密使用。
  3. 通過鎖或者冪等性設計,使得應用能正確、快速、自動地解決對同一份數據的競爭而導致的流程異常、數據不一致等問題。例如,多個定時任務同時處理一批數據。

使業務升級向前兼容

向前兼容指低版本的系統、程序或技術能優雅處理(例如:忽略其不理解的部分)高版本的系統、程序或技術。向前兼容技術的目標是讓舊系統能夠識別爲新系統生成的數據,簡單的說就是舊版本的系統可以接受新版本的數據,是舊版本對新版本的兼容。

我們建議在做業務升級時候,設計你的業務具有向前兼容的能力,以應對升級失敗時某一功能模塊或者依賴無法隨之回滾的風險。比如說在有數據庫字段變化的升級中,在正式對數據庫做變動之前,基於舊的業務流程做代碼層面更新,使其可以兼容數據庫將要發生的改動並加以部署。在數據庫升級完成之後,如果新的業務流程上線後不幸出現重大的問題等情況需要回滾時,回滾之後的代碼仍然可以兼容數據庫的變化,而不用對數據庫也進行回滾,畢竟數據庫的回滾成本非常高。

優點:

  1. 可以在新版本出現不容易修復和存在重大的風險的時候快速當回滾到舊的版本,業務中斷的可能性會大大降低。
  2. 即使整個系統中存在不可回滾的部分,但我們不用花費很多的精力去考慮和解決完全不可回滾的問題。

缺點:

  1. 設計成本:要做到兼容未來的變化。這聽起來就很難。一開始很難獲知所有用例、極端案例和業務理解。回顧過去並說這是一個錯誤的決定很容易,今天做出明天不會後悔的決定要困難得多。
  2. 爲了同時兼容兩種數據格式,需要在代碼中增加額外的處理邏輯,增加複雜度和投入的成本。

實施要點:

  1. select語句只獲取需要的字段,避免使用select * from語句,有效防止新增字段對應用邏輯的影響,還能減少對性能的影響。
  2. 對數據庫表結構變更通過新增字段實現。
  3. 儘量新增接口,避免對現有接口做修改,如需要修改現有接口,可嘗試在接口上增加版本標識。

使用唯一性標識給鏡像打標籤

當生成容器鏡像時,應當使用唯一性標識來給容器鏡像打標籤,唯一標識可以更好的標記當次生成的鏡像,避免出現多個同名標籤但不同的版本鏡像被使用的情況。例如多次部署都使用了latest標籤的鏡像,可能因爲拉取和緩存策略導致不同節點使用了不同版本的鏡像,從而導致功能上的不一致,在這種情況下,並不能很方便地判斷出某個節點部署的是哪一個版本。

唯一標識最好有一定的含義,不僅可以用來區分產物,還可以獲取到本次構建的關鍵信息。比如git提交哈希等關聯性比較強的標識。雖然時間戳也是一個唯一性比較強的標識,但是關聯性相對較差,如果長度不足,也有一定的機率產生碰撞。可以考慮使用組合型標籤,比如使用時間戳,build號,版本號等根據自己的需求來組合生成唯一標識,這樣的標籤本身就包含了很豐富的信息。

不建議單純使用pipeline的build序號來作爲鏡像的標籤,如果需要更換CI工具或者重建pipeline時,這個序號將會被重置而可能產生重複,除非在構建腳本中加入偏移量。而且不同的CI工具獲取這個序號的方法也有所不同,對於遷移並不友好。雖然它的可追溯性看起來較好,但是單純的Build序號和代碼之間並沒有直接的關聯。

如果不是需要對外公開發布的鏡像,並不建議對同一鏡像打上多個不同標籤。因爲絕大部分的情況下,我們只會選用其中一個標籤在所有的地方使用,多個標籤的實際意義並不會很大。

如果製品庫支持immutable特性,強烈建議開啓這個功能,防止因爲意外情況導致對已上傳的鏡像的覆蓋。

優點:

  1. 可以準確對應的到源代碼具體版本,在溯源時可以對應到特定的提交而不是可能存在的多個提交。
  2. 不需要使用SHA256等額外的信息來區分同一標籤的不同版本。

缺點:

  1. 一些類型的唯一性標識可讀性不是很高,比如git提交哈希。
  2. 一些類型的標識受時間影響,不能使用同一命令獲得一致結果,需要使用其他的方式來傳遞給後續階段,比如時間戳。
  3. 製品庫immutable功能開啓之後,重跑已完成構建鏡像的pipeline會發生上傳鏡像失敗的錯誤,有可能會導致後續任務不能繼續。

實施示例:

#!/usr/bin/env bash

GIT_HASH=$(git rev-parse HEAD)

docker build --rm -t "myapp:${GIT_HASH}" .

在所有環境中使用同一個構建產物

應該在不同環境中使用相同的構建產物來部署,避免對不同的環境生成不同的構建產物,以確保環境的一致性,同時也保證部署在不同環境中的業務代碼是測試和驗證通過的。比如某次的構建產物,在測試環境部署後經由測試人員和相關的自動化測試工具完成相關的測試驗證,如果沒有問題纔會繼續部署到後續環境中,應繼續使用該產物部署後面的環境,不建議重新構建新的產物來做後續環境的部署,也不建議覆蓋之前的構建產物標識。因爲在現有流行的語言和框架中,普遍存在大量的第三方依賴,即便是同一份源代碼,由於其依賴以及構建環境的不同,會有一定機率出現由於外部依賴的更新導致構建產物存在差異,從而產生非預期的情況出現。

優點:

  1. 確保所有的環境部署的構建產物是一樣的,儘可能的保證環境的一致性。
  2. 確保部署到生產環境的產物是測試驗證之後並無變化的,避免出現非預期的差異。

缺點:

  1. 對於如前端這類純靜態資源的應用,由於不同的環境需要連接不同的後端服務地址,因此無法直接使用唯一的構建產物。可以考慮在業務啓動階段,用一些額外的啓動腳本或命令配合傳入環境變量或參數來修改配置文件,從而達到所有環境使用同一個構建產物的目的。

    下面例子展示了在使用nginx的容器鏡像裏,通過在CMD指令裏面先執行一段腳本來對配置進行修改,來達到在容器運行時根據傳入的環境變量WEB_ENV的值來訪問對應環境的後端服務的目的。

    FROM nginx:1.21.3-alpine
    
    COPY dist /app/
    
    CMD sed -i -e "s/VUE_APP_ENV/${WEB_ENV}/g" /app/env-config.js \
    && nginx -g 'daemon off;'
    
  2. 對於移動端app,也存在與前端應用類似的問題,需要開發人員做額外設計和開發,在app啓動時判斷需要進入什麼樣的運行模式。

實施要點:

  1. 在設計CICD流水線時,將構建產物同步到製品庫時,給該產物打上唯一標識。
  2. 如製品庫支持,開啓製品庫的immutable特性。
  3. 將該唯一標識傳遞到在後面所有的部署流水線任務中,所有的部署任務都使用該唯一標識所指向的構建產物。
  4. 如果需要在多個製品庫保存同一個構建產物,建議在上傳成功之後對構建產物做完整性檢查。

減少腳本/工具對環境的依賴

一般情況下,腳本都會或多或少的使用到一些外部工具。而我們的腳本很有可能會運行在不同的環境中,不同環境中提供的工具也會有版本和用法的差異。如果需要在環境中維護某一工具的多個版本的,工具本身的版本管理,以及多個工具之間的依賴衝突和升級更新也會產生較高的管理和維護成本。

我們建議儘可能的減少所使用的工具對環境的依賴,尤其是系統不會默認安裝的工具。另外在編寫腳本的時候,也儘量避免使用只有某些版本特有的語法特性。這些情況都會導致腳本有可能出現一些不可預期的結果。我們建議使用容器化工具或者容器化環境管理工具如Batect來替代對應的需求。

優點:

  1. CI/CD agent中只需要安裝容器運行時即可,可以減小agent的體積。

  2. 容器化的工具因爲對環境的依賴非常低,所以不論是工具升級還是降級都非常簡單,同時也解耦了對agent特性的依賴,提高agent利用率。

  3. 最大化的保證環境一致性,使用容器化的工具消除了環境差異可能導致的非預期異常。

  4. 新人友好,新加入的團隊成員可以快速的配置好可運行的環境,無需過多的考慮具體工具的安裝,配置等。

  5. 解耦對CI/CD工具的依賴,雖然在實際項目中很少會有更換CI/CD工具的情況,但是如果需要遷移,我們也只需在新的工具環境中構建出容器運行環境即可,大大減少了切換工具工作量,提高遷移的速度。

缺點:

  1. 因爲沒有預裝構建所需要的各種軟件,如果本地沒有鏡像緩存,在運行容器化的工具時都需要去容器倉庫中獲取對應的工具鏡像,會有額外的帶寬壓力。

  2. 因爲需要獲取工具鏡像,容器啓動也比二進制的程序要慢,所以整個任務運行過程需要的時間會更長。

  3. 理論上來講,容器化技術性能損耗很小,工具的性能和二進制程序的差別不會很大,但是在實際的使用中,我們發現因爲容器引擎配置不當等原因會導致一些工具性能變差甚至無響應的情況出現。

實施示例:

在使用 terraform 時,不同版本之間的 terraform 並不兼容,那麼如何保證所有人與 CI 都使用相同的 terraform 版本就是一個非常麻煩的事情。那麼如果我們無論在 CI 還是本地都基於 docker 去運行 terraform 就可以解決這個問題。

#!/usr/bin/env bash

function terraform() {
  docker run --rm -it \
      -v $(pwd):/app -w /app \
      hashicorp/terraform:1.1.4 -c "$@"
}

terraform init
terraform plan && terraform apply

使用auto/ACTION模式來維護管理腳本

auto/ACTION是我們在項目實踐中總結並希望可以廣泛推廣的一個經驗總結,在和客戶合作過程中,尤其是有很多團隊的大型項目上,我們從這個模式中受益匪淺。auto/ACTION模式的核心是使用統一語義能表明腳本目的的ACTION來命名管理腳本,如應用的測試(test),驗證(validate),打包(build),發佈(deploy)等相關任務,統一把這些管理腳本歸放在auto目錄下來維護。

因爲類unix系統在運行的時候並不真正使用文件後綴來識別文件的類型,我們建議腳本名字不要加後綴。這個建議是基於管理腳本有可能會在多個地方被使用,而不同的開發和維護人員對於語言的偏好不同,如果在需要使用另外一種語言重寫腳本的時候,使用這個腳本的地方就不需要做更新,消除了因爲文件名變化可能導致的自動化任務的錯誤和中斷。雖然沒有後綴可能會帶來一些不便,比如編輯器的語言類型識別錯誤等,但是相對於它帶來的優點,還是非常值得的。

優點:

  1. 管理代碼和業務代碼放在同一代碼庫,使用版本控制,便於進行更新,回退。

  2. 每個腳本只做一件事,職責單一,同時便於理解和管理。

  3. 可以方便的知道所有可用的腳本。如:

    $ ls -l auto/
    auto/validate
    auto/test
    auto/build
    auto/release
    auto/deploy
    
  4. 如果跨團隊合作,或者團隊成員有輪換的時候,可以更快速的掌握業務管理的上下文。

缺點:

  1. 每個項目都有一套自己的auto腳本,如果有基礎性變化,改動成本較高,可以考慮使用git submodule等模式來管理。
  2. 沒有後綴的文件名會帶來一些管理上的不便。

實施要點:

  1. 腳本滿足既可在本地執行,又能在CI流水線上執行,便於驗證。

  2. 腳本中的變量內容儘可能從環境變量中讀取,避免向腳本中傳入參數,方便運行。

  3. 專屬於CI/CD平臺的腳本不要放在auto根目錄下,建議創建一個對應的子目錄,例如 .buildkite, .github, .travis來做管理。

  4. 可根據團隊的需求適當的擴展腳本的名字使之更容易理解,建議使用-而非_ 來分隔單詞, 如auto/upload-image-to-ecr。

管理腳本和業務腳本分離

我們的應用中一般都會有一些腳本來做一些輔助性的工作。這些腳本通常會和業務代碼放在同一個代碼倉庫,使用版本控制來進行管理。這些腳本大致分爲兩種:管理腳本和業務腳本。

管理腳本是用來做應用打包,部署等管理相關工作工作,這種類型的腳本是無需打包進業務運行所需的產出物中的;業務腳本是輔助業務運行,比如說初始化環境和配置,結束時的清理工作等,這些腳本需要打包到業務運行的產出物中。

我們建議除了一些有特殊要求的腳本外,不要把腳本放在根目錄。並且把這兩種不同類型的腳本存放在不同的目錄中。

優點:

  1. 在封裝鏡像時,業務腳本和業務代碼同等重要,需要封裝在鏡像中。將管理腳本和業務腳本分離可以減少鏡像中的文件數量。
  2. 在軟件開發過程中,針對業務運行和自動化管理關注信息不一樣,將管理腳本和業務腳本分離,讓團隊成員更加清楚腳本的類型和目的。

缺點:

  1. 將管理腳本和業務腳本分離,會增加倉庫的層次結構。

實施要點:

  1. 推薦將管理腳本放置在auto目錄,將業務腳本放置在scripts目錄。
  2. 腳本中的變量採用從環境變量中讀取,避免向腳本中傳入參數,方便運行。
  3. 推薦腳本名稱即表明腳本的作用,不建議使用auto/script這樣不表意的腳本命名。
  4. 不在文件名中使用文件類型後綴。

及時更新容器的基礎鏡像

基礎鏡像是業務鏡像的地基,其包含了我們業務和應用所必需的基礎庫、二進制文件和配置文件等。一個良好維護的基礎鏡像通常會根據需要做更新,這些更新通常包含安全補丁,新功能或對操作系統或框架的改進等,我們建議及時的更新容器的基礎鏡像來保障業務的安全性。除非有特定原因需要繼續使用舊版本鏡像,否則應及時跟進使用經過充分評估和測試的最新版本鏡像。

在Dockerfile和compose等文件中,可以通過指定鏡像中的標識和sha256值組合來指定基礎鏡像的版本。當鏡像有了更新之後,及時沿用瞭如latest或大版本號這類通用性比較高的標籤時,其sha256的值也會發生變化,通過更新這個組合可以更新使用最新版本的基礎鏡像。

優點:

  1. 最新的鏡像通常帶有可以增強應用程序安全性的補丁修復,降低安全風險。
  2. 最新的鏡像通常包括可以提高應用程序性能的新功能或改進功能。

缺點:

  1. 新功能可能存在不可預期的bug。
  2. 新的功能有非常小的概率存在未知的安全漏洞,如果有特殊的安全需求,請在安全部門的指導下升級。

實施示例:

可以使用dfresh或者類似的工具來檢查和更新基礎鏡像。

  • 檢查基礎鏡像是否有更新

    $ dfresh check Dockerfile
    Dockerfile:1: mysql
    old sha256:5e515d337402579571c19a2a34a9b733d26788805429b5b3bdca12b76e7cc208
    new sha256:fbe848f5738001063a89367adb747e7f283f9c87b20e74ccb6db3b13ec6e35cd
    
  • 更新基礎鏡像

    $ dfresh update Dockerfile
    Dockerfile:1: mysql
    old sha256:5e515d337402579571c19a2a34a9b733d26788805429b5b3bdca12b76e7cc208
    new sha256:fbe848f5738001063a89367adb747e7f283f9c87b20e74ccb6db3b13ec6e35cd
    
  • 回退方法 在需要回退基礎鏡像版本時,可從代碼庫的提交找到上一個可用版本的相應信息。

定期檢查和升級依賴包

隨着 Bug 修復、新功能的開發或者其他更新,我們應用的依賴包可能會過時。此時應用的依賴項越多,就越難跟上這些更新。過時的依賴包可能對安全構成威脅,並對性能產生負面影響。最新的軟件包可防止漏洞,這意味着定期的依賴性檢查和更新很重要。我們建議定期的對應用的依賴包做更新和安全檢查,並升級到一個合適的版本。並且我們建議在應用的 pipeline 中加入這些檢查任務,並在常規的開發過程中及時發現和升級。如果應用已經處於維護階段,我們也建議定期執行這些檢查並在需要的時候加以升級。

優點:

  1. 定期升級依賴可以讓應用的安全性和代碼的可用性都有保障。
  2. 定期升級依賴會讓解決依賴版本衝突和代碼兼容性變得容易。
  3. 更新依賴項可以獲得新的依賴項版本提供的所有性能改進。 這些改進可以有多種形式,例如修復以前的性能問題、改進了實現和算法等。
  4. 升級依賴項不僅可以改進現有功能,還可以使用到以前不存在的新功能。這些新功能最終可能讓我們更好的實現自己應用的新功能。

缺點:

  1. 如果不及時更新依賴,將會使得產品難以維護,並可能導致開發人員的時間被常規的、無意義的工作佔用。
  2. 如果長期不更新依賴,會使應用面臨無人問津的風險,之後在某一天需要進行改動的時候,面臨大量的依賴包過期無法獲取和版本升級造成的接口變化。這時就需要投入非常高的成本來讓代碼重新變得可用,甚至完全無法更新而變成遺留系統。
  3. 當進行大的版本升級時,需要對應用程序進行更多的更改才能與較新的庫兼容。這使得付出代價比及時更新依賴大得多。
  4. 如果忽略升級依賴項,那麼會面臨無法在自己喜歡的平臺上運行軟件的可能。 例如,如果停止升級軟件中的數據庫驅動程序,那麼將無法使用舊版本的數據庫系統。這不僅會使應用變得過時且易受攻擊,而且甚至可能無法從該數據庫系統提供商處獲得任何支持。
  5. 如果應用依賴於過時的依賴項而導致升級困難變得很難維護,會使得項目很難找到對這些舊技術有經驗的人,甚至失去現有的維護者。

實施示例:

1. 手動檢查
JS 篇
  • npm-outdated & npm-update

    • npm outdated:可以使用 npm outdated 獲取當前需要升級的包的信息。
    • npm update: 會把所有的包升級到我們定義的需要的版本號。如果需要升級到最新的則需要使用@latest eg: npm update cypress@latest。
  • npm-check-updates: 是一種更高級的檢查工具

    • 首先需要全局安裝 npm-check-updates: npm install -g npm-check-updates ;
    • ncu: 檢查需要升級的包信息,這裏類似 npm outdated;
    • ncu --upgrade/ncu -u: 將所有的包升級到最新版本,即便是包含重大更改,也會進行更新。注意:更新完成後不會自動運行 npm install,所以還需要再手動執行來更新 package-lock.json。
    • ncu --interactive/ncu -i : interactive mode 安裝某個包。
  • 小結:npm-outdated 和 npm-check-updates都可以用來做 JS項目的包檢查、升級。

Java 篇
  • 在 build.gradle中配置 owasp.dependency-check
  • 執行./gradlew dependencyCheckAnalyze
  • 查看報告: 項目根目錄>build>reports>dependency-check-report.html
2. CI Pipeline 集成
  • npm-check-updates 與 Buildkite Pipeline 的集成

    由於 buildkite 沒有官方插件支持 dependency-check。所以對於buildkite 推薦兩種方式:

    • 自己開發對應功能的插件,然後集成到 pipeline 的 step 中;
    • 通過 docker-compose 的方式去運行對應的檢查,將其在 pipeline 的 step 中去運行(如果需要可以添加 block 來強制檢查 npm-check-updates 的結果)。
## Dockerfile
FROM node:18.7.0
WORKDIR app
COPY ["package.json", "package-lock.json*", "./"]
RUN npm install -g npm-check-updates
## docker-compose
version: "2"
services:
node-version-check:
  build: .
  command: sh -c "ncu"
## auto/dependency-check.sh
#!/usr/bin/env bash
set -ex
docker-compose run --rm node-version-check
## buildkite script
steps
 - label: 'node version dependency-check'
   command: auto/dependency-check.sh
   agents:
     queue: 'xxxx'
 - block: 'Please check node-version-check'
  • jenkins pipeline 的集成:需要安裝 dependency-check Plugin。步驟如下:

    • 在 Jenkins Global Tool Configuration 安裝 dependency-check;
    • 在 Jenkins builder 配置已經安裝好的 dependency-check;
    • 在 Jenkins Publish 裏配置讀取 dependency-check 的 report ,通過對相關指標進行讀取,設置閾值,配置構建失敗或者警告等設置。
3. 工具集成檢查

如果項目 code 託管在 Github,我們可以使用 Dependabot 和 Renovate 工具和 Github 集成來做依賴檢查。這兩個工具都會做定期掃描,創建依賴版本升級的 PR。

配置 Dependabot 進行版本更新
  • 在 GitHub 的代碼倉庫的主頁,找到代碼倉庫名稱下的 setting;
  • 在邊欄的安全性部分中,單擊代碼安全性和分析;
  • 在代碼安全和分析下,在Dependabot version updates右側,單擊啓用以打開存儲庫 .github 目錄中的基本 dependabot.yml 配置文件;
  • 添加version;
  • 添加 updates 部分,並輸入希望 Dependabot 監視的每個包管理器的條目;
  • 對於每個包管理器,可使用:
    • package-ecosystem 指定包管理器。
    • directory 指定清單或其他定義文件的位置。
    • schedule.interval 指定檢查新版本的頻率。
  • 在代碼倉庫的根目錄創建.github目錄;
  • 創建 dependabot.yml文件並且存儲到.github目錄下。

示例 dependabot.yml

version: 2
updates:
  # Enable version updates for npm
  - package-ecosystem: "npm"
    # Look for 
配置 Renovate
  • 在 Github 的 App 裏面安裝 Renovate app https://github.com/apps/renovate;
  • 安裝並配置完成後可以在PR中看到一個自動生成的PR Configure Renovate,這個PR中包含一個 renovate.json 文件,這個文件中包含了 renovate 的一些默認設定;
  • 可以根據文檔 (https://docs.renovatebot.com/configuration-options/) 添加或者修改適合自身項目的具體配置項;
  • merge 此 PR;
  • Renovate 會根據你配置的 schedule 時間去自動的掃描並生成包升級 PR 提醒

定期的重新部署維護階段的應用

在應用處於維護階段,如果業務不再會增加新的功能,抑或因爲某些原因無法做定期的應用依賴升級,我們也建議你定期的重新部署這個應用,以應對平臺等更底層的變化帶來的部署失敗的風險。定期部署可以確保你的應用在新的平臺環境中也可以正常的部署,如果在週期性的部署過程中發現應用無法在新的環境部署,你也會有一個緩衝期來制訂應對策略,而不是在平臺完成升級之後的某一天,應用發生了問題才發現已經無法部署。

優點:

  1. 定期部署應用是對部署工具和流程的有效驗證,CI/CD Agent的一些升級有可能會導致我們在部署流程中使用工具發生兼容性問題,定期部署可以及早的發現這些問題。

  2. 定期部署應用也能夠有效縮短我們的依賴獲取未驗證的窗口期。雖然我們的應用依賴可以鎖定版本,也可以將依賴保存到私有倉庫,但長時間沒有運行相關部署流程,我們無法保證應用的依賴能夠在需要的時候可正常獲取且可用。

  3. 現在的應用的基礎設施很多都基於各類雲平臺,服務提供商會定期的對自己的基礎設施做升級和換代,定期部署應用可以讓我們及早的獲知基礎設施變化帶來的兼容性風險。

缺點:

  1. 定期部署會對系統的穩定運行造成一些影響,變化本身就會帶來一定的未知風險。

  2. 自動化的發佈一般情況下都需要配有完善的迴歸測試流程來確保業務的可用性,會帶來成本的增加

感謝

藍皮書在編撰的過程中,有很多熱心的小夥伴加入貢獻了自己的力量和知識,在這裏非常感謝他們。

常卉、馮煒、甘霖靜、高語越、何水平、何蔚、毛靈、毛遠鑫、錢文濤、喬偉星、石昆、孫瑞、許樂、楊偉健、趙浩、趙佩、周瑞豐、朱翔


文/Thoughtworks 朱燁
原文鏈接:DevOps最佳實踐之應用開發和部署

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章