1、概述
? 在前面的章節(jié)中我們已經(jīng)演示了不少案例與各種組件的介紹與使用,我們也實戰(zhàn)搭建了項目。通過K8S的幫助,我們可以很方便的部署項目,但還不是很完美。如果我們部署的是自己的項目,而我們的項目又是要經(jīng)常改動的,這就意味著我們需要經(jīng)常進行 打包、上傳、重啟、測試等,這些都是重復性的工作,一次兩次還好,次數(shù)多了也煩人。所以下面要講的 CI/CD 就是來幫我們解放雙手,擺脫這些重復性的工作!
1.1、CI/CD是什么?
CI/CD 是一種通過在應用開發(fā)階段引入 自動化 來頻繁向客戶交付應用的方法。
CI/CD 的核心概念是持續(xù)集成、持續(xù)交付和持續(xù)部署。
CI/CD 主要針對在集成新代碼時所引發(fā)的問題。
CI/CD 可讓持續(xù)自動化和持續(xù)監(jiān)控貫穿于應用的整個生命周期(從集成和測試階段,到交付和部署)。
這些關聯(lián)的事務通常被統(tǒng)稱為 “CI/CD 管道”,由開發(fā)和運維團隊以敏捷方式協(xié)同支持。
1.2、 CI 和 CD 有什么區(qū)別?
- CI/CD 中的 “CI” 始終指持續(xù)集成,它屬于開發(fā)人員的自動化流程。
- 成功的 CI 意味著應用代碼的新更改會定期構建、測試并合并到共享存儲庫中。
- 該解決方案可以解決在一次開發(fā)中有太多應用分支,從而導致相互沖突的問題。
- CI/CD 中的“CD”指的是持續(xù)交付和/或持續(xù)部署,這些相關概念有時會交叉使用。
- 兩者都事關管道后續(xù)階段的自動化,但它們有時也會單獨使用,用于說明自動化程度。
更多概念可以到
紅帽看官方介紹: https://www.redhat.com/zh/topics/devops/what-is-ci-cd
下面這張圖就相對完整的介紹了本章節(jié)要進行的工作:
- 開發(fā)手動提交代碼到git倉庫
- 自動拉取代碼
- 自動進行Maven構建、代碼檢查、單元測試
- 這個步驟在生產(chǎn)環(huán)境一般不會做自動構建,因為公司可能進行代碼檢查,確認無誤后由QA手動進行部署
- 本章節(jié)只進行Maven構建,代碼檢查和單元測試需要集成其他組件,讀者可以自行了解
- 自動build鏡像、上傳鏡像至鏡像倉庫
- 自動拉取鏡像進行部署

