k8s基于Jenkins構建微服務發布平臺流程

搭建整體流程圖

1640409529164.png

具體步驟

標題 url
基于Jenkins構建微服務發布平臺流程(本文) http://www.lxweimin.com/p/43e3f2e3eee1
部署一套完整的K8s高可用集群(二進制) http://www.lxweimin.com/p/d574e1a9675d
Gitlab http://www.lxweimin.com/p/ea10df706808
企業級鏡像倉庫Harbor http://www.lxweimin.com/p/ac4a66bb4709
Helm應用包管理 http://www.lxweimin.com/p/25ca410b1efd
k8s構建容器化微服務項目 http://www.lxweimin.com/p/0f0b2c9ee415
k8s-Prometheus http://www.lxweimin.com/p/8a88f42a4d94
k8s-elk http://www.lxweimin.com/p/96ad780638fa

基于Jenkins構建微服務發布平臺流程

1640310801682.png

配置PV持久化存儲

部署NFS共享服務器

#在所有節點安裝NFS軟件包
yum install nfs-utils -y

#master節點作為NFS共享存儲服務器,并授權網段
[root@k8s-m1 ~]#  vi /etc/exports
/ifs/kubernetes 192.168.153.0/24(rw,no_root_squash)

#啟動nfs
[root@k8s-m1 ~]# systemctl start nfs
[root@k8s-m1 ~]# systemctl enable nfs

#找node掛載測試
[root@k8s-node1 ~]# mount -t nfs 192.168.153.25:/ifs/kubernetes /mnt
[root@k8s-node1 /]# umount /mnt

為Jenkins準備PV

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-jekins
spec:
  capacity:
    storage: 5Gi
  accessModes: ["ReadWriteOnce"]
  nfs:
    path: /ifs/kubernetes/jenkins-data
    server: 192.168.153.25
    
---------------------------------------------------------------------------------
[root@k8s-m1 jenkins]# kubectl apply -f pv-jekins.yaml 
persistentvolume/pv-jekins created
[root@k8s-m1 jenkins]# kubectl get pv
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     
pv-jekins   5Gi        RWO            Retain           Available                       

Jenkins及其組件安裝

Jenkins安裝

[root@k8s-m1 jenkins]# kubectl apply -f jenkins.yml 

Please use the following password to proceed to installation:

dc7d3ccd7b0749bbbd4e33134619140f

http://192.168.153.25:30006/

修改國內源

[root@k8s-m1 jenkins-data]#  cd /ifs/kubernetes/jenkins-data/updates/
[root@k8s-m1 updates]# sed -i 's/https:\/\/updates.jenkins.io\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json
[root@k8s-m1 updates]# sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json

#重啟jenkins
[root@k8s-m1 jenkins]# kubectl delete pod jenkins-578b57ddcb-jchrb

安裝插件

? Git:拉取代碼
? Git Parameter:Git參數化構建
? Pipeline:流水線
? kubernetes:連接Kubernetes動態創建Slave代理
? Config File Provider:存儲配置文件
? Extended Choice Parameter:擴展選擇框參數,支持多選

Jenkins在K8s中動態創建代理

Jenkins主從架構介紹

001 當觸發Jenkins任務時,Jenkins會調用Kubernetes API創建Slave Pod
002 Pod啟動后會連接Jenkins,接受任務并處理
1640325338695.png

Kubernetes插件配置

Configure Clouds

#進入配置
Manage Jenkins -> Manage Nodes and Clouds -> Configure Clouds

[root@k8s-m1 ~]# kubectl get svc -n default
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                        
kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP     

https://kubernetes.default
http://jenkins.default

注意:一定是http://jenkins.default而不是https://jenkins.default

#測試連接
Connected to Kubernetes v1.20.4
 

自定義Jenkins Slave鏡像

? Dockerfile:構建鏡像
? jenkins-slave:shell腳本啟動slave.jar
? settings.xml:修改maven官方源為阿里云源
? slave.jar:agent程序,接受master下發的任務,下載http://jenkinsip:port/jnlpJars/slave.jar
? helm和kubectl客戶端工具

