完全指南:在容器中運行 Jenkins 構建
現今,由於 Docker 和 Kubernetes(K8S)提供了可擴展、可管理的應用平台,將應用運行在容器中的實踐已經被企業廣泛接受。近些年勢頭很猛的微服務架構也很適合用容器實現。
容器應用平台可以動態啟動指定資源配額、互相隔離的容器,這是其最主要的優勢之一。讓我們看看這會對我們運行 持續集成/持續部署 (CI/CD)任務的方式產生怎樣的改變。
構建並打包應用需要一定的環境,要求能夠下載源代碼、使用相關依賴及已經安裝構建工具。作為構建的一部分,運行單元及組件測試可能會用到本地埠或需要運行第三方應用(如資料庫及消息中間件等)。另外,我們一般定製化多台構建伺服器,每台執行一種指定類型的構建任務。為方便測試,我們維護一些實例專門用於運行第三方應用(或者試圖在構建伺服器上啟動這些第三方應用),避免並行運行構建任務導致結果互相干擾。為 CI/CD 環境定製化構建伺服器是一項繁瑣的工作,而且隨著開發團隊使用的開發平台或其版本變更,會需要大量的構建伺服器用於不同的任務。
一旦我們有了容器管理平台(自建或在雲端),將資源密集型的 CI/CD 任務在動態生成的容器中執行是比較合理的。在這種方案中,每個構建任務運行在獨立啟動並配置的構建環境中。構建過程中,構建任務的測試環節可以任意使用隔離環境中的可用資源;此外,我們也可以在輔助容器中啟動一個第三方應用,只在構建任務生命周期中為測試提供服務。
聽上去不錯,讓我們在現實環境中實踐一下。
註:本文基於現實中已有的解決方案,即一個在 Red Hat OpenShift v3.7 集群上運行的項目。OpenShift 是企業級的 Kubernetes 版本,故這些實踐也適用於 K8S 集群。如果願意嘗試,可以下載 Red Hat CDK,運行 jenkins-ephemeral
或 jenkins-persistent
模板在 OpenShift 上創建定製化好的 Jenkins 管理節點。
解決方案概述
在 OpenShift 容器中執行 CI/CD 任務(構建和測試等) 的方案基於分散式 Jenkins 構建,具體如下:
- 我們需要一個 Jenkins 主節點;可以運行在集群中,也可以是外部提供
- 支持 Jenkins 特性和插件,以便已有項目仍可使用
- 可以用 Jenkins GUI 配置、運行任務或查看任務輸出
- 如果你願意編碼,也可以使用 Jenkins Pipeline
從技術角度來看,運行任務的動態容器是 Jenkins 代理節點。當構建啟動時,首先是一個新節點啟動,通過 Jenkins 主節點的 JNLP(5000 埠) 告知就緒狀態。在代理節點啟動並提取構建任務之前,構建任務處於排隊狀態。就像通常 Jenkins 代理伺服器那樣,構建輸出會送達主節點;不同的是,構建完成後代理節點容器會自動關閉。
不同類型的構建任務(例如 Java、 NodeJS、 Python等)對應不同的代理節點。這並不新奇,之前也是使用標籤來限制哪些代理節點可以運行指定的構建任務。啟動用於構建任務的 Jenkins 代理節點容器需要配置參數,具體如下:
- 用於啟動容器的 Docker 鏡像
- 資源限制
- 環境變數
- 掛載的卷
這裡用到的關鍵組件是 Jenkins Kubernetes 插件。該插件(通過使用一個服務賬號) 與 K8S 集群交互,可以啟動和關閉代理節點。在插件的配置管理中,多種代理節點類型表現為多種 Kubernetes pod 模板,它們通過項目標籤對應。
這些代理節點鏡像以開箱即用的方式提供(也有 CentOS7 系統的版本):
- jenkins-slave-base-rhel7:基礎鏡像,啟動與 Jenkins 主節點連接的代理節點;其中 Java 堆大小根據容器內容設置
- jenkins-slave-maven-rhel7:用於 Maven 和 Gradle 構建的鏡像(從基礎鏡像擴展)
- jenkins-slave-nodejs-rhel7:包含 NodeJS4 工具的鏡像(從基礎鏡像擴展)
注意:本解決方案與 OpenShift 中的 Source-to-Image(S2I) 構建無關,雖然後者也可以用於某些特定的 CI/CD 任務。
入門學習資料
有很多不錯的博客和文檔介紹了如何在 OpenShift 上執行 Jenkins 構建。不妨從下面這些開始:
- OpenShift Jenkins 鏡像文檔及 源代碼
- 網路播客:基於 OpenShift 的 CI/CD
- 外部 Jenkins 集成 劇本
閱讀這些博客和文檔有助於完整的理解本解決方案。在本文中,我們主要關注具體實踐中遇到的各類問題。
構建我的應用
作為示例項目,我們選取了包含如下構建步驟的 Java 項目:
- 代碼源: 從一個 Git 代碼庫中獲取項目代碼
- 使用 Maven 編譯: 依賴可從內部倉庫獲取,(不妨使用 Apache Nexus) 鏡像自外部 Maven 倉庫
- 發布成品: 將編譯好的 JAR 上傳至內部倉庫
在 CI/CD 過程中,我們需要與 Git 和 Nexus 交互,故 Jenkins 任務需要能夠訪問這些系統。這要求參數配置和已存儲憑證可以在下列位置進行管理:
- 在 Jenkins 中: 我們可以在 Jenkins 中添加憑證,通過 Git 插件能夠對項目添加和使用文件(使用容器不會改變操作)
- 在 OpenShift 中: 使用 ConfigMap 和 Secret 對象,以文件或環境變數的形式附加到 Jenkins 代理容器中
- 在高度定製化的 Docker 容器中: 鏡像是定製化的,已包含完成特定類型構建的全部特性;從一個代理鏡像進行擴展即可得到。
你可以按自己的喜好選擇一種實現方式,甚至你最終可能混用多種實現方式。下面我們採用第二種實現方式,即首選在 OpenShift 中管理參數配置。使用 Kubernetes 插件配置來定製化 Maven 代理容器,包括設置環境變數和映射文件等。
注意:對於 Kubernetes 插件 v1.0 版,由於 bug,在 UI 界面增加環境變數並不生效。可以升級插件,或(作為變通方案) 直接修改 config.xml
文件並重啟 Jenkins。
從 Git 獲取源代碼
從公共 Git 倉庫獲取源代碼很容易。但對於私有 Git 倉庫,不僅需要認證操作,客戶端還需要信任伺服器以便建立安全連接。一般而言,通過兩種協議獲取源代碼:
- HTTPS:驗證通過用戶名/密碼完成。Git 伺服器的 SSL 證書必須被代理節點信任,這僅在證書被自建 CA 簽名時才需要特別注意。
git clone https://git.mycompany.com:443/myapplication.git
- SSH:驗證通過私鑰完成。如果伺服器的公鑰指紋出現在
known_hosts
文件中,那麼該伺服器是被信任的。
git clone ssh://git@git.mycompany.com:22/myapplication.git
對於手動操作,使用用戶名/密碼通過 HTTP 方式下載源代碼是可行的;但對於自動構建而言,SSH 是更佳的選擇。
通過 SSH 方式使用 Git
要通過 SSH 方式下載源代碼,我們需要保證代理容器與 Git 的 SSH 埠之間可以建立 SSH 連接。首先,我們需要創建一個私鑰-公鑰對。使用如下命令生成:
ssh keygen -t rsa -b 2048 -f my-git-ssh -N ''
命令生成的私鑰位於 my-git-ssh
文件中(口令為空),對應的公鑰位於 my-git-ssh.pub
文件中。將公鑰添加至 Git 伺服器的對應用戶下(推薦使用「服務賬號」);網頁界面一般支持公鑰上傳。為建立 SSH 連接,我們還需要在代理容器上配置兩個文件:
- 私鑰文件位於
~/.ssh/id_rsa
- 伺服器的公鑰位於
~/.ssh/known_hosts
。要實現這一點,運行ssh git.mycompany.com
並接受伺服器指紋,系統會在~/.ssh/known_hosts
文件中增加一行。這樣需求得到了滿足。
將 id_rsa
對應的私鑰和 known_hosts
對應的公鑰保存到一個 OpenShift 的 secret(或 ConfigMap) 對象中。
apiVersion: v1
kind: Secret
metadata:
name: mygit-ssh
stringData:
id_rsa: |-
-----BEGIN RSA PRIVATE KEY-- ...
-----END RSA PRIVATE KEY-- known_hosts: |-
git.mycompany.com ecdsa-sha2-nistp256 AAA...
在 Kubernetes 插件中將 secret 對象配置為卷,掛載到 /home/jenkins/.ssh/
,供 Maven pod 使用。secret 中的每個對象對應掛載目錄的一個文件,文件名與 key 名稱相符。我們可以使用 UI(管理 Jenkins / 配置 / 雲 / Kubernetes),也可以直接編輯 Jenkins 配置文件 /var/lib/jenkins/config.xml
:
<org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
<name>maven</name>
...
<volumes>
<org.csanchez.jenkins.plugins.kubernetes.volumes.SecretVolume>
<mountPath>/home/jenkins/.ssh</mountPath>
<secretName>mygit-ssh</secretName>
</org.csanchez.jenkins.plugins.kubernetes.volumes.SecretVolume>
</volumes>
此時,在代理節點上運行的任務應該可以通過 SSH 方式從 Git 代碼庫獲取源代碼。
註:我們也可以在 ~/.ssh/config
文件中自定義 SSH 連接。例如,如果你不想處理 known_hosts
或私鑰位於其它掛載目錄中:
Host git.mycompany.com
StrictHostKeyChecking no
IdentityFile /home/jenkins/.config/git-secret/ssh-privatekey
通過 HTTP 方式使用 Git
如果你選擇使用 HTTP 方式下載,在指定的 Git-credential-store 文件中添加用戶名/密碼:
- 例如,在一個 OpenShift secret 對象中增加
/home/jenkins/.config/git-secret/credentials
文件對應,其中每個站點對應文件中的一行:
https://username:password@git.mycompany.com
https://user:pass@github.com
- 在 git-config 配置中啟用該文件,其中配置文件默認路徑為
/home/jenkins/.config/git/config
:
[credential]
helper = store --file=/home/jenkins/.config/git-secret/credentials
如果 Git 服務使用了自有 CA 簽名的證書,為代理容器設置環境變數 GIT_SSL_NO_VERIFY=true
是最便捷的方式。更恰當的解決方案包括如下兩步:
- 利用 ConfigMap 將自有 CA 的公鑰映射到一個路徑下的文件中,例如
/usr/ca/myTrustedCA.pem
)。 - 通過環境變數
GIT_SSL_CAINFO=/usr/ca/myTrustedCA.pem
或上面提到的git-config
文件的方式,將證書路徑告知 Git。
[http "https://git.mycompany.com"]
sslCAInfo = /usr/ca/myTrustedCA.pem
註:在 OpenShift v3.7 及早期版本中,ConfigMap 及 secret 的掛載點之間不能相互覆蓋,故我們不能同時映射 /home/jenkins
和 /home/jenkins/dir
。因此,上面的代碼中並沒有使用常見的文件路徑。預計 OpenShift v3.9 版本會修復這個問題。
Maven
要完成 Maven 構建,一般需要完成如下兩步:
- 建立一個社區 Maven 庫(例如 Apache Nexus),充當外部庫的代理。將其當作鏡像使用。
- 這個內部庫可能提供 HTTPS 服務,其中使用自建 CA 簽名的證書。
對於容器中運行構建的實踐而言,使用內部 Maven 庫是非常關鍵的,因為容器啟動後並沒有本地庫或緩存,這導致每次構建時 Maven 都下載全部的 Jar 文件。在本地網路使用內部代理庫下載明顯快於從網際網路下載。
Maven Jenkins 代理鏡像允許配置環境變數,指定代理的 URL。在 Kubernetes 插件的容器模板中設置如下:
MAVEN_MIRROR_URL=https://nexus.mycompany.com/repository/maven-public
構建好的成品(JAR) 也應該保存到庫中,可以是上面提到的用於提供依賴的鏡像庫,也可以是其它庫。Maven 完成 deploy
操作需要在 pom.xml
的分發管理 下配置庫 URL,這與代理鏡像無關。
<project ...>
<distributionManagement>
<snapshotRepository>
<id>mynexus</id>
<url>https://nexus.mycompany.com/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>mynexus</id>
<url>https://nexus.mycompany.com/repository/maven-releases/</url>
</repository>
</distributionManagement>
上傳成品可能涉及認證。在這種情況下,在 settings.xml
中配置的用戶名/密碼要與 pom.xml
文件中的對應的伺服器 id
下的設置匹配。我們可以使用 OpenShift secret 將包含 URL、用戶名和密碼的完整 settings.xml
映射到 Maven Jenkins 代理容器中。另外,也可以使用環境變數。具體如下:
- 利用 secret 為容器添加環境變數:
MAVEN_SERVER_USERNAME=admin
MAVEN_SERVER_PASSWORD=admin123
- 利用 config map 將
settings.xml
掛載至/home/jenkins/.m2/settings.xml
:
<settings ...>
<mirrors>
<mirror>
<mirrorOf>external:*</mirrorOf>
<url>${env.MAVEN_MIRROR_URL}</url>
<id>mirror</id>
</mirror>
</mirrors>
<servers>
<server>
<id>mynexus</id>
<username>${env.MAVEN_SERVER_USERNAME}</username>
<password>${env.MAVEN_SERVER_PASSWORD}</password>
</server>
</servers>
</settings>
禁用交互模式(即,使用批處理模式) 可以忽略下載日誌,一種方式是在 Maven 命令中增加 -B
參數,另一種方式是在 settings.xml
配置文件中增加 <interactiveMode>false</interactiveMode>
配置。
如果 Maven 庫的 HTTPS 服務使用自建 CA 簽名的證書,我們需要使用 keytool 工具創建一個將 CA 公鑰添加至信任列表的 Java KeyStore。在 OpenShift 中使用 ConfigMap 將這個 Keystore 上傳。使用 oc
命令基於文件創建一個 ConfigMap:
oc create configmap maven-settings --from-file=settings.xml=settings.xml --from-
file=myTruststore.jks=myTruststore.jks
將這個 ConfigMap 掛載至 Jenkins 代理容器。在本例中我們使用 /home/jenkins/.m2
目錄,但這僅僅是因為配置文件 settings.xml
也對應這個 ConfigMap。KeyStore 可以放置在任意路徑下。
接著在容器環境變數 MAVEN_OPTS
中設置 Java 參數,以便讓 Maven 對應的 Java 進程使用該文件:
MAVEN_OPTS=
-Djavax.net.ssl.trustStore=/home/jenkins/.m2/myTruststore.jks
-Djavax.net.ssl.trustStorePassword=changeit
內存使用量
這可能是最重要的一部分設置,如果沒有正確的設置最大內存,我們會遇到間歇性構建失敗,雖然每個組件都似乎工作正常。
如果沒有在 Java 命令行中設置堆大小,在容器中運行 Java 可能導致高內存使用量的報錯。JVM 可以利用全部的宿主機內存,而不是使用容器內存現在並相應設置默認的堆大小。這通常會超過容器的內存資源總額,故當 Java 進程為堆分配過多內存時,OpenShift 會直接殺掉容器。
雖然 jenkins-slave-base
鏡像包含一個內建腳本設置堆最大為容器內存的一半(可以通過環境變數 CONTAINER_HEAP_PERCENT=0.50
修改),但這隻適用於 Jenkins 代理節點中的 Java 進程。在 Maven 構建中,還有其它重要的 Java 進程運行:
mvn
命令本身就是一個 Java 工具。- Maven Surefire 插件 默認派生一個 JVM 用於運行單元測試。
總結一下,容器中同時運行著三個重要的 Java 進程,預估內存使用量以避免 pod 被誤殺是很重要的。每個進程都有不同的方式設置 JVM 參數:
- 我們在上面提到了 Jenkins 代理容器堆最大值的計算方法,但我們顯然不應該讓代理容器使用如此大的堆,畢竟還有兩個 JVM 需要使用內存。對於 Jenkins 代理容器,可以設置
JAVA_OPTS
。 mvn
工具被 Jenkins 任務調用。設置MAVEN_OPTS
可以用於自定義這類 Java 進程。- Maven
surefire
插件滋生的用於單元測試的 JVM 可以通過 Maven argLine 屬性自定義。可以在pom.xml
或settings.xml
的某個配置文件中設置,也可以直接在maven
命令參數MAVEN_OPS
中增加-DargLine=…
。
下面例子給出 Maven 代理容器環境變數設置方法:
JAVA_OPTS=-Xms64m -Xmx64m
MAVEN_OPTS=-Xms128m -Xmx128m -DargLine=${env.SUREFIRE_OPTS}
SUREFIRE_OPTS=-Xms256m -Xmx256m
我們的測試環境是具有 1024Mi 內存限額的代理容器,使用上述參數可以正常構建一個 SpringBoot 應用並進行單元測試。測試環境使用的資源相對較小,對於複雜的 Maven 項目和對應的單元測試,我們需要更大的堆大小及更大的容器內存限額。
註:Java8 進程的實際內存使用量包括「堆大小 + 元數據 + 堆外內存」,因此內存使用量會明顯高於設置的最大堆大小。在我們上面的測試環境中,三個 Java 進程使用了超過 900Mi 的內存。可以在容器內查看進程的 RSS 內存使用情況,命令如下:ps -e -o pid,user,rss,comm,args
。
Jenkins 代理鏡像同時安裝了 JDK 64 位和 32 位版本。對於 mvn
和 surefire
,默認使用 64 位版本 JVM。為減低內存使用量,只要 -Xmx
不超過 1.5 GB,強制使用 32 位 JVM 都是有意義的。
JAVA_HOME=/usr/lib/jvm/Java-1.8.0-openjdk-1.8.0.161–0.b14.el7_4.i386
注意到我們可以在 JAVA_TOOL_OPTIONS
環境變數中設置 Java 參數,每個 JVM 啟動時都會讀取該參數。JAVA_OPTS
和 MAVEN_OPTS
中的參數會覆蓋 JAVA_TOOL_OPTIONS
中的對應值,故我們可以不使用 argLine
,實現對 Java 進程同樣的堆配置:
JAVA_OPTS=-Xms64m -Xmx64m
MAVEN_OPTS=-Xms128m -Xmx128m
JAVA_TOOL_OPTIONS=-Xms256m -Xmx256m
但缺點是每個 JVM 的日誌中都會顯示 Picked up JAVA_TOOL_OPTIONS:
,這可能讓人感到迷惑。
Jenkins 流水線
完成上述配置,我們應該已經可以完成一次成功的構建。我們可以獲取源代碼,下載依賴,運行單元測試並將成品上傳到我們的庫中。我們可以通過創建一個 Jenkins 流水線項目來完成上述操作。
pipeline {
/* Which container to bring up for the build. Pick one of the templates configured in Kubernetes plugin. */
agent {
label 'maven'
}
stages {
stage('Pull Source') {
steps {
git url: 'ssh://git@git.mycompany.com:22/myapplication.git', branch: 'master'
}
}
stage('Unit Tests') {
steps {
sh 'mvn test'
}
}
stage('Deploy to Nexus') {
steps {
sh 'mvn deploy -DskipTests'
}
}
}
}
當然,對應真實項目,CI/CD 流水線不僅僅完成 Maven 構建,還可以部署到開發環境,運行集成測試,提升至更接近於生產的環境等。上面給出的學習資料中有執行這些操作的案例。
多容器
一個 pod 可以運行多個容器,每個容器有單獨的資源限制。這些容器共享網路介面,故我們可以從 localhost
訪問已啟動的服務,但我們需要考慮埠衝突的問題。在一個 Kubernetes pod 模板中,每個容器的環境變數是單獨設置的,但掛載的卷是統一的。
當一個外部服務需要單元測試且嵌入式方案無法工作(例如,資料庫、消息中間件等) 時,可以啟動多個容器。在這種情況下,第二個容器會隨著 Jenkins 代理容器啟停。
查看 Jenkins config.xml
片段,其中我們啟動了一個輔助的 httpbin
服務用於 Maven 構建:
<org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
<name>maven</name>
<volumes>
...
</volumes>
<containers>
<org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
<name>jnlp</name>
<image>registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7:v3.7</image>
<resourceLimitCpu>500m</resourceLimitCpu>
<resourceLimitMemory>1024Mi</resourceLimitMemory>
<envVars>
...
</envVars>
...
</org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
<org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
<name>httpbin</name>
<image>citizenstig/httpbin</image>
<resourceLimitCpu></resourceLimitCpu>
<resourceLimitMemory>256Mi</resourceLimitMemory>
<envVars/>
...
</org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
</containers>
<envVars/>
</org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
總結
作為總結,我們查看上面已描述配置的 Jenkins config.xml
對應創建的 OpenShift 資源以及 Kubernetes 插件的配置。
apiVersion: v1
kind: List
metadata: {}
items:
- apiVersion: v1
kind: ConfigMap
metadata:
name: git-config
data:
config: |
[credential]
helper = store --file=/home/jenkins/.config/git-secret/credentials
[http "http://git.mycompany.com"]
sslCAInfo = /home/jenkins/.config/git/myTrustedCA.pem
myTrustedCA.pem: |-
-----BEGIN CERTIFICATE-- MIIDVzCCAj+gAwIBAgIJAN0sC...
-----END CERTIFICATE--- apiVersion: v1
kind: Secret
metadata:
name: git-secret
stringData:
ssh-privatekey: |-
-----BEGIN RSA PRIVATE KEY-- ...
-----END RSA PRIVATE KEY-- credentials: |-
https://username:password@git.mycompany.com
https://user:pass@github.com
- apiVersion: v1
kind: ConfigMap
metadata:
name: git-ssh
data:
config: |-
Host git.mycompany.com
StrictHostKeyChecking yes
IdentityFile /home/jenkins/.config/git-secret/ssh-privatekey
known_hosts: '[git.mycompany.com]:22 ecdsa-sha2-nistp256 AAAdn7...'
- apiVersion: v1
kind: Secret
metadata:
name: maven-secret
stringData:
username: admin
password: admin123
基於文件創建另一個 ConfigMap:
oc create configmap maven-settings --from-file=settings.xml=settings.xml
--from-file=myTruststore.jks=myTruststore.jks
Kubernetes 插件配置如下:
<?xml version='1.0' encoding='UTF-8'?>
<hudson>
...
<clouds>
<org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud plugin="kubernetes@1.0">
<name>openshift</name>
<defaultsProviderTemplate></defaultsProviderTemplate>
<templates>
<org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
<inheritFrom></inheritFrom>
<name>maven</name>
<namespace></namespace>
<privileged>false</privileged>
<alwaysPullImage>false</alwaysPullImage>
<instanceCap>2147483647</instanceCap>
<slaveConnectTimeout>100</slaveConnectTimeout>
<idleMinutes>0</idleMinutes>
<label>maven</label>
<serviceAccount>jenkins37</serviceAccount>
<nodeSelector></nodeSelector>
<nodeUsageMode>NORMAL</nodeUsageMode>
<customWorkspaceVolumeEnabled>false</customWorkspaceVolumeEnabled>
<workspaceVolume class="org.csanchez.jenkins.plugins.kubernetes.volumes.workspace.EmptyDirWorkspaceVolume">
<memory>false</memory>
</workspaceVolume>
<volumes>
<org.csanchez.jenkins.plugins.kubernetes.volumes.SecretVolume>
<mountPath>/home/jenkins/.config/git-secret</mountPath>
<secretName>git-secret</secretName>
</org.csanchez.jenkins.plugins.kubernetes.volumes.SecretVolume>
<org.csanchez.jenkins.plugins.kubernetes.volumes.ConfigMapVolume>
<mountPath>/home/jenkins/.ssh</mountPath>
<configMapName>git-ssh</configMapName>
</org.csanchez.jenkins.plugins.kubernetes.volumes.ConfigMapVolume>
<org.csanchez.jenkins.plugins.kubernetes.volumes.ConfigMapVolume>
<mountPath>/home/jenkins/.config/git</mountPath>
<configMapName>git-config</configMapName>
</org.csanchez.jenkins.plugins.kubernetes.volumes.ConfigMapVolume>
<org.csanchez.jenkins.plugins.kubernetes.volumes.ConfigMapVolume>
<mountPath>/home/jenkins/.m2</mountPath>
<configMapName>maven-settings</configMapName>
</org.csanchez.jenkins.plugins.kubernetes.volumes.ConfigMapVolume>
</volumes>
<containers>
<org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
<name>jnlp</name>
<image>registry.access.redhat.com/openshift3/jenkins-slave-maven-rhel7:v3.7</image>
<privileged>false</privileged>
<alwaysPullImage>false</alwaysPullImage>
<workingDir>/tmp</workingDir>
<command></command>
<args>${computer.jnlpmac} ${computer.name}</args>
<ttyEnabled>false</ttyEnabled>
<resourceRequestCpu>500m</resourceRequestCpu>
<resourceRequestMemory>1024Mi</resourceRequestMemory>
<resourceLimitCpu>500m</resourceLimitCpu>
<resourceLimitMemory>1024Mi</resourceLimitMemory>
<envVars>
<org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<key>JAVA_HOME</key>
<value>/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.161-0.b14.el7_4.i386</value>
</org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<key>JAVA_OPTS</key>
<value>-Xms64m -Xmx64m</value>
</org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<key>MAVEN_OPTS</key>
<value>-Xms128m -Xmx128m -DargLine=${env.SUREFIRE_OPTS} -Djavax.net.ssl.trustStore=/home/jenkins/.m2/myTruststore.jks -Djavax.net.ssl.trustStorePassword=changeit</value>
</org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<key>SUREFIRE_OPTS</key>
<value>-Xms256m -Xmx256m</value>
</org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<key>MAVEN_MIRROR_URL</key>
<value>https://nexus.mycompany.com/repository/maven-public</value>
</org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<key>MAVEN_SERVER_USERNAME</key>
<secretName>maven-secret</secretName>
<secretKey>username</secretKey>
</org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<key>MAVEN_SERVER_PASSWORD</key>
<secretName>maven-secret</secretName>
<secretKey>password</secretKey>
</org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
</envVars>
<ports/>
<livenessProbe>
<execArgs></execArgs>
<timeoutSeconds>0</timeoutSeconds>
<initialDelaySeconds>0</initialDelaySeconds>
<failureThreshold>0</failureThreshold>
<periodSeconds>0</periodSeconds>
<successThreshold>0</successThreshold>
</livenessProbe>
</org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
<org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
<name>httpbin</name>
<image>citizenstig/httpbin</image>
<privileged>false</privileged>
<alwaysPullImage>false</alwaysPullImage>
<workingDir></workingDir>
<command>/run.sh</command>
<args></args>
<ttyEnabled>false</ttyEnabled>
<resourceRequestCpu></resourceRequestCpu>
<resourceRequestMemory>256Mi</resourceRequestMemory>
<resourceLimitCpu></resourceLimitCpu>
<resourceLimitMemory>256Mi</resourceLimitMemory>
<envVars/>
<ports/>
<livenessProbe>
<execArgs></execArgs>
<timeoutSeconds>0</timeoutSeconds>
<initialDelaySeconds>0</initialDelaySeconds>
<failureThreshold>0</failureThreshold>
<periodSeconds>0</periodSeconds>
<successThreshold>0</successThreshold>
</livenessProbe>
</org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
</containers>
<envVars/>
<annotations/>
<imagePullSecrets/>
</org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
</templates>
<serverUrl>https://172.30.0.1:443</serverUrl>
<serverCertificate>-----BEGIN CERTIFICATE--MIIC6jCC...
-----END CERTIFICATE-----</serverCertificate>
<skipTlsVerify>false</skipTlsVerify>
<namespace>first</namespace>
<jenkinsUrl>http://jenkins.cicd.svc:80</jenkinsUrl>
<jenkinsTunnel>jenkins-jnlp.cicd.svc:50000</jenkinsTunnel>
<credentialsId>1a12dfa4-7fc5-47a7-aa17-cc56572a41c7</credentialsId>
<containerCap>10</containerCap>
<retentionTimeout>5</retentionTimeout>
<connectTimeout>0</connectTimeout>
<readTimeout>0</readTimeout>
<maxRequestsPerHost>32</maxRequestsPerHost>
</org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud>
</clouds>
</hudson>
嘗試愉快的構建吧!
原文發表於 ITNext,已獲得翻版授權。
via: https://opensource.com/article/18/4/running-jenkins-builds-containers
作者:Balazs Szeti 選題:lujun9972 譯者:pinewall 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive