Jenkins 做為最著名的 CI/CD 工具,在全世界范圍內(nèi)被廣泛使用蛤铜,而隨著以 Kubernetes 為首的云平臺的不斷發(fā)展與壯大官研,在 Kubernetes 上運行 Jenkins 的需求越來越多。
本文將介紹如何使用 Helm3 在 Kubernets 上快速部署一個生產(chǎn)環(huán)境可用的 Jenkins 實例泻骤。
通過本文的學習漆羔,你將能夠:
- 了解并掌握 Helm 的一些基本操作知識梧奢。
- 利用 Helm Chart 快速部署一個符合自己需求的 Jenkins 實例。
安裝前的準備
Kubernetes 集群
既然是部署在 Kubernetes 平臺上演痒,首先你當然需要有一個可用的 Kubernetes 集群亲轨,本文支持幾乎所有 Kubernetes 平臺,并分別在 GKE鸟顺、EKS 以及 Minikube 上做了部署測試惦蚊。同時你還需要正確配置了本地的 kubeconfig 文件,確保 kubectl
命令可以與你的集群正常通信讯嫂。
HELM
本文將使用 Helm 部署 Jenkins 到 Kubernetes 平臺上蹦锋。Helm 是一款 Kubernetes 平臺上類似于包的管理工具,它將在 Kubernetes 平臺上部署應用程序時所需的所有 Kubernetes 資源的定義文件(如:Deployment端姚、Service晕粪、PVC 等等)打包到一起,稱之為 Chart渐裸,而 Helm 正是通過部署這些 Chart 將相應的應用程序部署到 Kubernetes 平臺上的巫湘。
安裝 HELM
在能夠使用 Helm 之前,首先要確保 Helm 客戶端被正確安裝到本地環(huán)境中昏鹃。本文所使用的 Helm 版本為 Helm3 尚氛,它與 Helm2 版本最大的區(qū)別在于:Helm3 不在像 Helm2 那樣,在可以使用 Helm 命令之前洞渤,需要在目標 Kubernetes 平臺上提前部署好用于接收和處理由 Helm 命令發(fā)送的 API 請求的 Tiller(部署在 kube-system namespace 下的 Pod)阅嘶,Helm3 則可以直接與目標 Kubernetes API 進行通信,而不再需要任何中間翻譯層载迄。
因此讯柔,在使用 Helm3 版本時,只需確保 Helm3 被正確安裝到本地即可护昧。安裝 Helm 非常簡單魂迄,對于 MacOS 用戶,可直接通過 brew
命令安裝:
brew install helm
而 Windows 用戶則可以使用 choco
命令安裝:
choco install kubernetes-helm
或者你也可直接到 Helm 所在的 Github Release 頁面下載 Helm3 版本下對應平臺的可執(zhí)行二進制文件惋耙,并保存到系統(tǒng)環(huán)境變量 PATH 指定的目錄下捣炬。關(guān)于更多安裝詳情,請查看官方 安裝文檔绽榛。
當安裝完成后湿酸,即可通過 Helm 的 version
命令查看當前安裝的 Helm 版本信息:
$ helm version
version.BuildInfo{Version:"v3.1.2", GitCommit:"d878d4d45863e42fd5cff6743294a11d28a9abce", GitTreeState:"clean", GoVersion:"go1.13.8"}
如果你也得到以上類似信息,那么說明 Helm3 已經(jīng)被正確安裝灭美,接下來我們就可以直接使用 helm
命令來部署應程序到 Kubernetes 平臺上了推溃。
添加 Helm Chart 倉庫
我們已經(jīng)知道,Helm 是通過部署某個應用程序所對應的 Chart 來實現(xiàn)對該應用程序的部署的届腐。當前已經(jīng)存在了許許多多被定義好的 Chart 來供我們使用美莫,這些 Chart 被保存在了不同的 Chart 倉庫中页眯,你可以通過在 Helm Hub 中搜索并查看是否存在某個應用程序?qū)?Chart,也可以通過查看 HELM 官方在 Github 上的 Chart 倉庫 來查看官方為我們提供的所有可用的 Chart 包厢呵。
注意:官方 Chart 被分為了兩類:stable 和 incubator窝撵。顧名思義,stable 為穩(wěn)定版襟铭,處于 stable 下的所有 Chart 可以被應用到生產(chǎn)環(huán)境中碌奉;而 incubator 中的 Chart 仍然處在積極的開發(fā)狀態(tài)中,不推薦在生產(chǎn)環(huán)境中使用寒砖。而我們本文中所要使用的則是位于 stable 下的 Jenkins Chart 赐劣。
當我們要部署某個保存在 Chart 倉庫中的 Chart 時,首先需要將該倉庫通過 Helm 的 repo add
命令添加到本地倉庫列表中哩都,這樣 Helm 才知道從何處下載該 Chart:
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
"stable" has been added to your repositories
上面這條指令將官方 Stable Chart 庫的地址添加到了本地魁兼,并為其命名為 stable
,這樣我們就可以使用 stable/CHART-NAME
格式引用并部署被存儲到該倉庫下的Chart 了漠嵌,如我們接下來要使用的 stable/jenkins
Chart咐汞。
當某個倉庫被添加后,就可以在 repo list
命令列出的所有倉庫列表中查看到剛剛添加的倉庫信息:
$ helm repo list
NAME URL
stable https://kubernetes-charts.storage.googleapis.com/
也可以使用 repo update
命令更新當前已添加的 Chart 庫:
$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "stable" chart repository
Update Complete. ? Happy Helming!?
我們還可以通過 search repo
命令在當前配置的 Chart 倉庫中查詢某個 Chart :
$ helm search repo jenkins
NAME CHART VERSION APP VERSION DESCRIPTION
stable/jenkins 1.10.1 lts Open source continuous integration server. It s...
該命令會在添加到當前系統(tǒng)中的所有 Chart 倉庫中搜索名為 Jenkins 的 Chart儒鹿,而從獲取到的結(jié)果中我們可以看到化撕,在我們剛剛添加的 stable 庫中找到了 Jenkins Chart stable/jenkins
,這正是我們接下來部署 Jenkins 時所需要用到的 Chart 约炎。
創(chuàng)建 Jenkins namespace
為了能夠更好地組織我們部署在 Kubernetes 中的應用程序植阴,通常會將某個應用程序安裝到自己獨立的 namespace 下,Jenkins 也不例外圾浅,因此在部署 Jenkins 之前掠手,首先創(chuàng)建一個專用的 namespace jenkins
:
$ kubectl create ns jenkins
如果你熟悉 Helm2,會了解到當使用 Helm2 部署應用程序到某個特定的 namespace 下時狸捕,若該 namespace 在當前 Kubernetes 不存在惨撇,Helm2 會自動為我們創(chuàng)建出該 namespace。而這一行為在 Helm3 中則發(fā)生了改變 府寒,當使用 Helm3 部署某個應用程序時,若指定的 namespace 在當前 Kubernetes 中不存在报腔,則會報出 namespace 無法找到的錯誤信息株搔,并終止部署流程。
持久化存儲卷
默認情況下纯蛾,我們所使用的 Jenkins Chart 會在部署過程中使用當前 Kubernetes 集群中默認的 StorageClass 創(chuàng)建一個大小為 8G 的 PVC 做為 JENKINS_HOME 的掛載卷纤房,因此在部署前請確保你所在的 Kubernetes 集群存在這樣一個默認的 StorageClass,并能夠創(chuàng)建出符合條件的 PVC翻诉,否則你的部署流程會由于無法創(chuàng)建出對應的 PVC 而被卡住炮姨“乒危可通過如下命令查看你的 Kubernetes 集群中是否存在默認的 StorageClass:
$ kubectl get sc
NAME PROVISIONER AGE
standard (default) kubernetes.io/gce-pd 5d5h
其中 StorageClass standard
后面的 (default)
說明了該 StorageClass 為當前系統(tǒng)默認的 StorageClass。
如果你使用的 Kubernetes 集群中沒有默認的 StorageClass舒岸,或是沒有足夠的空間來創(chuàng)建出 8G 大小的 PVC绅作,也不用擔心,可以暫時在下面的部署命令中通過追加 --set persistence.enabled=false
參數(shù)來禁止該 Chart 創(chuàng)建任何 PVC蛾派,我們將在后面介紹 Jenkins Home 持久化存儲時講解如何使用其它方式創(chuàng)建出 PVC 來俄认。
開始第一次部署
配置好 Helm 及創(chuàng)建好 namespace 之后,就可以使用 helm install
命令來部署 Jenkins Chart 了:
$ helm install jenkins stable/jenkins -n jenkins
或者如果你無法創(chuàng)建出 PVC洪乍,請使用下面命令代替:
# 或使用該命令來禁止在部署過程中創(chuàng)建任何 PVC
$ helm install jenkins stable/jenkins -n jenkins --set persistence.enabled=false
上面的 Helm 命令使用 stable/jenkins
Chart 創(chuàng)建一個名為 jenkins 的部署眯杏,其中 -n
參數(shù)指定來我們要部署的 namespace。
當命令執(zhí)行成功后壳澳,你將會看到類似如下的輸出信息:
NAME: jenkins
LAST DEPLOYED: Thu Apr 2 11:07:36 2020
NAMESPACE: jenkins
STATUS: deployed
REVISION: 1
NOTES:
1. Get your 'admin' user password by running:
printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
2. Get the Jenkins URL to visit by running these commands in the same shell:
export POD_NAME=$(kubectl get pods --namespace jenkins -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=jenkins" -o jsonpath="{.items[0].metadata.name}")
echo http://127.0.0.1:8080
kubectl --namespace jenkins port-forward $POD_NAME 8080:8080
3. Login with the password from step 1 and the username: admin
For more information on running Jenkins on Kubernetes, visit:
https://cloud.google.com/solutions/jenkins-on-container-engine
通過上面的輸出岂贩,我們可以得知以下幾點信息:
- 此次的 Helm 部署名為
jenkins
,部署的 namespace 同樣為jenkins
巷波。 - Jenkins 管理員登陸賬號為
admin
萎津,且密碼可以通過執(zhí)行命令printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
獲取到。 - 當前部署的 Jenkins 實例并沒有任何外部可直接訪問的 IP 地址或 URL褥紫,而是需要通過 port forward 的方式將部署的 Jenkins Pod 的端口映射到本地的方式來訪問它姜性。
提示:我們也可以通過使用 Helm 的 status
查看當前某個部署的信息的方式,來獲取以上信息:helm status jenkins -n jenkins
髓考。
上面的輸出僅僅代表了 Helm 命令返回成功部念,但這并不意味著 Jenkins 已經(jīng)被成功部署到了 Kubernetes 平臺上,該 Chart 所定義的 Kubernetes 資源可能仍然處在創(chuàng)建過程中氨菇,設置可能會出現(xiàn)創(chuàng)建失敗的情況儡炼。如果你沒有在部署的命令行中通過追加 --set persistence.enabled=false
參數(shù)來禁止創(chuàng)建 PVC,則我們應當首先確認 PVC 是否被成功的創(chuàng)建出來:
$ kubectl -n jenkins get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
jenkins Bound pvc-265e71bb-2b82-46d1-8b3c-d495407b1e6d 8Gi RWO standard 87s
當確認 PVC 被成功創(chuàng)建后查蓉,接下來讓我們查看一下 Pod 的狀態(tài)信息乌询,如果你在 Helm 命令執(zhí)行成功后馬上查看 Pod 的狀態(tài)信息,你可能會看到類似下面的信息:
$ kubectl -n jenkins get pods
NAME READY STATUS RESTARTS AGE
jenkins-58d9d655df-cjw5h 0/1 Init:0/1 0 55s
Pod 狀態(tài)為 Init:0/1
豌研,說明該 Pod 正在處于初始化階段妹田。Jenkins Chart 生成的 Deployment 資源為 Pod 定義了一個名為 copy-default-config 的 initContainers,用于執(zhí)行初始化腳本 apply_config.sh鹃共,該腳本的主要作用是將定義在 configmap 中的配置信息應用到我們最終部署的 Jenkins 實例中鬼佣。同時,該腳本還會自動為我們安裝定義的插件霜浴、創(chuàng)建自定義初始化 job 等等工作晶衷。
我們可以在查看 Pod 日志信息時通過 -c copy-default-config
參數(shù)來指定查看該 initContainers 的日志信息:
$ kubectl -n jenkins logs -f jenkins-58d9d655df-cjw5h -c copy-default-config
Creating initial locks...
Analyzing war /usr/share/jenkins/jenkins.war...
Registering preinstalled plugins...
Using version-specific update center: https://updates.jenkins.io/2.204...
Downloading plugins...
...
...
...
Cleaning up locks
Jenkins Chart 為我們創(chuàng)建的不僅僅是 Pod,同時還包括了所有其它的必要資源,如:service晌纫、persistentVolumeClaim税迷、serviceAccount 等等,可通過 Helm 的 get manifest
命令將所部署的所有資源以 YAML 的格式打印出來:
$ helm get manifest jenkins -n jenkins
---
# Source: jenkins/templates/service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins
namespace: jenkins
labels:
"app.kubernetes.io/name": 'jenkins'
"helm.sh/chart": "jenkins-1.10.1"
"app.kubernetes.io/managed-by": "Helm"
"app.kubernetes.io/instance": "jenkins"
"app.kubernetes.io/component": "jenkins-master"
---
# Source: jenkins/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: jenkins
namespace: jenkins
... more output
訪問 Jenkins 服務
等待 Pod 狀態(tài)轉(zhuǎn)換為 Running锹漱,且 Pod 內(nèi)運行的 Jenkins 服務完全啟動后箭养,就可以訪問我們的 Jenkins 實例了。
你可以通過觀察 Pod 的日志輸出凌蔬,如果輸出的最后包含了類似 INFO hudson.WebAppMain$3#run: Jenkins is fully up and running
的信息露懒,則說明 Pod 內(nèi)的 Jenkins 服務已經(jīng)啟動成功,并可以接收請求了砂心。
但在訪問之前懈词,我們還需完成兩件事:首先需要獲取登陸用戶 admin 的密碼,該密碼為隨機生成辩诞,可通過 Helm 輸出中給定的 print 命令獲瓤餐洹:
# 獲取 Admin 用戶的登陸密碼
printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
另一件需要完成的事是端口轉(zhuǎn)發(fā)。如果你此時查看 jenkins namespace 的 SVC:
$ kubectl -n jenkins get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins ClusterIP 10.101.220.161 <none> 8080/TCP 2m
jenkins-agent ClusterIP 10.97.93.57 <none> 50000/TCP 2m
Chart 為我們創(chuàng)建的 Jenkins 的 SVC 類型為 ClusterIP
译暂,而該類型的 SVC 只能在 Kubernetes 內(nèi)部進行訪問抠忘。因此,我們需要通過端口轉(zhuǎn)發(fā)的方式外永,將該 Pod 端口直接映射到本地指定的端口上崎脉,在通過訪問本地地址+該端口號的方式訪問該 Pod:
# 獲取 Pod 名
export POD_NAME=$(kubectl get pods --namespace jenkins -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=jenkins" -o jsonpath="{.items[0].metadata.name}")
# 開啟端口轉(zhuǎn)發(fā)
kubectl --namespace jenkins port-forward $POD_NAME 8080:8080
上面命令表示將本地的 8080 端口映射到 Pod 的 8080 端口,執(zhí)行成功后伯顶,你將會看到類似如下的輸出結(jié)果:
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
此時說明已經(jīng)成功開啟了端口映射囚灼,在瀏覽器輸入 http://127.0.0.1:8080 即可訪問我們的 Jenkins 服務了。
至此祭衩,一個最基本的 Jenkins 實例就已經(jīng)被成功地部署到了我們的 Kubernetes 集群中灶体,并且可以開始為我們提供了。但就目前所部署的 Jenkins 實例來說掐暮,它還不適用于生產(chǎn)環(huán)境蝎抽,至少我們還需要為其設定一個可以直接對外訪問的 URL 地址,這通常是通過為創(chuàng)建的 service 資源的 Type 屬性設定為 LoadBalancer
或是 NodePort
路克,或是為其創(chuàng)建一個 Ingress 資源來實現(xiàn)的樟结,接下來就讓我們學習如果通過自定義的方式來部署我們所需的資源。
自定義部署
通過使用 Helm chart 的方式部署應用程序時精算, 帶給我們的不僅僅是簡單快速的部署方式瓢宦,更多的是靈活的自定義性。
當使用 Chart 部署應用程序時殖妇,Helm 首先會解析定義在該 Chart 中的模版文件,使其生成對應的用于創(chuàng)建 Kubernetes 資源的 YAML 文件破花,并最終利用這些文件來創(chuàng)建出所有資源谦趣。Chart 模版文件使用 Go 語言實現(xiàn)疲吸,它支持 Go 語言模版引擎所提供的幾乎全部功能,包括例如變量前鹅、表達式摘悴、循環(huán)、函數(shù)等等舰绘。
Chart 中定義的每個模版文件中幾乎都定義了一系列變量蹂喻,并且在 Chart 的 values.yaml
文件中為所有這些定義的變量設定了默認值,如 Jenkins Chart 的 values.yaml 文件捂寿。我們可以通過在部署 Chart 的過程中為這些變量賦予不同于默認值的其它合法值的方式口四,來創(chuàng)建含有特定設定的 Kubernetes 資源,以實現(xiàn)自定義部署的目的秦陋。
Helm 支持兩種變量賦值的方式:在命令行中通過 --set
參數(shù)直接為某個變量進行賦值蔓彩,如 --set foo=bar
,將字符串 bar 賦值給變量 foo驳概,當需要為多個變量設定值時赤嚼,可以多次指定 set 參數(shù)來為每個變量賦值;另一種方式是像 Chart 中的 values 文件那樣顺又,創(chuàng)建自己的 values.yaml
文件更卒,并將所有想要重新賦值的變量及其新值寫入到該文件中,并在部署時通過 -f
參數(shù)指定該文件稚照,如: -f values.yaml
蹂空。
我們通常更傾向于采用第二種方式:將所有要自定義的變量和值保存到 values 文件中。這種方式不僅可以簡化我們的命令行锐锣,因為無論有多少要重寫的變量腌闯,最終在命令行都只需指定一個 -f
參數(shù)即可;同時雕憔,我們還可以將 values 文件保存到如 Git 這樣的 SCM 工具中姿骏,在方便多人合作的同時,還可以對該文件的歷史記錄進行跟蹤管理斤彼。
不同的 Helm Chart 可設定的自定義變量都不盡相同分瘦,在安裝前需仔細閱讀相關(guān) Chart 文檔,或直接查看其 Chart 的 values.yaml
文件琉苇。
接下來就讓我們看一下如何通過為這些變量設定適當?shù)闹祦聿渴鹨粋€生產(chǎn)環(huán)境可用的 Jenkins 服務嘲玫。
創(chuàng)建工作目錄
由于我們將要采用的是以文件的方式保存要設定的變量值,因此在開始之前首先使用如下命令創(chuàng)建出我們所需的工作目錄及文件:
$ mkdir jenkins
$ cd jenkins
$ touch values.yaml
在接下來的講解中并扇,所有設定的變量都將被保存到 values.yaml
文件中
創(chuàng)建可對外訪問的服務
對于一個的 Jenkins 服務來說去团,我們更希望可以直接通過某個 URL 地址對其進行訪問,而不是像前面那樣通過端口轉(zhuǎn)發(fā)的方式進行訪問。
為能夠直接訪問 Jenkins 服務土陪,我們可以將 Chart 創(chuàng)建的 service 資源的 type
屬性設定為 NodePort
或 LoadBalancer
昼汗,或是通過創(chuàng)建 Ingress 資源使其 service 可對外訪問。
而在實際的生產(chǎn)環(huán)境中鬼雀,我們則更傾向于后兩種方式:LoadBalancer 和 Ingress顷窒,接下來讓我們分別看一下如何實現(xiàn)這兩種設定。
LoadBalancer
如果你所使用的云廠商嘗試支持 LoadBalancer源哩,那么創(chuàng)建一個 LoadBalancer 類型的 service 是最簡單鞋吉,也是最值得推薦的方式±常可以通過將變量 serviceType 的值直接設定為 LoadBalancer
即可:
master:
serviceType: LoadBalancer
將上面的內(nèi)容保存到本地的 values.yaml
文件中谓着。注意,當為某個變量重新賦值時崩侠,要保證該變量對應的 key 值所處的結(jié)構(gòu)不能發(fā)生改變漆魔。如這里的 serviceType
key 在原 Chart 的 values.yaml
文件中屬于 master
下的一個子屬性,在我們自己所編寫的 values.yaml
文件中要遵守同樣的規(guī)則却音。
Ingress
若你不希望使用 LoadBalancer改抡,或者你所在的 Kubernetes 平臺不支持 LoadBalancer 功能,你也可以通過創(chuàng)建 Ingress 資源的方式讓外界訪問到你到 service:
注意系瓢,如果你使用的是 minikube阿纤,在繼續(xù)下面到講解之前請確保你已經(jīng)開啟了 ingress 插件,可通過命令 minikube addons list
查看 Ingress 插件是否被啟用夷陋,如若沒有啟用欠拾,則執(zhí)行命令 minikube addons enable ingress
來啟用 。
master:
ingress:
enabled: true
serviceType: NodePort
ingress.enabled 默認值為 false骗绕,表示不會為我們創(chuàng)建任何 Ingress 資源藐窄,因此這里需要顯示設定該值為 true 以確保讓 Jenkins Chart 自動為我們創(chuàng)建出 Ingress 資源。
同時我們需要將 serviceType 屬性指定為 NodePort
以便 Ingress 可以訪問到我們到 service酬土。如果你所使用到云平臺廠商支持 LoadBalancer荆忍,則將 serviceType 設置為 LoadBalancer 仍然是你最好到選擇。
除了 enabled
外撤缴,用于創(chuàng)建 Ingress 的 Chart 模版 jenkins-master-ingress.yaml 還支持許多其它參數(shù)來為生成的 Ingress 設定其它屬性刹枉,如為 ingress 資源創(chuàng)建 Labels,Annotations屈呕,設定 hostname 以及 tls 等等微宝,可通過查看 values 文件中的關(guān)于 ingress 設定的部分所有支持的變量,并根據(jù)自己的實際情況為這些變量設定相應的值虎眨。
重新部署你的 Jenkins 服務
到目前為止蟋软,我們創(chuàng)建了一個名為 values.yaml
的 YAML 文件镶摘,并包含了可以讓你的 Jenkins 服務直接對外訪問的基本配置,接下來岳守,就讓我們利用該文件來重新部署我們的 Jenkins 實例钉稍。
但在重新部署之前,首先讓我們查看下當前 Kubernetes 中 Helm 的部署情況:
helm ls -n jenkins
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
jenkins jenkins 1 2020-04-02 11:07:36.98936 +0800 CST deployed jenkins-1.10.1 lts
上面使用了 Helm 的 ls
命令列出了當前在 jenkins namespace 下的所有部署信息棺耍,可以看到已經(jīng)存在了有一個名為 jenkins
的部署存在于我們的 Kubernetes 中,這正是我們之前使用默認值部署的 Jenkins 實例种樱。
注意:Helm3 與 Helm2 另一個不同之處就是蒙袍,在 Helm3 中,所有的部署都被綁定到了某個 namespace 下嫩挤,因此害幅,上面的命令需要通過 -n
參數(shù)指定我們要查看的 namespace。
而對于一個已經(jīng)存在了的部署岂昭,要想對其進行重新部署以现,一般有兩種選擇:
- 刪除當前部署,之后在重新對其進行另一個新的部署约啊;
- 在當前部署的基礎之上對其進行升級部署邑遏;
讓我們分別看一下如何通過這兩種方式重新部署我們的 Jenkins 服務。
重新創(chuàng)建
這種通過刪除/創(chuàng)建的方式來對某個 Chart 進行重新部署恰矩,是非常不推薦的一種方式记盒,在這里列出該方式的實現(xiàn)只是為了給大家做參考使用。
首先是使用 delete
命令刪除某個特定的部署:
$ helm delete jenkins -n jenkins
release "jenkins" uninstalled
該命令將刪除 jenkins namespace 下的名為 jenkins 的部署外傅,在命令執(zhí)行完成后纪吮,你將會看到上面的輸出結(jié)果,提示我們的 jenkins 部署已經(jīng)被成功刪除萎胰。
你可以使用下面命令確認所有資源是否已經(jīng)被刪除:
$ kubectl -n jenkins get all
No resources found in jenkinss namespace.
之后在重新使用 install 命令進行新的部署:
$ helm install jenkins stable/jenkins -n jenkins -f values.yaml
在上面的命令中碾盟,通過 -f
參數(shù)將我們的 values.yaml 文件傳遞給了 Helm 命令,這樣技竟,Helm 就會從該文件中讀取我們設定的變量值冰肴。
升級部署
升級部署是指對當前某個已經(jīng)存在的部署直接做升級操作,這也是比較推薦的一種方式灵奖。通過該種方式對某個 Chart 做升級操作后嚼沿,不僅可以保留升級的歷史記錄耳鸯,同時還可以將我們升級的 Chart 做回滾操作撇寞,使其回退到之前的某個版本查剖。
Helm 使用 upgrade
命令對某個部署進行升級:
$ helm upgrade jenkins stable/jenkins -n jenkins -f values-ing.yaml
該命令使用了我們創(chuàng)建的 values-ing.yaml 文件對當前的 jenkins 部署做了升級操作挚歧,升級完成后你將看到類似如下的輸出結(jié)果:
Release "jenkins" has been upgraded. Happy Helming!
NAME: jenkins
LAST DEPLOYED: Thu Apr 2 13:27:58 2020
NAMESPACE: jenkins
STATUS: deployed
REVISION: 2
NOTES:
1. Get your 'admin' user password by running:
printf $(kubectl get secret --namespace jenkins jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
2. Get the Jenkins URL to visit by running these commands in the same shell:
export NODE_PORT=$(kubectl get --namespace jenkins -o jsonpath="{.spec.ports[0].nodePort}" services jenkins)
export NODE_IP=$(kubectl get nodes --namespace jenkins -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT/login
3. Login with the password from step 1 and the username: admin
For more information on running Jenkins on Kubernetes, visit:
https://cloud.google.com/solutions/jenkins-on-container-engine
與我們創(chuàng)建部署時返回的結(jié)果基本相似五督,除了第一句提示為 升級押逼。
查看我們的 service 和 ingress 情況:
# 獲取 service 信息
kubectl -n jenkins get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins NodePort 10.101.220.161 <none> 8080:30450/TCP 140m
jenkins-agent ClusterIP 10.97.93.57 <none> 50000/TCP 140m
# 獲取 ingress 信息
$ kubectl -n jenkins get ing
NAME CLASS HOSTS ADDRESS PORTS AGE
jenkins <none> * 192.168.99.101 80 35s
此時的 jenkins service 類型已經(jīng)被更新為了 NodePort
類型箫措,同時 Ingress 資源也被創(chuàng)建出來了塑陵,并且我們可以通過 Ingress 地址 192.168.99.101
來訪問我們的 Jenkins 服務了。
使用 Helm 的 history
命令查看 Jenkins Chart 的所有升級歷史記錄:
helm history jenkins -n jenkins
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Thu Apr 2 11:07:36 2020 superseded jenkins-1.10.1 lts Install complete
2 Thu Apr 2 13:27:58 2020 deployed jenkins-1.10.1 lts Upgrade complete
什么的輸出中谭贪,第二條記錄即為我們本次升級的記錄信息境钟。
提示:無論是創(chuàng)建或者升級某個部署時,你都可以在命令行中指定 --dry-run
參數(shù)俭识,該參數(shù)的作用是僅僅打印出 Chart 生成的 Kubernetes 資源定義信息慨削,而不會做任何真正的部署,我們通常在部署之前通過該命令驗證 Chart 生成的資源定義信息是否是我們所需要的套媚。
Jenkins Home 持久化存儲
Jenkins 的所有配置信息及 Job 信息都是以文件的方式存儲在 JENKINS_HOME
目錄中的缚态,在真正的生產(chǎn)環(huán)境中,我們通常需要將該目錄掛載到 PVC 中做持久存儲堤瘤,這樣做不僅可以保證數(shù)據(jù)在 pod 意外重啟或刪除后不會丟失玫芦;同時,這也是實現(xiàn) Jenkins 可擴容性(同時支持多個 Jenkins Pod 運行)的必要前提本辐。
默認情況下桥帆,Jenkins chart 會利用當前 Kubernetes 上的默認 StorageClass 創(chuàng)建一個大小為 8G 的 PVC,并自動將 JENKINS_HOME 掛載到該 PVC 上慎皱。
指定其它 StorageClass
如果你當前所在的 Kubernetes 平臺沒有設定默認的 StorageClass老虫,或是你希望使用其它非默認的 StorageClass 來為你創(chuàng)建 PVC,可以通過設定 persistence.storageClass
key 來實現(xiàn):
persistence:
storageClass: MySC
注意:persistence 并沒有位于 master 下茫多。
上面的配置指定了在部署過程中张遭,將會使用 MySC
StorageClass 來創(chuàng)建 PVC。
使用現(xiàn)有 PVC
你也可以提前創(chuàng)建好自己的 PVC地梨,并通過 existingClaim
key 指定你的 PVC:
persistence:
existingClaim: JENKINS_HOME_PVC
一旦為 existingClaim
設定了值菊卷,Chart 就不會在利用 StorageClass 創(chuàng)建任何 PVC,如果你所在的 Kubernetes 平臺上沒有任何可用的 StorageClass 宝剖,則可以采用該方式進行部署洁闰。
Chart 模版還支持一些其它用于設定 PVC 屬性的變量,如設定 PVC 大小的 size
變量万细,設定 PVC 訪問模式的 accessMode
變量等等扑眉,如下是我們當前所要使用的 PVC 配置,創(chuàng)建一個大小為 5G 的 PVC:
persistence:
# 修改自動創(chuàng)建的 PVC 大小
size: "5Gi"
關(guān)于更多支持的變量赖钞,請查看 values 文件中關(guān)于 persistence 獲取完整可支持的變量腰素。
有一點需要注意,一旦我們創(chuàng)建好一個 PVC 后雪营,就不能在對其大小作出任何改變(雖然有些 PVC 可以對其進行擴容操作弓千,這取決要 PVC 底層使用的存儲系統(tǒng)是否對支持該功能),因此如果我們對 PVC 對大小作出了任何改變献起,應當先刪除該 Helm 部署洋访,之后在對其重新創(chuàng)建一個新對部署镣陕。刪除某個 PVC,也意味著該 PVC 中存儲的數(shù)據(jù)也都將丟失姻政,因此在創(chuàng)建 PVC 之前盡量對其規(guī)劃好呆抑,盡量避免后期對其進行更改。
禁用 PVC
如果基于某種原因汁展,你不希望部署的 Jenkins 實例使用任何 PVC鹊碍,你可以設定 persistence.enabled
的值為 false:
persistence:
enabled: false
這樣 Chart 就不會創(chuàng)建任何 PVC,也不會為我們的 Jenkins 掛載任何 PVC 資源食绿。
預安裝 Jenkins 插件
Jenkins 的成功可以說離不開它豐富而強大的插件妹萨,在每次初始化好一個 Jenkins 實例后,我們通常首要的任務就是安裝各種我們所需的插件炫欺。
Jenkins Helm Chart 支持我們將需要安裝的所有插件以列表的形式賦值給 installPlugins 變量,這樣在 Jenkins Pod 初始化時會在 initContainers 中自動為我們安裝這些插件:
master:
installPlugins:
- ldap
- matrix-auth
- authorize-project
- ansicolor
- jacoco
- job-dsl
- slack
- checkstyle
- kubernetes
- openshift-client
- workflow-job
- workflow-aggregator
- credentials-binding
- git
- github-branch-source
- github-pullrequest
- ghprb
注意:這里使用的是插件 ID熏兄,而不是插件的名字品洛,插件 ID 可以在插件詳情頁面的 ID 字段中獲取到。
除了像上面那樣只寫插件 ID 外摩桶,還可以在插件 ID 后追加要安裝的插件的版本號桥状,中間使用冒號分隔,如:kubernetes:1.24.1
硝清,來安裝指定版本的插件辅斟。
當部署完成后,就可以在 Manage Jenkins -> Plugins Manager 頁面的 Installed tab 下查看到這些已經(jīng)被安裝的插件:
Approval scripts
Jenkins 中的 Pipeline 實際上都是在 Jenkins 提供的 Groovy Sandbox 中運行的芦拿,而為了安全起見士飒,Sandbox 會限制我們執(zhí)行的 Groovy 腳本,只有少數(shù)一些被信任當 Groovy 方法才可以被執(zhí)行蔗崎。
但有些時候我們需要在 Pipeline 中執(zhí)行一些特殊的 Groovy 方法酵幕,而在首次執(zhí)行包含了沒有被信任的 Groovy 方法的 Pipeline 時,Pipeline 會因報錯而終止缓苛,并提示我們 Jenkins 的 Admin 用戶需要將這些方法添加到 Jenkins 的信任列表以后才可以在 Pipelien 中調(diào)用他們芳撒。
我們可以將所有希望添加到信任列表中的 Groovy 方法以 list 的形式賦值給 scriptApproval 變量,這樣當 Jenkins 部署好后未桥,會將這些方法自動添加到信任列表中:
master:
scriptApproval:
- "method groovy.json.JsonSlurperClassic parseText java.lang.String"
- "new groovy.json.JsonSlurperClassic"
使用該 scriptApproval
部署的 Jenkins 服務可以讓我們直接在 Pipeline 中實例化 JsonSlurperClassic
類笔刹,以及調(diào)用該類的 parseText
方法。
通過 “Manage Jenkins” -> “In-process Script Approval” 頁面可以查看所有 Approved scripts:
注意:該功能需要設定 enableXmlConfig 值為 true
冬耿。
自動創(chuàng)建 Job
每當我們在 Jenkins 中創(chuàng)建好一個 Job 后舌菜,都會在 JENKINS_HOME/jobs/
目錄下生成出一個與該 Job 同名的目錄,且該 Job 的配置信息將以 XML 的格式保存在了該目錄下的 config.xml
文件中亦镶。
我們可以通過將這些 Job 的配置信息傳遞給 Jenkins Helm Chart 的 jobs 變量的方式酷师,讓 Chart 自動為我們在新部署的 Jenkins 中將這些 Job 創(chuàng)建出來:
master:
jobs:
HelloMyPipeline: |-
<?xml version='1.1' encoding='UTF-8'?>
<flow-definition plugin="workflow-job@2.38">
<description></description>
<keepDependencies>false</keepDependencies>
<properties/>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps@2.80">
<script>pipeline {
agent any
stages {
stage('Hello') {
steps {
echo 'Hello World'
}
}
}
}
</script>
<sandbox>true</sandbox>
</definition>
<triggers/>
<disabled>false</disabled>
</flow-definition>
上面的配置會在部署好的 Jenkins 中創(chuàng)建一個名為 HelloMyPipeline
的 Pipeline, 其 Pipeline 腳本內(nèi)容如下圖所示:
注意:該功能需要設定 enableXmlConfig 值為 true
讶凉。
其它常見配置
更改默認登陸名和密碼
若沒有為部署的 Jenkins 服務指定任何其它如 LDAP 等登陸方式時,Jenkins 將采用默認的用戶名密碼的登陸方式進行認證山孔,并自動創(chuàng)建出一個登錄名為 admin
懂讯,密碼為隨機生成的管理員賬號,我們可以通過 Helm Chart 生成的 secret 中獲取經(jīng)過 base64 轉(zhuǎn)譯后的該用戶名和密碼(secret 名與我們部署的 Helm 名同名台颠,這里即為 jenkins)褐望,如:
$ kubectl -n jenkins get secret jenkins -o yaml
apiVersion: v1
data:
jenkins-admin-password: clBEWVBtZDg2eg==
jenkins-admin-user: YWRtaW4=
kind: Secret
metadata:
... more data
其中 jenkins-admin-user
和 jenkins-admin-password
分別保存了經(jīng)過 base64 轉(zhuǎn)譯后的值,我們可以通過 base64 -d
命令獲取其轉(zhuǎn)譯前真正的值:echo "YWRtaW4=" | base64 -d -
串前。
我們也可以通過為 adminUser
和 adminPassword
設定值的方式來指定我們想要的登陸賬號和密碼瘫里,如 :
master:
adminUser: sysadmin
adminPassword: sysadmin
上面的設定將登錄名和密碼同時修改成了 sysadmin
。
Pod resources
Jenkins Helm Chart 為創(chuàng)建的 Pod 設定了如下默認的資源限制:
master:
resources:
requests:
cpu: "50m"
memory: "256Mi"
limits:
cpu: "2000m"
memory: "4096Mi"
因此我們可以通過修改這些值來修改 Pod 對資源限制的需求荡碾。
Pod Probes
為了保證 Jenkins 服務的健壯性谨读,Helm Chart 通過以下變量為 Jenkins Pod 分別設定了 Readiness 和 Liveness:
master:
healthProbes: true
healthProbesLivenessTimeout: 5
healthProbesReadinessTimeout: 5
healthProbeLivenessPeriodSeconds: 10
healthProbeReadinessPeriodSeconds: 10
healthProbeLivenessFailureThreshold: 5
healthProbeReadinessFailureThreshold: 3
healthProbeLivenessInitialDelay: 90
healthProbeReadinessInitialDelay: 60
你可以通過設定 healthProbes
的值設定為 false
來關(guān)閉 livenessProbe
和 readinessProbe
,當然并不推薦在生產(chǎn)環(huán)境中這樣做坛吁。
完整的 values 文件
至此劳殖,我們已經(jīng)對大部分我們需要的變量進行了重新賦值,來滿足我們部署的要求拨脉, 現(xiàn)在是時候看一下完整的 Chart 中的 values.yaml
文件了:
persistence:
# 修改自動創(chuàng)建的 PVC 大小
size: "5Gi"
master:
serviceType: NodePort
# 啟用 Ingresss 資源
ingress:
enabled: true
# 設定要安裝的插件
installPlugins:
- ldap
- matrix-auth
- authorize-project
- ansicolor
- jacoco
- job-dsl
- slack
- checkstyle
- kubernetes
- openshift-client
- workflow-job
- workflow-aggregator
- credentials-binding
- git
- github-branch-source
- github-pullrequest
- ghprb
# 修改 Pod 資源限制
resources:
requests:
cpu: "50m"
memory: "256Mi"
limits:
cpu: "2000m"
memory: "4096Mi"
# 添加要加入到信任列表中的 Groovy 方法
scriptApproval:
- "method groovy.json.JsonSlurperClassic parseText java.lang.String"
- "new groovy.json.JsonSlurperClassic"
如果你足夠細心哆姻,會發(fā)現(xiàn)這里并沒有 Job 的定義信息。這里我們選擇將 Job 的配置信息放到一個獨立的文件中玫膀,將 Job 從主配置文件中分離出來矛缨,不僅簡化了主配置信息,而且我們可以編寫多個 Job 配置文件帖旨,在為不同環(huán)境部署 Jenkins 服務時來部署針對該環(huán)境下的特定的 Job箕昭。將 Job 配置單獨存放在 jobs.yaml
中:
master:
# 需要自動創(chuàng)建的初始化 Job
jobs:
HelloMyPipeline: |-
<?xml version='1.1' encoding='UTF-8'?>
<flow-definition plugin="workflow-job@2.38">
<description></description>
<keepDependencies>false</keepDependencies>
<properties/>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps@2.80">
<script>pipeline {
agent any
stages {
stage('Hello') {
steps {
echo 'Hello World'
}
}
}
}
</script>
<sandbox>true</sandbox>
</definition>
<triggers/>
<disabled>false</disabled>
</flow-definition>
再次使用 upgrade
對我們的 Jenkins 進行升級部署:
$ helm upgrade jenkins stable/jenkins -n jenkins -f values.yaml -f jobs.yaml
在上面的命令中,我們通過指定的第二個 -f
參數(shù)將 jobs.yaml
中定義的內(nèi)容傳遞給 Helm解阅,以便幫助我們創(chuàng)建出我們所需的 Job盟广。由于本次我們對生成對 Pod 作出了改動,因此在升級對過程中 Pod 會被重新創(chuàng)建:
kubectl -n jenkins get pods
NAME READY STATUS RESTARTS AGE
jenkins-ddd7fb47f-blv7m 0/1 Init:0/1 0 35s
等待升級完成瓮钥,新創(chuàng)建的 Pod 啟動成功后筋量,我們的 Jenkins 實例就被部署成功了,再次通過 Ingress 地址或是 LoadBalancer 地址即可訪問剛剛升級后的 Jenkins 服務了碉熄。
至此桨武,我們成功地部署了一個經(jīng)過定制化的 Jenkins 實例到我們的 Kubernetes 平臺。雖然部署好后的 Jenkins 會自動為我們安裝所需插件锈津,創(chuàng)建初始化 job 等一些工作呀酸,但是在可以正式使用之前,仍然需要對我們的 Jenkins 服務進行許多手動配置琼梆,在下一篇文章中性誉,我們將介紹如何使用 Jenkins 的 Configuration as Code 插件實現(xiàn)將所有的配置保存到我們的 values.yaml
文件中窿吩,最終達到 Jenkins 零配置的目的。