[root@k8s-m1 jenkins-slave]# ls
Dockerfile  helm  jenkins-slave  kubectl  settings.xml  slave.jar

構建并推送到鏡像倉庫:
docker build -t 192.168.153.20/library/jenkins-slave-jdk:1.8 .
docker push 192.168.153.20/library/jenkins-slave-jdk:1.8

測試主從架構是否正常

pipeline {
  agent {
    kubernetes {
        label "jenkins-slave"
        yaml """
kind: Pod
metadata:
  name: jenkins-slave
spec:
  containers:
  - name: jnlp
    image: "192.168.153.20/library/jenkins-slave-jdk:1.8"
"""
      }     
    }
    stages {
        stage('第一步測試'){
            steps {
                sh 'hostname'
            }
        }
    }
}


-----------------------------------------------------------------------------------
#運行過程時會啟動slave的pod
[root@k8s-m1 jenkins-slave]# kubectl get pod
NAME                        READY   STATUS              RESTARTS   AGE
jenkins-578b57ddcb-7nwhj    1/1     Running             0          40m
jenkins-slave-354vz-0rcjt   0/1     ContainerCreating   0          13s

#運行結束后,slave的pod消失
[root@k8s-m1 jenkins-slave]# kubectl get pod
NAME                       READY   STATUS    RESTARTS   AGE
jenkins-578b57ddcb-7nwhj   1/1     Running   0          41m

流水線自動發布微服務項目

準備工作

Gitlab

git config --global user.name "lql"
git config --global user.email "lql_h@163.com"

cd simple-microservice-dev3
git init
git remote add origin http://192.168.153.18/root/microservice.git
git add .
git commit -m "Initial commit"
git push -u origin master

http://192.168.153.18/root/microservice.git
http://192.168.153.18/root/microservice.git

Mysql

#Gitlab配置數據庫配置文件application-fat.yml [product、order、stock]
mysql://192.168.153.27:3306/tb_product
mysql://192.168.153.27:3306/tb_stock
mysql://192.168.153.27:3306/tb_order

#啟動mysql
[root@k8s-node1 ~]# docker start mysql

host

192.168.153.27 eureka.ctnrs.com
192.168.153.27 gateway.ctnrs.com

#ingresscontorl的pod在192.168.153.27上需要有

全局憑據

#憑據配置 
Configure credentials -> 全局憑據 (unrestricted)

