朋友的真實(shí)操作流程妹萨,使用 Jenkins 和 Kubernetes 完成持續(xù)集成和持續(xù)部署年枕,有搭建,有入門乎完,手把手教學(xué)文檔熏兄,干得擰不出水來(lái),分享一波树姨。
本文作者:孫丹丹摩桶,女,單身 帽揪,DevOps 運(yùn)維工程師硝清,CKA 認(rèn)證。就職于某容器云平臺(tái)服務(wù)公司转晰,負(fù)責(zé)國(guó)內(nèi)多家知名企業(yè) DevOps 運(yùn)維交付芦拿。
安裝 Jenkins
啟動(dòng) Jenkins 容器
docker run -d -u root -v /workspace/jenkins-home/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock -v "$HOME":/home -p 8080:8080 -p 50000:50000 jenkinsci/blueocean
參數(shù) | 說(shuō)明 |
---|---|
-d |
d 指 daemon士飒,后臺(tái)啟動(dòng) |
-u |
指定運(yùn)行用戶 |
-v |
-v /workspace/jenkins-home:/var/jenkins_home hostDir:containerDir 表示將容器中 jenkins_home 映射到宿主機(jī) jenkins-home 目錄 |
-p |
-p 8080:8080 hostPort:containerPort |
檢查 Jenkins 服務(wù)狀態(tài)
docker ps | grep jenkins
啟動(dòng)成功后,就可以通過(guò) ip:port 在瀏覽器上訪問(wèn)了蔗崎。ip 為 docker 所在機(jī)器的 ip, port 為 Jenkins 容器映射的宿主機(jī)端口酵幕。
配置 Jenkins
Jenkins 啟動(dòng)成功后,需要執(zhí)行一些快速的 "一次性" 步驟蚁趁。當(dāng)你第一次訪問(wèn)一個(gè)新的 Jenkins 實(shí)例時(shí), 要求你使用自動(dòng)生成的密碼對(duì)其進(jìn)行解鎖裙盾。密碼為 Jenkins 所在容器的 /var/jenkins_home/secrets/initialAdminPassword 的內(nèi)容:
docker exec -it <jenkins_container> bash -c "cat /var/jenkins_home/secrets/initialAdminPassword"
或者用 K8S 命令 kubectl
kubectl exec -it <jenkins_container> bash -c "cat /var/jenkins_home/secrets/initialAdminPassword"
在 Unlock Jenkins 頁(yè)面, 粘貼該密碼到 Administrator password 字段并點(diǎn)擊 Continue。解鎖 Jenkins 后他嫡,插件安裝頁(yè)面出現(xiàn)番官,點(diǎn)擊 Install suggested plugins 即可。
這個(gè)過(guò)程會(huì)耗時(shí)一段時(shí)間钢属。
創(chuàng)建第一個(gè)管理員用戶徘熔,可以填寫,也可以跳過(guò)淆党,直接使用 admin 賬戶繼續(xù)酷师。
這邊我選擇了跳過(guò),點(diǎn)擊開(kāi)始使用 Jenkins染乌,就可以使用 Jenkins 了山孔。
實(shí)現(xiàn) Java 應(yīng)用持續(xù)集成和持續(xù)發(fā)布
Fork 和 Clone GitHub 示例倉(cāng)庫(kù)
- 登錄 GitHub 賬號(hào):https://github.com
- 上傳代碼到 GitHub 代碼倉(cāng)庫(kù)中,或 Fork 到你的 GitHub 倉(cāng)庫(kù)中荷憋,演示代碼 prometheus-test-demo台颠,地址為 https://github.com/0820sdd/prometheus-test-demo
- 將你的 GitHub 賬戶中的 prometheus-test-demo 倉(cāng)庫(kù) Clone 到本地機(jī)器:
a. 打開(kāi)一個(gè)終端/命令提示符,并且進(jìn)入正確的目錄路徑: Mac OS 系統(tǒng)路徑為/Users/<your-username>/Documents/GitHub/
Linux 系統(tǒng)路徑為/home/<your-username>/GitHub/
Windows 系統(tǒng)路徑為C:\Users\<your-username>\Documents\GitHub\
(推薦使用 Git bash 命令行勒庄,而不是通常的 Microsoft 命令提示符)
b. 運(yùn)行以下命令完成倉(cāng)庫(kù)的 clone:git clone https://github.com/YOUR-GITHUB-ACCOUNT-NAME/simple-java-maven-app
其中YOUR-GITHUB-ACCOUNT-NAME
是你的 GitHub 賬戶的名稱串前。
在 Jenkins 中創(chuàng)建流水線
登錄 Jenkins,點(diǎn)擊頁(yè)面創(chuàng)建一個(gè)新任務(wù)实蔽。若是你無(wú)法看見(jiàn)該內(nèi)容荡碾,點(diǎn)擊左上方的新建 item。
為新建的流水線項(xiàng)目指定名稱(例如 prometheus-test-demo)局装,選擇流水線坛吁,點(diǎn)擊確定。
安裝 K8S 插件
登錄 Jenkins铐尚,系統(tǒng)管理→ 插件管理 → 搜索 kubernetes拨脉,選擇第二個(gè) Kubernetes,點(diǎn)擊 安裝塑径,安裝完成后重啟 Jenkins 。
對(duì)接 K8S 集群
申請(qǐng) K8S 憑據(jù)
因?yàn)?Jenkins 服務(wù)器在 kubernetes 集群之外填具,所以我們準(zhǔn)備以下文件才能從外面連接到 kubernetes 集群统舀。
登錄 Jenkins匆骗,點(diǎn)擊右上角「用戶」 → 左下角「憑據(jù)」:
然后點(diǎn)擊 Jenkins,選擇全局憑據(jù)(Unrestricted)
添加憑據(jù)誉简,類型選擇 X.509 Client Certificate
- Client Key: .kube/config文件中 client-key 對(duì)應(yīng)的 key 文件
- Client Certificate: .kube/config文件中 client-certificate 對(duì)應(yīng)的 crt 或是 pem 文件
- Server CA Certificate:.kube/config 文件中 certificate-authority 對(duì)應(yīng)的 crt 或是 pem 文件碉就,K8S 的最高權(quán)限證書(shū)
- ID:可不填寫,默認(rèn)會(huì)自動(dòng)生成一串字符串闷串,也可以自行設(shè)置
- 描述:描述下這個(gè)憑據(jù)的作用瓮钥,比如這個(gè)可以寫 對(duì)接 K8S 集群憑據(jù)
填寫完畢,點(diǎn)擊確定烹吵。
配置 K8S 集群的對(duì)接
登錄 Jenkins碉熄,點(diǎn)擊 系統(tǒng)管理 → 系統(tǒng)配置 → 滑動(dòng)到頁(yè)面最下面
點(diǎn)擊 a separate configuration page:
- Kubernetes 地址:kubernetes服務(wù)地址,也就是 apiserver 的地址肋拔,一般是master 節(jié)點(diǎn) NodeIP+6443 端口
- Kubernetes 服務(wù)證書(shū) key:kube-ca.crt 文件的內(nèi)容
- 憑據(jù):剛才創(chuàng)建的 certificate 憑據(jù)
- Jenkins 地址:Agent 連接 Jenkins Master 的地址
其他都使用默認(rèn)配置锈津,點(diǎn)擊連接測(cè)試,連接測(cè)試成功凉蜂,點(diǎn)擊 Save 存儲(chǔ)琼梆。
K8S pod template 配置
Jenkins 的 kubernetes-plugin 在執(zhí)行構(gòu)建時(shí)會(huì)在 kubernetes 集群中自動(dòng)創(chuàng)建一個(gè) Pod,并在 Pod 內(nèi)部創(chuàng)建一個(gè)名為 jnlp 的容器窿吩,該容器會(huì)連接 Jenkins 并運(yùn)行 Agent 程序茎杂,形成一個(gè) Jenkins 的 Master 和 Slave 架構(gòu),然后 Slave 會(huì)執(zhí)行構(gòu)建腳本進(jìn)行構(gòu)建纫雁,但如果構(gòu)建內(nèi)容是要?jiǎng)?chuàng)建 Docker Image 就要實(shí)現(xiàn) Docker In Docker 方案(在 Docker 里運(yùn)行 Docker)煌往,如果要在集群集群內(nèi)部進(jìn)行部署操作可以使用 kubectl 執(zhí)行命令,要解決 kubectl 的安裝和權(quán)限分配問(wèn)題先较。
為了方便配置一個(gè) Pod Templates携冤,在配置 kubernetes 連接內(nèi)容的下面,這里的模板只是模板(與類一樣使用時(shí)還要實(shí)例化過(guò)程)闲勺,名稱和標(biāo)簽列表不要以為是 Pod 的 name 和 label曾棕,這里的名稱和標(biāo)簽列表只是 Jenkins 查找選擇模板時(shí)使用的,Jenkins 自動(dòng)創(chuàng)建 Pod 的 name 是項(xiàng)目名稱+隨機(jī)字母的組合菜循,所以我們填寫 jenkins-slave翘地,命名空間填寫對(duì)應(yīng)的 namespace。
這邊要注意癌幕,添加 2 個(gè) container衙耕,第一個(gè),Pod 內(nèi)添加一個(gè)容器名稱是 jnlp勺远,Docker 鏡像填寫:jenkins/jnlp-slave:4.3-7橙喘,后面的使用默認(rèn)的即可,然后在添加一個(gè) container胶逢,容器名稱是 jnlp-kubectl厅瞎,是這個(gè)容器里面有 kubectl 的命令饰潜,鏡像名稱填寫 harbor.edu.cn/library/centos-docker-kubectl:v1.0
,下面增加了 Host Path Volume:/var/run/docker.sock和簸、/root/.kube/彭雾、/etc/kubernetes/pki,這邊便是為了 jenkins-slave 下有足夠的權(quán)限可以執(zhí)行 docker 及 kubectl 部署到 k8s 集群的權(quán)限锁保,因?yàn)?jenkins-slave pod 有可能會(huì)被調(diào)度到任一 worker 節(jié)點(diǎn)薯酝,所以所有的 worker 節(jié)點(diǎn)上都必須有 /root/.kube/、/etc/kubernetes/pki爽柒,配置好之后點(diǎn)擊保存吴菠。
Jenkins pipeline 說(shuō)明
Pipeline,簡(jiǎn)單來(lái)說(shuō)霉赡,就是一套運(yùn)行在 Jenkins 上的工作流框架橄务,將原來(lái)獨(dú)立運(yùn)行于單個(gè)或者多個(gè)節(jié)點(diǎn)的任務(wù)連接起來(lái),實(shí)現(xiàn)單個(gè)任務(wù)難以完成的復(fù)雜流程編排和可視化的工作穴亏。
Jenkins Pipeline 有幾個(gè)核心概念:
- Node:節(jié)點(diǎn)蜂挪,一個(gè) Node 就是一個(gè) Jenkins 節(jié)點(diǎn),Master 或者 Agent嗓化,是執(zhí)行 Step 的具體運(yùn)行環(huán)境棠涮,比如我們之前動(dòng)態(tài)運(yùn)行的 Jenkins Slave 就是一個(gè) Node 節(jié)點(diǎn)
- Stage:階段,一個(gè) Pipeline 可以劃分為若干個(gè) Stage刺覆,每個(gè) Stage 代表一組操作严肪,比如:Build、Test谦屑、Deploy驳糯,Stage 是一個(gè)邏輯分組的概念,可以跨多個(gè) Node
- Step:步驟氢橙,Step 是最基本的操作單元酝枢,可以是打印一句話,也可以是構(gòu)建一個(gè) Docker 鏡像悍手,由各類 Jenkins 插件提供帘睦,比如命令:sh 'make',就相當(dāng)于我們平時(shí) shell 終端中執(zhí)行 make 命令一樣坦康。
Pipeline的使用:
- Pipeline 腳本是由 Groovy 語(yǔ)言實(shí)現(xiàn)的
- Pipeline 支持兩種語(yǔ)法:Declarative(聲明式)和 Scripted Pipeline(腳本式)語(yǔ)法
- Pipeline 也有兩種創(chuàng)建方法:可以直接在 Jenkins 的 Web UI 界面中輸入腳本竣付;也可以通過(guò)創(chuàng)建一個(gè) Jenkinsfile 腳本文件放入項(xiàng)目源碼庫(kù)中
- 一般我們都推薦在 Jenkins 中直接從源代碼控制(SCMD)中直接載入 Jenkinsfile Pipeline 這種方法,但是本次為了更直觀的展示滞欠,我們?cè)?Web UI 界面中輸入腳本
Jenkins pipeline 入門
創(chuàng)建并運(yùn)行 pipeline
- 進(jìn)入到 Jenkins 首頁(yè)古胆,點(diǎn)擊項(xiàng)目 prometheus-test-demo,點(diǎn)擊左側(cè) 配置
- 點(diǎn)擊頁(yè)面頂部的 Pipeline 選項(xiàng)卡筛璧,向下滾動(dòng)到 Pipeline 部分
- 在 定義 域中逸绎,選擇 Pipeline script 選項(xiàng)
node {
stage('Clone') {
echo "1.Clone Stage"
}
stage('Test') {
echo "2.Test Stage"
}
stage('Build') {
echo "3.Build Stage"
}
stage('Deploy') {
echo "4. Deploy Stage"
}
}
點(diǎn)擊保存妖滔,切換到 Jenkins 頁(yè)面,點(diǎn)擊左側(cè)的 打開(kāi) Blue Ocean 進(jìn)入Jenkins的Blue Ocean界面桶良,進(jìn)入到 相應(yīng)的項(xiàng)目下,點(diǎn)擊 運(yùn)行 沮翔。
也可以在 Jenkins prometheus-test-demo 項(xiàng)目下陨帆,點(diǎn)擊左側(cè)菜單 立即構(gòu)建,然后點(diǎn)擊正在構(gòu)建的任務(wù)采蚀,就可以看到 Console Output:
在 Slave 中運(yùn)行 Pipeline
上面對(duì) Jenkins 的 Pipeline 做了簡(jiǎn)單的測(cè)試疲牵,但是其并未在我們的 Slave中運(yùn)行,如果要在 Slave 中運(yùn)行榆鼠,其就要使用我們?cè)趯?duì)接 K8S 集群時(shí) Pod Template 指定的標(biāo)簽列表 纲爸,點(diǎn)擊進(jìn) prometheus-test-demo 項(xiàng)目,點(diǎn)擊左側(cè)菜單 配置妆够,進(jìn)入到 pipeline scripts 部分识啦,修改 pipeline scripts 如下:
node('slave') {
stage('Clone') {
echo "1.Clone Stage"
}
stage('Test') {
echo "2.Test Stage"
}
stage('Build') {
echo "3.Build Stage"
}
stage('Deploy') {
echo "4. Deploy Stage"
}
}
點(diǎn)擊 立即構(gòu)建,同時(shí)可以登錄到k8s集群神妹,使用 kubectl get po -w 可以看到 jenkins-slave pod 的生命周期颓哮,就是我們開(kāi)始構(gòu)建這個(gè)任務(wù),選擇了使用 jenkins slave鸵荠,所以在執(zhí)行過(guò)程中jenkins-slave就會(huì)自動(dòng)創(chuàng)建冕茅,任務(wù)執(zhí)行完成,jenkins-slave 對(duì)應(yīng)的pod會(huì)自動(dòng)回收:
在構(gòu)建日志里我們也可以看到 jenkins 啟動(dòng)了 jenkins-slave-dj3vc pod 進(jìn)行這個(gè)任務(wù)的執(zhí)行蛹找,也和上面的 pod 名稱對(duì)應(yīng)起來(lái)了姨伤。
完整 pipeline 示例
部署應(yīng)用的流程如下:
- 拉取 Github 代碼
- maven 打包
- 編寫 Dockerfile
- 構(gòu)建打包 Docker 鏡像
- 推送 Docker 鏡像到倉(cāng)庫(kù)
- 編寫 Kubernetes YAML 文件
- 更改 YAML 文件中 Docker 鏡像 TAG
- 利用 kubectl 工具部署應(yīng)用
最終的 Pipeline 腳本如下:
pipeline {
agent none
stages {
stage('Clone Code') {
agent {
label 'master'
}
steps {
echo "1.Git Clone Code"
git url: "https://github.com/0820sdd/prometheus-test-demo.git"
}
}
stage('Maven Build') {
agent {
docker {
image 'maven:latest'
args '-v /root/.m2:/root/.m2'
}
}
steps {
echo "2.Maven Build Stage"
sh 'mvn -B clean package -Dmaven.test.skip=true'
}
}
stage('Image Build') {
agent {
label 'master'
}
steps {
echo "3.Image Build Stage"
sh 'docker build -f Dockerfile --build-arg jar_name=target/prometheus-test-demo-0.0.1-SNAPSHOT.jar -t prometheus-test-demo:${BUILD_ID} . '
sh 'docker tag prometheus-test-demo:${BUILD_ID} harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}'
}
}
stage('Push') {
agent {
label 'master'
}
steps {
echo "4.Push Docker Image Stage"
sh "docker login --username=admin harbor.edu.cn -p Harbor12345"
sh "docker push harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}"
}
}
}
}
node('slave') {
container('jnlp-kubectl') {
stage('Clone YAML') {
echo "5. Git Clone YAML To Slave"
git url: "https://github.com/0820sdd/prometheus-test-demo.git"
}
stage('YAML') {
echo "6. Change YAML File Stage"
sh 'sed -i "s#{VERSION}#${BUILD_ID}#g" ./jenkins/scripts/prometheus-test-demo.yaml'
}
stage('Deploy') {
echo "7. Deploy To K8s Stage"
sh 'kubectl apply -f ./jenkins/scripts/prometheus-test-demo.yaml'
}
}
}
注意,prometheus-test-demo.yaml 可放在 GitHub 的 prometheus-test-demo 倉(cāng)庫(kù)里庸疾,也可以另外新建一個(gè)倉(cāng)庫(kù)專門放 YAML 文件乍楚。
下面我們分解講下上面過(guò)程的具體含義:
克隆代碼
stage('Clone to master') {
agent {
label 'master'
}
steps {
echo "1.Git Clone Stage"
git url: "https://github.com/0820sdd/prometheus-test-demo.git"
}
}
這步就是從 GitHub 上拉取代碼,注意這邊的 GitHub 倉(cāng)庫(kù)倉(cāng)庫(kù)比如是 公開(kāi)的彼硫,因?yàn)?private 的需要各種權(quán)限配置炊豪,Jenkins 必須有一個(gè)公網(wǎng) IP 或者是公網(wǎng)域名,但因資源問(wèn)題拧篮,這部分暫時(shí)沒(méi)有辦法實(shí)現(xiàn)词渤。注意,這邊 agent 里面指定運(yùn)行環(huán)境串绩,選擇了 master缺虐,即是這個(gè)步驟在 Jenkins master節(jié)點(diǎn)執(zhí)行。
maven 打包
stage('Maven Build') {
agent {
docker {
image 'maven:latest'
args '-v /root/.m2:/root/.m2'
}
}
steps {
echo "2.Maven Build Stage"
sh 'mvn -B clean package -Dmaven.test.skip=true'
}
}
maven 構(gòu)建礁凡,我們指定了 maven 打包的 agent 是在 Jenkins 所在節(jié)點(diǎn)另起一個(gè) docker 容器高氮,容器的 image 為 maven:latest慧妄,并且使用 -v 參數(shù)把本地的 /root/.m2 掛載到 容器的 /root/.m2 目錄下,下面 steps 的步驟即是在這個(gè) maven 容器里面的具體操作:mvn -B clean package -Dmaven.test.skip=true剪芍。
構(gòu)建鏡像
stage('Image Build') {
agent {
label 'master'
}
steps {
echo "3.Image Build Stage"
sh 'docker build -f Dockerfile --build-arg jar_name=target/prometheus-test-demo-0.0.1-SNAPSHOT.jar -t prometheus-test-demo:${BUILD_ID} . '
sh 'docker tag prometheus-test-demo:${BUILD_ID} harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}'
}
}
maven 構(gòu)建成功塞淹,下一步就是使用 maven build 生成的 prometheus-test-demo-0.0.1-SNAPSHOT.jar 包進(jìn)行 docker build,docker build 的具體命令有2條 bash 命令 組成罪裹,第一步 docker build 使用 -f 指定了 Dockerfile 的文件饱普,使用--build-arg 參數(shù)指定了一些參數(shù),比如上面指定了 jar_name 是 target/prometheus-test-demo-0.0.1-SNAPSHOT.jar状共,最后使用 -t 參數(shù)指定了 docker build 的 image 的名稱及版本號(hào)套耕。第二步就是 使用 docker tag 命令把上一步 docker build 完成的鏡像 打 tag 為 harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID},這步打 tag 的步驟是為了上傳到 harbor 鏡像倉(cāng)庫(kù)峡继,可以隨時(shí)使用冯袍。
推送鏡像
stage('Push') {
agent {
label 'master'
}
steps {
echo "4.Push Docker Image Stage"
sh "docker login --username=admin harbor.edu.cn -p Harbor12345"
sh "docker push harbor.edu.cn/library/prometheus-test-demo:${BUILD_ID}"
}
}
鏡像 build 完成,就可以使用 docker push 命令推送到 harbor.edu.cn 鏡像倉(cāng)庫(kù)碾牌。
拉取鏡像
node('slave') {
container('jnlp-kubectl') {
stage('Clone YAML') {
echo "5. Git Clone YAML To Slave"
git url: "https://github.com/0820sdd/prometheus-test-demo.git"
}
}
}
現(xiàn)在鏡像已經(jīng)打包完成康愤,并推送到了鏡像倉(cāng)庫(kù),后面我們所要做的就是拉取 k8s 編排文件舶吗,這一步和第一步的 拉取代碼實(shí)際是一樣的翘瓮,只不過(guò)上面的拉取代碼是為了 build image,這一步是為了進(jìn)行部署到 K8S裤翩。
注意:這邊指定了運(yùn)行此步驟的節(jié)點(diǎn)是在 Jenkins 的 slave 節(jié)點(diǎn)下的 jnlp-kubectl container 下资盅,這個(gè) slave 是指在配置 對(duì)接 K8S 集群時(shí),在 Pod Template 下指定的 標(biāo)簽列表的名稱踊赠,必須與這個(gè)名稱一致呵扛,不然 jenkins 執(zhí)行過(guò)程中就會(huì)報(bào)找不到對(duì)應(yīng)的 label 。還有這邊指定了 jnlp-kubectl container 筐带,這是因?yàn)?jnlp-kubectl container下有 kubectl 命令今穿,且配置 對(duì)接 K8S 集群時(shí),指定了把宿主機(jī)的 /root/.kube /etc/kubernetes/pki 目錄分別掛載到 container 的 /root/.kube /etc/kubernetes/pki目錄下伦籍,這邊就是 jnlp-kubectl container 可以訪問(wèn) K8S 集群的原因蓝晒。
替換 YAML 文件變量
stage('YAML') {
echo "6. Change YAML File Stage"
sh 'sed -i "s#{VERSION}#${BUILD_ID}#g" ./jenkins/scripts/prometheus-test-demo.yaml'
}
yaml文件拉取完畢,替換其中的變量帖鸦。
部署
stage('Deploy') {
echo "5. Deploy To K8s Stage"
sh 'kubectl apply -f ./jenkins/scripts/prometheus-test-demo.yaml -n default'
}
使用 kubectl 命令部署 prometheus-test-demo 應(yīng)用到 K8S 集群芝薇。