前言
首先明确軟體版本,我這裡使用的是
Jenkins ver. 2.121.3
,這個版本比較老,其上安裝 Kubernetes 插件所使用
kubectl
版本也比較老,無法使用 Kustomize 的 yaml 檔案需要的
apiVersion: apps/v1
,直接使用生成
deploy.yaml
檔案會報錯,是以這裡選擇了自己建構一個包含
kubectl
和
kustomize
的鏡像,在鏡像中使用 Kustomize 生成所需 yaml 檔案并在 Kubernetes 上部署。
軟體版本
前期準備
- Jenkins :本篇使用 Jenkins 示範 CI/CD ,安裝 Jenkins 就不在贅述,可以使用多種方法安裝 Jenkins ,詳細方法見 官網 。同時。 CI/CD 的工具有很多,這裡為了省事使用筆者現有的 Jenkins 進行示範,不推薦使用同筆者一樣的版本,請使用較新的版本;同時也可以使用其他 CI/CD 工具,這裡推薦使用 drone 。如果有更好的方案,歡迎交流。
-
&kubectl
:上文中提到了由于 Jenkins 版本比較老,是以這裡筆者自己制作了包含二者的 docker 鏡像,已上傳 dockerhub ,需要自取:kustomize
guoxudongdocker/kubectl
- Web 應用:這裡使用 flask 寫了一個簡單的 web 應用,用于示範,同樣以上傳 dockerhub
guoxudongdocker/flask-python
目錄結構
首先看一下目錄結構,目錄中包括
Dockerfile
、
Jenkinsfile
、 Kustomize 要使用的
deploy
目錄以及 web 應用目錄。
.
├── Dockerfile
├── Jenkinsfile
├── app
│ ├── main.py
│ └── uwsgi.ini
└── deploy
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── dev
│ ├── healthcheck_patch.yaml
│ ├── kustomization.yaml
│ └── memorylimit_patch.yaml
└── prod
├── healthcheck_patch.yaml
├── kustomization.yaml
└── memorylimit_patch.yaml
這裡可以看到 overlays 總共有兩個子目錄
dev
prod
,分别代表不同環境,在不同的環境中,應用不同的配置。
Jenkins 配置
Jenkins 的配置相對簡單,隻需要建立一個 pipeline 類型的 job