d713a4b9-7938-4fc1-98f5-83da66273c91    root/****** (12345678)      git-auth
83ac8c1d-a5e6-4902-9e72-68b7ec6be75f    admin/****** (Harbor12345)  harbor-auth

Managed files

#Managed files
Managed files -> Custom file

[root@k8s-m1 jenkins-slave]#  cat /root/.kube/config 
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /opt/kubernetes/ssl/ca.pem
    server: https://192.168.153.25:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: admin
  name: default
current-context: default
kind: Config
preferences: {}
users:
- name: admin
  user:
    client-certificate: /opt/kubernetes/ssl/admin.pem
    client-key: /opt/kubernetes/ssl/admin-key.pem


----------------------------------------------------------------------------
Custom file
MyCustom    aa483569-be58-4fc0-b9a3-070c4c9eef74

#取出(certificate-authority、client-certificate、client-key)的結果進行Base64編碼(Encode),得到: 
certificate-authority-data
client-certificate-data
client-key-data

#測試配置文件
helm list  --kubeconfig helmconfig 

https://base64.us/

Harbor

#創建項目
microservice

#推送helm
helm push ms-0.1.0.tgz --username admin --password Harbor12345 http://192.168.153.20/chartrepo/microservice
 

部署ingress

#host(客戶端)
192.168.153.27 eureka.ctnrs.com
192.168.153.27 gateway.ctnrs.com

[root@k8s-m1 k8s]# kubectl apply -f ingress-controller.yaml 

部署eurka

[root@k8s-m1 k8s]# kubectl apply -f eureka.yaml 

Pipeline腳本

#!/usr/bin/env groovy
// 所需插件: Git Parameter/Git/Pipeline/Config File Provider/kubernetes/Extended Choice Parameter
// 公共
def registry = "192.168.153.20"
// 項目
def project = "microservice"
def git_url = "http://192.168.153.18/root/microservice.git"
def gateway_domain_name = "gateway.ctnrs.com"
def portal_domain_name = "portal.ctnrs.com"
// 認證
def image_pull_secret = "registry-pull-secret"
def harbor_auth = "83ac8c1d-a5e6-4902-9e72-68b7ec6be75f"
def git_auth = "d713a4b9-7938-4fc1-98f5-83da66273c91"
// ConfigFileProvider ID
def k8s_auth = "aa483569-be58-4fc0-b9a3-070c4c9eef74"

pipeline {
  agent {
    kubernetes {
        label "jenkins-slave"
        yaml """
apiVersion: v1
kind: Pod
metadata:
  name: jenkins-slave
spec:
  containers:
  - name: jnlp
    image: "${registry}/library/jenkins-slave-jdk:1.8"
    imagePullPolicy: Always
    volumeMounts:
      - name: docker-cmd
        mountPath: /usr/bin/docker
      - name: docker-sock
        mountPath: /var/run/docker.sock
      - name: maven-cache
        mountPath: /root/.m2
  volumes:
    - name: docker-cmd
      hostPath:
        path: /usr/bin/docker
    - name: docker-sock
      hostPath:
        path: /var/run/docker.sock
    - name: maven-cache
      hostPath:
        path: /tmp/m2
"""
        }
      
      }
    parameters {
        gitParameter branch: '', branchFilter: '.*', defaultValue: 'origin/master', description: '選擇發布的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH'        
        extendedChoice defaultValue: 'none', description: '選擇發布的微服務', \
          multiSelectDelimiter: ',', name: 'Service', type: 'PT_CHECKBOX', \
          value: 'gateway-service:9999,portal-service:8080,product-service:8010,order-service:8020,stock-service:8030'
        choice (choices: ['ms', 'demo'], description: '部署模板', name: 'Template')
        choice (choices: ['1', '3', '5', '7'], description: '副本數', name: 'ReplicaCount')
        choice (choices: ['ms'], description: '命名空間', name: 'Namespace')
    }
    stages {
        stage('拉取代碼'){
            steps {
                checkout([$class: 'GitSCM', 
                branches: [[name: "${params.Branch}"]], 
                doGenerateSubmoduleConfigurations: false, 
                extensions: [], submoduleCfg: [], 
                userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]
                ])
            }
        }
        stage('代碼編譯') {
            // 編譯指定服務
            steps {
                sh """
                  mvn clean package -Dmaven.test.skip=true
                """
            }
        }
        stage('構建鏡像') {
          steps {
              withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
                sh """
                 docker login -u ${username} -p '${password}' ${registry}
                 for service in \$(echo ${Service} |sed 's/,/ /g'); do
                    service_name=\${service%:*}
                    image_name=${registry}/${project}/\${service_name}:${BUILD_NUMBER}
                    cd \${service_name}
                    if ls |grep biz &>/dev/null; then
                        cd \${service_name}-biz
                    fi
                    docker build -t \${image_name} .
                    docker push \${image_name}
                    cd ${WORKSPACE}
                  done
                """
                configFileProvider([configFile(fileId: "${k8s_auth}", targetLocation: "admin.kubeconfig")]){
                    sh """
                    # 添加鏡像拉取認證
                    kubectl create secret docker-registry ${image_pull_secret} --docker-username=${username} --docker-password=${password} --docker-server=${registry} -n ${Namespace} --kubeconfig admin.kubeconfig |true
                    # 添加私有chart倉庫
                    helm repo add  --username ${username} --password ${password} myrepo http://${registry}/chartrepo/${project}
                    """
                }
              }
          }
        }
        stage('Helm部署到K8S') {
          steps {
              sh """
              common_args="-n ${Namespace} --kubeconfig admin.kubeconfig"
              
              for service in  \$(echo ${Service} |sed 's/,/ /g'); do
                service_name=\${service%:*}
                service_port=\${service#*:}
                image=${registry}/${project}/\${service_name}
                tag=${BUILD_NUMBER}
                helm_args="\${service_name} --set image.repository=\${image} --set image.tag=\${tag} --set replicaCount=${replicaCount} --set imagePullSecrets[0].name=${image_pull_secret} --set service.targetPort=\${service_port} --description=\${image}:\${tag}  myrepo/${Template}"

                # 判斷是否為新部署
                if helm history \${service_name} \${common_args} &>/dev/null;then
                  action=upgrade
                else
                  action=install
                fi

                # 針對服務啟用ingress
                if [ \${service_name} == "gateway-service" ]; then
                  helm \${action} \${helm_args} \
                  --set ingress.enabled=true \
                  --set ingress.host=${gateway_domain_name} \
                   \${common_args}
                elif [ \${service_name} == "portal-service" ]; then
                  helm \${action} \${helm_args} \
                  --set ingress.enabled=true \
                  --set ingress.host=${portal_domain_name} \
                   \${common_args}
                else
                  helm \${action} \${helm_args} \${common_args}
                fi
              done
              # 查看Pod狀態
              sleep 10
              kubectl get pods \${common_args}
              """
          }
        }
    }
}

執行結果

[root@k8s-m1 ~]# helm list -n ms
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
gateway-service ms              2               2021-12-25 02:49:52.32458612 +0000 UTC  deployed        ms-0.1.0        0.1.0      
order-service   ms              1               2021-12-24 14:34:25.413383174 +0000 UTC deployed        ms-0.1.0        0.1.0      
portal-service  ms              4               2021-12-25 04:54:16.041854433 +0000 UTC deployed        ms-0.1.0        0.1.0      
product-service ms              1               2021-12-24 14:27:54.785617184 +0000 UTC deployed        ms-0.1.0        0.1.0      
stock-service   ms              1               2021-12-24 14:34:27.396239729 +0000 UTC deployed        ms-0.1.0        0.1.0   

執行日志

kubectl create secret docker-registry registry-pull-secret --docker-username=admin --docker-password=**** --docker-server=192.168.153.20 -n ms --kubeconfig admin.kubeconfig

helm repo add --username admin --password **** myrepo http://192.168.153.20/chartrepo/microservice

helm upgrade portal-service --set image.repository=192.168.153.20/microservice/portal-service --set image.tag=11 --set replicaCount=1 --set 'imagePullSecrets[0].name=registry-pull-secret' --set service.targetPort=8080 --description=192.168.153.20/microservice/portal-service:11 myrepo/ms --set ingress.enabled=true --set ingress.host=portal.ctnrs.com -n ms --kubeconfig admin.kubeconfig


1640357371000.png

自動化部署效果

#網關測試
http://gateway.ctnrs.com/product/queryAllProduct?page=1&limit=10

{"status":200,"msg":"success","result":[{"id":1,"productName":"測試商品1","price":99.99,"stock":98},{"id":2,"productName":"美女","price":999.0,"stock":87},{"id":3,"productName":"Q幣","price":100.0,"stock":77},{"id":4,"productName":"貂皮大衣很厚很厚的那種","price":9999.0,"stock":65}]}

#首頁展示
http://portal.ctnrs.com/
1640356856850.png
1640356877654.png
1640356894602.png

項目回滾

整體流程

1640409785132.png

根據服務獲取最近3次的版本號

[root@k8s-m1 ~]# curl -s -X GET -u admin:Harbor12345 http://192.168.153.20/v2/microservice/portal-service/tags/list

{"name":"microservice/portal-service","tags":["10"]}

----------------------------------------------------------------------------------
[root@k8s-m1 ~]# vi get_tag.sh                           
#!/bin/bash
Harbor_add=192.168.153.20
Username=admin
Password=Harbor12345
Project=$1
Service=$2

curl -s -X GET -u "${Username}:${Password}" "http://${Harbor_add}/v2/${Project}/${Service}/tags/list" |awk -F'[][]' '{split($2,a,",");for (v in a) print 
a[v]}' |sed 's/"http://g' |sort -nr|head -n 3
------------------------------------------------------------------------------------

[root@k8s-m1 ~]# ./get_tag.sh microservice portal-service   
10
9
8

#腳本復制到jenkins容器中
[root@k8s-m1 ~]# kubectl get pod
NAME                       READY   STATUS    RESTARTS   AGE
jenkins-578b57ddcb-7nwhj   1/1     Running   2          21h
[root@k8s-m1 ~]# kubectl cp get_tag.sh jenkins-578b57ddcb-7nwhj:/var/jenkins_home

配置插件

General ->This project is parameterized  ->Choice parameter
Name: Service
Choices: 
portal-service
gateway-service
product-service
order-service
stock-service

Description:請選擇要回滾的服務

--------------------------------------------------------------------------
#安裝插件Active Choices
Active Choices Reactive Parameter

Name : Tag
Script: Groovy Script

Groovy Script:
cmd = "/bin/bash /var/jenkins_home/get_tag.sh microservice ${Service}"
tags_list = cmd.execute().text.tokenize()
return tags_list

Referenced parameters:Service

定位回滾版本號腳本

[root@k8s-m1 ~]# helm history portal-service -n ms
REVISION        UPDATED                         STATUS          CHART           APP VERSION     DESCRIPTION                                                            
2               Sat Dec 25 02:43:58 2021        deployed        ms-0.1.0        0.1.0           192.168.153.20/microservice/portal-service:11
3               Sat Dec 25 02:43:58 2021        deployed        ms-0.1.0        0.1.0           192.168.153.20/microservice/portal-service:12


[root@k8s-m1 ~]# helm history portal-service -n ms|awk '$NF~/portal-service:12/{print $1}'
3

Pipeline腳本

def registry = "192.168.153.20"
def namespace = "ms"
def k8s_auth = "aa483569-be58-4fc0-b9a3-070c4c9eef74"

pipeline {
  agent {
    kubernetes {
        label "jenkins-slave"
        yaml """
apiVersion: v1
kind: Pod
metadata:
  name: jenkins-slave
spec:
  containers:
  - name: jnlp
    image: "${registry}/library/jenkins-slave-jdk:1.8"
    imagePullPolicy: Always
    volumeMounts:
      - name: docker-cmd
        mountPath: /usr/bin/docker
      - name: docker-sock
        mountPath: /var/run/docker.sock
      - name: maven-cache
        mountPath: /root/.m2
  volumes:
    - name: docker-cmd
      hostPath:
        path: /usr/bin/docker
    - name: docker-sock
      hostPath:
        path: /var/run/docker.sock
    - name: maven-cache
      hostPath:
        path: /tmp/m2
"""
        }
      
      }
    stages {
        stage('執行回滾的操作') {
          steps {
                configFileProvider([configFile(fileId: "${k8s_auth}", targetLocation: "admin.kubeconfig")]){
                    sh """
                    #根據選擇的服務名稱拼接鏡像地址
                    rollback_image=${Service}:${Tag}
                   revision=\$(helm history ${Service} --kubeconfig admin.kubeconfig  -n ms|awk '\$NF~/${Service}:${Tag}/{print \$1}')
                   helm  rollback ${Service} \$revision --kubeconfig admin.kubeconfig -n ${namespace} 

                    """
                }
              }
        }

    }
}

執行結果

[root@k8s-m1 ~]# helm list -n ms
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
gateway-service ms              2               2021-12-25 02:49:52.32458612 +0000 UTC  deployed        ms-0.1.0        0.1.0  
......

執行日志

helm rollback portal-service 2 --kubeconfig admin.kubeconfig -n ms
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
禁止轉載,如需轉載請通過簡信或評論聯系作者。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374