Jenkins 在 Kubernetes 上的實踐,你會了嗎?
本文轉載自微信公眾號「問其」,作者陳少文。轉載本文請聯系問其公眾號。
1. 配置較大的 -Xms -Xmx 參數
Jenkins 是由 Java 編寫的編排引擎,在 Full GC 時會 Stop The World(STW)。在大規模構建時,STW 可能會導致 Jenkins 無法處理新的請求。
為了避免頻繁的 STW,同時增大并發量,建議設置較大的堆,-Xms3g -Xmx6g -XX:MaxRAM=6g。具體數值可以根據監控值來設置,Java Full GC 之后,內存占用會陡降。
2. request 不要設置太小
request 設置太小,可能會導致 Jenkins 運行起來之后,節點資源不足,引發驅逐,甚至壓垮節點。
request 應該接近真實值,如果有足夠的機器資源,應該配置親和性,讓 Jenkins 盡可能運行在單獨的機器上。request >= 1.25 * JVM 最大堆內存,limit >= 2 * JVM 最大堆內存。
3. IO 性能不能差
Jenkins 使用磁盤文件存儲數據,每條流水線、每次構建都會占用一個文件目錄,產生大量文件。通常流水線數量有限,但在構建歷史達到 10000+ 級別時,會感受到 IO 對 Jenkins 的影響。
如果使用本地存儲,推薦使用高性能的 SSD。如果是使用網絡存儲,需要高性能的網絡支持,同時加大客戶端的緩存池。
4. 較大的 jenkins_home 的磁盤空間
磁盤滿時,Jenkins 將不能工作,在 Jenkins 后臺會有錯誤提示。
建議對 Jenkins 的工作目錄進行磁盤使用率監控,并配置告警規則。如果沒有監控告警系統,那么建議直接設置一個較大的磁盤空間給 /var/jenkins_home 目錄。因為有一些 Storage Class 不支持動態擴容,當磁盤滿時,就只能手動拷貝了。
5. 使用 Kubernetes plugin 在 Kuberntes 上構建
基于物理機、虛擬機的構建,增加了運維成本、限制了并發的數量。
使用 Kubernetes plugin 插件在 Kubernetes 上進行構建能充分利用云原生易擴展、易維護的優勢,進行大規模的構建。參考: 在 Kubernetes 上動態創建 Jenkins Slave,https://www.chenshaowen.com/blog/creating-jenkins-slave-dynamically-on-kubernetes.html) 。由于構建比較占用資源,為了避免對集群的影響,可以配置親和性,將構建 Pod 集中到指定的節點執行。
6. 使用 CasC 管理 Jenkins 的配置
通過 Jenkins 頁面進行各種構建、安全等配置,不僅繁瑣、不易維護,而且不能夠復用。
使用 CasC 插件,允許用戶將 Jenkins 的配置,通過文本的形式進行描述,還可以放置到 Git 倉庫中進行版本管理。
- jenkins:
- securityRealm:
- ldap:
- configurations:
- - groupMembershipStrategy:
- fromUserRecord:
- attributeName: "memberOf"
- inhibitInferRootDN: false
- rootDN: "dc=acme,dc=org"
- server: "ldaps://ldap.acme.org:1636"
- nodes:
- - permanent:
- name: "static-agent"
- remoteFS: "/home/jenkins"
- launcher:
- jnlp:
- workDirSettings:
- disabled: true
- failIfWorkDirIsMissing: false
- internalDir: "remoting"
- workDirPath: "/tmp"
- slaveAgentPort: 50000
- agentProtocols:
- - "jnlp2"
7. 使用 Custom WAR Packager 打包 Jenkins
在部署一套新的 Jenkins 環境時,會需要安裝大量插件,非常影響部署速度,同時插件是否能正常下載也存在不確定性。
Custom WAR Packager 允許用戶將 Jenkins 、配置、插件打包成一個完整的 war 包或者鏡像。這樣無論是開發測試,還是線上部署,都可以很方便的部署,并且環境一致,而用戶只需要寫一個 yaml 文件。
- bundle:
- groupId: com.dev
- artifactId: "jenkins"
- description: "Jenkins Custom With Package"
- vendor: "Jenkins Project"
- buildSettings:
- docker:
- base: jenkins/jenkins:2.277.4
- tag: shaowenchen/jenkins:2.277.4
- build: true
- war:
- groupId: org.jenkins-ci.main
- artifactId: jenkins-war
- source:
- version: 2.277.4
- plugins:
- - groupId: io.jenkins
- artifactId: configuration-as-code
- source:
- version: "1.47"
- libPatches:
- - groupId: "org.jenkins-ci.main"
- artifactId: "remoting"
- source:
- git: https://github.com/jenkinsci/remoting.git
- systemProperties: {
- jenkins.model.Jenkins.slaveAgentPort: "50000",
- jenkins.model.Jenkins.slaveAgentPortEnforce: "true"}
- groovyHooks:
- - type: "init"
- id: "initScripts"
- source:
- dir: scripts
- casc:
- - id: "jcasc-config"
- source:
- dir: jenkins.yml
8. Jenkins Shared Libraries
在使用 Groovy 編寫 Pipeline 的過程中,經常會有大量重復代碼。
Jenkins 共享庫提供函數級別的共享,可以在不同流水線之間復用同一套函數邏輯,對于平臺建設、大規模使用場景適用。不僅能加快 Pipeline 編寫,還方便維護、平滑升級。
- @Library('utils') import org.foo.Utilities
- def utils = new Utilities(this)
- node {
- utils.mvn 'clean package'
- }
9. 參考
- https://www.jenkins.io/zh/doc/book/pipeline/shared-libraries/
- https://github.com/jenkinsci/configuration-as-code-plugin
- https://github.com/jenkinsci/custom-war-packager
- https://zhuanlan.zhihu.com/p/370241822