2、環(huán)境準備
- 準備一個項目
- 準備一個 Git 倉庫
- 可以是自己搭建的也可以是GitHub或者碼云都可以
- 準備一個鏡像倉庫
- 這里使用阿里云的鏡像倉庫
- 準備一個安裝了 Kubernetes 的機器
- 直接使用之前搭建好的 K8S 集群
- 安裝 Java
- 安裝 Maven
- 安裝 Git
- 安裝 Jenkins
- Jenkins必須在k8s集群中,因為后面需要在jenkins的目錄下創(chuàng)建文件執(zhí)行K8S的命令
- 其他環(huán)境在這臺機器安裝的原因在于Jenkins需要依賴這些環(huán)境
2.1、環(huán)境搭建
-
安裝 Java
下載 Java 安裝包上傳并解壓到服務器
-
配置環(huán)境變量
- 采用 profile.d 目錄設置環(huán)境變量,好處在于想刪掉該環(huán)境可以直接刪除文件,無需修改配置文件
# 1、配置環(huán)境變量 [root@worker01-kubeadm-k8s profile.d]# pwd /etc/profile.d [root@worker01-kubeadm-k8s profile.d]# vi java.sh export JAVA_HOME=/root/develop/java/jdk1.8.0_181 export JRE_HOM=$JAVA_HOME/jre export CLASSPATH=$JAVA_HOME/lib/ export PATH=$PATH:$JAVA_HOME/bin # 2、賦予權限 [root@worker01-kubeadm-k8s profile.d]# chmod 755 ./java.sh # 3、編譯文件 [root@worker01-kubeadm-k8s profile.d]# source ./java.sh # 4、測試 [root@worker01-kubeadm-k8s profile.d]# java -version java version "1.8.0_181" Java(TM) SE Runtime Environment (build 1.8.0_181-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
-
安裝 Maven
下載 Maven 安裝包上傳并解壓到服務器
-
配置環(huán)境變量
# 1、配置環(huán)境變量 [root@worker01-kubeadm-k8s profile.d]# vi mvn.sh export MAVEN_HOME=/root/develop/maven/apache-maven-3.6.3 export PATH=$PATH:$MAVEN_HOME/bin # 2、賦予權限 [root@worker01-kubeadm-k8s profile.d]# chmod 755 ./mvn.sh # 3、編譯文件 [root@worker01-kubeadm-k8s profile.d]# source ./mvn.sh # 4、測試 [root@worker01-kubeadm-k8s profile.d]# mvn -v Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f) Maven home: /root/develop/maven/apache-maven-3.6.3 Java version: 1.8.0_181, vendor: Oracle Corporation, runtime: /root/develop/java/jdk1.8.0_181/jre Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "3.10.0-1062.18.1.el7.x86_64", arch: "amd64", family: "unix" -
配置本地倉庫路徑、阿里云鏡像
# 1、本地倉庫路徑,改成自己的 <localRepository>/root/develop/maven/repo</localRepository> # 2、配置阿里云鏡像 <mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共倉庫</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>
-
安裝 Git
-
下載安裝
# 1、安裝 Git [root@worker01-kubeadm-k8s ~]# yum install git # 2、測試 [root@worker01-kubeadm-k8s ~]# git --version git version 1.8.3.1
+ 配置賬號 ```ruby [root@worker01-kubeadm-k8s ~]# git config --global user.name "Sunny" [root@worker01-kubeadm-k8s ~]# git config --global user.email "yzy_zhaoyang@163.com" [root@worker01-kubeadm-k8s ~]# ssh-keygen -t rsa -C "yzy_zhaoyang@163.com" # 出現(xiàn)需要輸入密碼的地方可以設置自己的ssh密碼, 也可以直接回車表示不設置密碼 Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. # 這里的路徑文件指的是公鑰,我們要打開這個文件將公鑰填到 Git 倉庫 Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: ae:ca:9b:84:t5:3e:b7:as:98:51:d1:77:31:34:0e:tt yzy_zhaoyang@163.com The key's randomart image is: +--[ RSA 2048]----+ | ...o | | . E. o | |o .. o . | |.o . o | |. . S | | .. . | | .... . | |.o=+.. . | |.=+o*o. | +-----------------+ -
2.2、準備項目

-
上傳到 Git 倉庫
image.png
2.3、搭建 Jenkins
-
前情提要
Jenkins 官網(wǎng):https://jenkins.io/
入門指南:https://jenkins.io/zh/doc/pipeline/tour/getting-started/
下載并上傳 Jenkins 到服務器
-
啟動 Jenkins
#以后臺啟動方式啟動 Jenkins,設置端口為 8088 [root@worker01-kubeadm-k8s jenkins]# [root@sunny jenkins]# nohup java -jar jenkins.war --httpPort=8088 & # 查看啟動日志 [root@worker01-kubeadm-k8s jenkins]# tail -f nohup.out Running from: /root/jenkins/jenkins.war webroot: $user.home/.jenkins 2020-04-16 15:20:49.849+0000 [id=1] INFO org.eclipse.jetty.util.log.Log#initialized: Logging initialized @753ms to org.eclipse.jetty.util.log.JavaUtilLog # ... 省略 ... ************************************************************* ************************************************************* ************************************************************* Jenkins initial setup is required. An admin user has been created and a password generated. Please use the following password to proceed to installation: # 這是進入 Jenkins 管理頁面所需要的密碼 f9025b52a4824997b09cb62d5c89f7cc # 這是存放密碼的文件 This may also be found at: /root/.jenkins/secrets/initialAdminPassword ************************************************************* ************************************************************* *************************************************************

2.3.1、配置 Jenkins
-
安裝推薦的插件
image.png
等待安裝即可,需要的時間比較久
也可以先點推薦安裝,然后刷新頁面選擇跳過安裝,之后手動下載插件安裝,這樣會更快
如果跳過,先截圖保存一下推薦插件的列表,后面手動安裝要去搜索的
-
創(chuàng)建用戶
username: sunny password: sunnyimage.png
-
安裝插件
這里說的是推薦插件安裝完后還需要安裝的一些插件,如果你選擇了跳過安裝,那要先記好它推薦了哪些插件,有些插件是必要的
- 中文插件
- Locale
- Localization: Chinese (Simplified)
- Localization Support
- git插件
- GitHub / Gitee
- Gitlab Hook
- Gitlab Plugin
- 中文插件
-
配置Java、Maven、Git路徑
Manage Jenkins — Global Tool Configuration
-
配置機器中的路徑
image.png
2.3.2、鏡像倉庫與Kubernetes集群
鏡像倉庫采用國內(nèi)的阿里云鏡像倉庫
Kubernetes 集群直接采用我們之前章節(jié)中已經(jīng)搭建好的 Kubernetes 集群即可。
3、Pipeline任務
我們一個步驟一個步驟的演示,從最開始的拉取代碼,慢慢延伸到最終的CICD!
3.1 拉取項目代碼
Jenkins要實現(xiàn)自動拉取代碼,需要安裝Git相關插件,以及要到Git倉庫去進行一些配置,插件之前都已經(jīng)安裝了,接下來就演示一下Jenkins的配置。
-
創(chuàng)建任務
image.png
-
創(chuàng)建流水線任務
image.png
-
編寫pipeline
注意這里要勾選上,保存webhook的鏈接,后面配置自動拉取時要用到
image.png

node {
// Pull
stage('Pull') { //stage表示一個任務
//這里是任務的內(nèi)容
//因為我們的機器已經(jīng)生成了秘鑰且與Gieee進行了綁定,所以無需輸入賬號密碼就可以進行拉取代碼
git 'https://gitee.com/suny95/springboot-demo-k8s.git'
}
}
配置完成后點擊保存
-
構建任務
image.png
構建完成后會顯示綠色,構建失敗是紅色,可以去查看錯誤信息

這里是Jenkins工作目錄:/root/.jenkins/workspace目錄
代碼是拉取到這個目錄下的
# Jenkins工作目錄
[root@worker01-kubeadm-k8s workspace]# pwd
/root/.jenkins/workspace
[root@worker01-kubeadm-k8s workspace]# ll
total 0
drwxr-xr-x. 4 root root 62 Apr 18 14:37 springboot-k8s-task
# 新建的任務目錄
[root@worker01-kubeadm-k8s workspace]# cd springboot-k8s-task/
[root@worker01-kubeadm-k8s springboot-k8s-task]# ll
total 4
-rw-r--r--. 1 root root 1277 Apr 18 14:37 pom.xml
drwxr-xr-x. 3 root root 18 Apr 18 14:37 src
3.2 Maven自動編譯
修改之前編寫好的流水線任務,增加一個Stage用來做Maven自動編譯
-
修改Pipeline腳本內(nèi)容
node { // Pull stage('Pull') { //stage表示一個任務 //這里是任務的內(nèi)容 //因為我們的機器已經(jīng)生成了秘鑰且與Gieee進行了綁定,所以無需輸入賬號密碼就可以進行拉取代碼 git 'https://gitee.com/suny95/springboot-demo-k8s.git' } //Maven stage('AutoCompile') { sh "mvn clean package" } } -
構建任務
開始構建任務后,可以通過Console Output監(jiān)控當前任務執(zhí)行情況
image.png

# 再次查看目錄,發(fā)現(xiàn)已經(jīng)成功編譯出 target 目錄了
[root@worker01-kubeadm-k8s springboot-k8s-task]# ll
total 4
-rw-r--r--. 1 root root 1277 Apr 18 14:37 pom.xml
drwxr-xr-x. 3 root root 18 Apr 18 14:37 src
drwxr-xr-x. 6 root root 181 Apr 18 14:56 target
到這里為止,手動構建的方式已經(jīng)完成, 下面將要開始配置自動構建
3.3 Git Push 觸發(fā) Jenkins 自動構建
當用戶進行git push提交代碼到 GitHub / Git EE 時,能夠通知 jenkins 自動構建
注意: Jenkins 的 ip 一定要是 Git EE 能夠訪問到的地址
我這里由于是本地搭建的虛擬機,就不做演示了,百度搜一下有很多的教程可以參考
3.4 build 與 push 鏡像
經(jīng)過前面的演示,現(xiàn)在已經(jīng)可以獲取到代碼,并且用maven進行構建了,最終拿到一個target/xxx.jar
現(xiàn)在我們要演示Docker的鏡像構建與Push鏡像到鏡像倉庫!
-
準備執(zhí)行文件
-
到 Jenkins 的工作目錄
- cd /root/.jenkins/workspace
-
創(chuàng)建 .sh 執(zhí)行文件
# 創(chuàng)建專門存放腳本的目錄 [root@worker01-kubeadm-k8s workspace]# mkdir scripts [root@worker01-kubeadm-k8s workspace]# cd scripts/ # 編寫執(zhí)行文件 [root@worker01-kubeadm-k8s scripts]# vi springboot-demo-k8s-build-image.sh # ================== 執(zhí)行文件內(nèi)容 ====================== # 進入到springboot-k8s-task目錄 cd ../springboot-k8s-task # 編寫Dockerfile文件, 這里也可以先在項目里寫好 cat <<EOF > Dockerfile FROM openjdk:8-jre-alpine COPY target/springboot-demo-0.0.1-SNAPSHOT.jar /springboot-demo.jar ENTRYPOINT ["java","-jar","/springboot-demo.jar"] EOF echo "Dockerfile created successfully!" # 基于指定目錄下的Dockerfile構建鏡像 # 注意 zhao_yang 這個命名空間是公開的,如果是私有的,還需要配置K8S的認證 docker build -t registry.cn-hangzhou.aliyuncs.com/zhao_yang/springboot-demo-k8s:v1.0 . # 登錄docker賬號 # 注意: 如果密碼不能開放的話,可以先手動在機器上登錄一次,那這里就無需再次登錄了 docker login --username=用戶名 --password=密碼 registry.cn-shanghai.aliyuncs.com # push鏡像 docker push registry.cn-hangzhou.aliyuncs.com/zhao_yang/springboot-demo-k8s:v1.0 # ================== 執(zhí)行文件內(nèi)容 ====================== # 增加執(zhí)行權限 [root@worker01-kubeadm-k8s scripts]# chmod +x ./springboot-demo-k8s-build-image.sh
-
-
修改任務的Pipeline腳本
node { // Pull stage('Pull') { //stage表示一個任務 //這里是任務的內(nèi)容 //因為我們的機器已經(jīng)生成了秘鑰且與Gieee進行了綁定,所以無需輸入賬號密碼就可以進行拉取代碼 git 'https://gitee.com/suny95/springboot-demo-k8s.git' } //Maven stage('AutoCompile') { sh "mvn clean package" } //增加任務,執(zhí)行腳本文件 stage('Build And Push Image') { sh "/root/.jenkins/workspace/scripts/springboot-demo-k8s-build-image.sh" } } -
構建任務,監(jiān)控輸出
image.pngimage.png
build 鏡像與 push 鏡像至鏡像倉庫 都已成功!!!
3.1.5 Kubernetes 拉取鏡像運行
這個過程需要提前準備的也就是image鏡像和ingress,image剛才我們都已經(jīng)上傳到阿里云鏡像倉庫了,ingress我們在之前也準備過了,如果沒有ingress環(huán)境的,可以去看前面的 kubernetes 網(wǎng)絡模型 ,里面有安裝ingress的流程!
-
編寫 YAML 文件
YAML文件可以寫到項目中,也可以直接在機器上創(chuàng)建
- vi /root/.jenkins/workspace/scripts/springboot-demo-k8s.yaml
# 以Deployment部署Pod apiVersion: apps/v1 kind: Deployment metadata: name: springboot-demo-k8s spec: selector: matchLabels: app: springboot-demo-k8s replicas: 1 template: metadata: labels: app: springboot-demo-k8s spec: containers: - name: springboot-demo-k8s image: registry.cn-hangzhou.aliyuncs.com/zhao_yang/springboot-demo-k8s:v1.0 ports: - containerPort: 8080 --- # 創(chuàng)建Pod的Service apiVersion: v1 kind: Service metadata: name: springboot-demo-k8s spec: ports: - port: 80 protocol: TCP targetPort: 8080 selector: app: springboot-demo-k8s --- # 創(chuàng)建Ingress,定義訪問規(guī)則 apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: springboot-demo-k8s spec: rules: - host: springboot.sunny.com http: paths: - path: / backend: serviceName: springboot-demo-k8s servicePort: 80 -
編寫 .sh 執(zhí)行文件
[root@worker01-kubeadm-k8s scripts]# vi /root/.jenkins/workspace/scripts/k8s-deploy-springboot-demo.sh # ================== YAML文件內(nèi)容 ============ kubectl delete -f /root/.jenkins/workspace/scripts/springboot-demo-k8s.yaml kubectl apply -f /root/.jenkins/workspace/scripts/springboot-demo-k8s.yaml echo "k8s deploy success!" # ================== YAML文件內(nèi)容 ============ [root@worker01-kubeadm-k8s scripts]# chmod +x k8s-deploy-springboot-demo.sh -
修改Pipeline
node { // Pull stage('Pull') { //stage表示一個任務 //這里是任務的內(nèi)容 //因為我們的機器已經(jīng)生成了秘鑰且與Gieee進行了綁定,所以無需輸入賬號密碼就可以進行拉取代碼 git 'https://gitee.com/suny95/springboot-demo-k8s.git' } //Maven stage('AutoCompile') { sh "mvn clean package" } //build push stage('Build And Push Image') { sh "/root/.jenkins/workspace/scripts/springboot-demo-k8s-build-image.sh" } //k8s stage('K8S Deploy') { sh "/root/.jenkins/workspace/scripts/k8s-deploy-springboot-demo.sh" } } -
構建任務并監(jiān)控輸出
image.png
發(fā)現(xiàn)出現(xiàn)異常了,這個問題其實是因為我們選擇的機器在 K8S 集群中不是 Master 節(jié)點,它沒有執(zhí)行kubectl 命令的權限,我們需要配置一下!
-
復制 .kube 文件目錄到 Worker01 節(jié)點
[root@master-kubeadm-k8s .kube]# pwd /root/.kube # 這里的 config 是權限認證的文件 [root@master-kubeadm-k8s .kube]# ll total 12 drwxr-xr-x. 3 root root 23 Mar 24 14:32 cache -rw-------. 1 root root 5454 Mar 24 14:30 config drwxr-xr-x. 3 root root 4096 Apr 4 08:59 http-cacheimage.png
```ruby
[root@worker01-kubeadm-k8s ~]# mkdir .kube
[root@worker01-kubeadm-k8s ~]# cd .kube/
# 將 Master 節(jié)點中config文件內(nèi)容復制進去即可
[root@worker01-kubeadm-k8s .kube]# vi config
[root@worker01-kubeadm-k8s .kube]# ll
total 8
-rw-r--r--. 1 root root 5454 Apr 19 09:45 config
```
-
重新構建并監(jiān)控
image.png
-
測試
# pod 運行成功 [root@worker01-kubeadm-k8s scripts]# kubectl get pods NAME READY STATUS RESTARTS AGE springboot-demo-k8s-79c867fd58-ts2f7 1/1 Running 0 5m53s # service 也創(chuàng)建成功 [root@worker01-kubeadm-k8s scripts]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 25d springboot-demo-k8s ClusterIP 10.99.138.171 <none> 80/TCP 6m46s # ingress 也在 [root@worker01-kubeadm-k8s scripts]# kubectl get ingress NAME HOSTS ADDRESS PORTS AGE springboot-demo-k8s springboot.sunny.com 80 10m # 訪問 Service IP + 路徑, 成功訪問到結(jié)果 [root@worker01-kubeadm-k8s scripts]# curl 10.99.138.171/k8s hello K8S- 通過Ingress訪問也成功

由于機器問題,我沒辦法演示 Git Push 就觸發(fā)自動構建的任務,大家如果有公網(wǎng)的機器的話,可以去嘗試弄一下!