增加參數化建構,注:參數化建構需要安裝 Jenkins 插件
然後配置代碼倉庫即可
Pipeline
podTemplate(label: 'jnlp-slave', cloud: 'kubernetes',
containers: [
containerTemplate(
name: 'jnlp',
image: 'guoxudongdocker/jenkins-slave',
alwaysPullImage: true
),
containerTemplate(name: 'kubectl', image: 'guoxudongdocker/kubectl:v1.14.1', command: 'cat', ttyEnabled: true),
],
nodeSelector:'ci=jenkins',
volumes: [
hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'),
hostPathVolume(mountPath: '/usr/bin/docker', hostPath: '/usr/bin/docker'),
hostPathVolume(mountPath: '/usr/local/jdk', hostPath: '/usr/local/jdk'),
hostPathVolume(mountPath: '/usr/local/maven', hostPath: '/usr/local/maven'),
secretVolume(mountPath: '/home/jenkins/.kube', secretName: 'devops-ctl'),
],
)
{
node("jnlp-slave"){
stage('Git Checkout'){
git branch: '${branch}', url: 'https://github.com/sunny0826/flask-python.git'
}
stage('Build and Push Image'){
withCredentials([usernamePassword(credentialsId: 'docker-register', passwordVariable: 'dockerPassword', usernameVariable: 'dockerUser')]) {
sh '''
docker login -u ${dockerUser} -p ${dockerPassword}
docker build -t guoxudongdocker/flask-python:${Tag} .
docker push guoxudongdocker/flask-python:${Tag}
'''
}
}
stage('Deploy to K8s'){
if ('true' == "${deploy}") {
container('kubectl') {
sh '''
cd deploy/base
kustomize edit set image guoxudongdocker/flask-python:${Tag}
'''
echo "部署到 Kubernetes"
if ('prod' == "${ENV}") {
sh '''
# kustomize build deploy/overlays/prod | kubectl apply -f -
kubectl applt -k deploy/overlays/prod
'''
}else {
sh '''
# kustomize build deploy/overlays/dev | kubectl apply -f -
kubectl applt -k deploy/overlays/dev
'''
}
}
}else{
echo "跳過Deploy to K8s"
}
}
}
}
這裡要注意幾點:
- 拉取 git 中的代碼需要在 jenkins 中配置憑據。
- 筆者的 jenkins 部署在 Kubernetes 上,要操作叢集的話,需要将 kubeconfig 以 Secret 的形式挂載到 jenkins 所在 namespace。
-
需要 Java 環境運作,是以要将主控端的jenkins-slave
挂載到jdk
中。jenkins-slave
- 同樣的,主控端中需要事先安裝
。docker
-
為 dockerhub 的登入憑證,需要在 jenkins 中添加相應的憑證。docker-register
示範
開始建構
這裡選擇環境、分支,填入版本即可開始建構,注意:這裡的版本将已 tag 的形式标記 docker 鏡像。
這裡就可以看到建構成功了
檢視結果
這裡為了友善(其實就是懶),我就不給這個服務添加 ingress 來從外部通路了,這裡使用
KT打通本地和 k8s 叢集網絡來進行調試。
為了簡化在Kubernetes下進行聯調測試的複雜度,雲效在SSH隧道網絡的基礎上并結合Kubernetes特性建構了一款面向開發者的輔助工具kt
這裡看到這個服務正常啟動了
釋出新版本
更新 web 服務并送出
按照上面步驟在 jenkins 中重新建構,當然也可以配置鈎子,每次代碼送出後自動建構
檢視檢視新版本
同上面一樣,在建構成功後檢視服務是否更新
可以看到,版本已經更新了
釋出生産環境
這裡模拟一下釋出生産環境,假設生産環境是在
devops-prod
的 namespace 中,這裡隻做示範之用,真正的生産環境中,可能存在不止一個 k8s 叢集,這時需要修改 Jenkinsfile 中的
secretVolume
來挂載不同 k8s 的 kubeconfig 來達到釋出到不同叢集的目的。當然,一般釋出生産環境隻需選擇測試通過的鏡像來釋出即可,不需要在進行建構打包。
檢視生産版本
總結
上面的這些步驟簡單的示範了使用 jenkins 進行 CI/CD 的流程,流程十分簡單,這裡僅供參考
Kustomize 的作用
那麼, Kustomize 在整個流程中又扮演了一個什麼角色呢?
更新鏡像
在
jenkinsfile
中可以看到, kustomize 更新了基礎配置的鏡像版本,這裡我們之前一直是使用
sed -i "s/#Tag/${Tag}/g" deploy.yaml
來進行替換了,但是不同環境存在比較多的差異,需要替換的越來越多,導緻 Jekninsfile 也越來越臃腫和難以維護。 kustomize 解決了這個問題。
kustomize edit set image guoxudongdocker/flask-python:${Tag}
環境區分
上面也提到了,不同的環境我們存在這許多差異,雖然看上去大緻類似,但是很多細節都需要修改。這時 kustomize 就起到了很大的作用,不同環境相同的配置都放在
base
中,而差異就可以在
overlays
中實作。
.
├── base
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── dev
│ ├── healthcheck_patch.yaml
│ ├── kustomization.yaml
│ └── memorylimit_patch.yaml
└── prod
├── healthcheck_patch.yaml
├── kustomization.yaml
└── memorylimit_patch.yaml
可以看到,
base
中維護了項目共同的基礎配置,如果有鏡像版本等基礎配置需要修改,可以使用
kustomize edit set image ...
來直接修改基礎配置,而真正不同環境,或者不同使用情況的配置則在
overlays
中 以 patch 的形式添加配置。這裡我的配置是 prod 環境部署的副本為2,同時給到的資源也更多,詳情可以在
Github上檢視。
與 kubectl 的內建
在 jenkinsfile 中可以看到
# kustomize build deploy/overlays/dev | kubectl apply -f -
kubectl apply -k deploy/overlays/dev
這兩條指令的執行效果是一樣的,在
kubectl v1.14.0
以上的版本中,已經內建了 kustomize ,可以直接使用
kubectl
進行部署。
結語
這裡隻是對 kustomize 在 CI/CD 中簡單應用的展示,隻是一種比較簡單和基礎的使用,真正的 CI 流程要比這個複雜的多,這裡隻是為了示範 kustomize 的使用而臨時搭建的。而 kustomize 還有很多黑科技的用法,将會在後續的文章中介紹。