1. 程式人生 > >Jenkins+GitLab+Docker+SpringCloud+Kubernetes實現可持續自動化微服務

Jenkins+GitLab+Docker+SpringCloud+Kubernetes實現可持續自動化微服務

  現有混合雲平臺的場景下,即有線下和線上的環境,又有測試與正式的場景,而且結合了Docker,導致打包內容有所區分,且服務的釋出流程複雜起來,手工打包需要在編譯階段就要根據環境到處更改配置,因此純手工釋出增加了實施的難度,需要一個統一的適應各種環境部署的方案。

基於微服務的釋出流程

  手動/自動構建 -> Jenkins 排程 K8S API ->動態生成 Jenkins Slave pod -> Slave pod 拉取 Git 程式碼/編譯/打包映象 ->推送到映象倉庫 Harbor -> Slave工作完成,Pod 自動銷燬 ->部署到測試或生產 Kubernetes(K8S)平臺。

  上面是理想狀況下的將服務編譯打包成映象上傳到映象庫後部署到Kubernetes平臺的一個流程,但問題是:

  1. 我們有線上線下平臺,程式碼線上下GitLab,是出不了外網的,因此線上K8S叢集無法拉取程式碼編譯。
  2. Jenkins的master所在伺服器是CentOS6.5,沒有Docker環境,也沒有在K8S叢集伺服器內,因此無法直接執行docker build映象和 kubectl apply 釋出服務到K8S叢集。
  3. Jenkins的slave節點都是無法訪問外網的,
  4. 線上服務需要Pinpoint而線下環境暫時不需要啟用Pinpoint,否則一直報錯,因此需要根據選擇的環境動態的構建Dockerfile,而且要求整個釋出流程可選擇。

就上面現實問題,我們將釋出流程簡化:

關鍵點:

Docker映象的打包使用com.spotify的docker-maven-plugin外掛結合Dockerfile,呼叫遠端伺服器的Docker環境生成映象。

K8S服務部署採用的是ssh方式,將Deployment檔案上傳到K8S叢集伺服器,然後執行部署命令。

如何利用Dockerfile打包映象

  之前也是用com.spotify的docker-maven-plugin外掛來打包映象並推送到私有映象倉庫,但問題是無法根據環境寫條件判斷,如動態選擇是否需要啟動pinpoint,線上線下庫地址動態更換,導致映象名字首也是要動態變化的,此時直接配置無法滿足,需要結合Dockerfile來實現。

先更改pom檔案,指定本專案的Dockerfile檔案地址,預設是放在專案根目錄下:

           <plugin>
                <groupId>com.spotify</groupId>
                <artifactId>docker-maven-plugin</artifactId>
                <version>1.2.0</version>
                <configuration>
                    <!--覆蓋相同標籤映象-->
                    <forceTags>true</forceTags>
                    <!-- 與maven配置檔案settings.xml一致 -->
                    <serverId>nexus-releases</serverId>
                    <!--私有倉庫地址 -->
                    <registryUrl>https://${docker.repostory}</registryUrl>
                    <!--遠端Docker地址 -->
                    <dockerHost>http://10.3.87.210:2375</dockerHost>
                    <!-- 注意imageName一定要是符合正則[a-z0-9-_.]的,否則構建不會成功 -->
                    <!--指定映象名稱 倉庫/映象名:標籤-->
<imageName>${docker.repostory}/${project.artifactId}:${project.version}</imageName>
                    <dockerDirectory>${project.basedir}</dockerDirectory>
                    <resources>
                        <resource>
                            <!-- 指定要複製的目錄路徑,這裡是當前目錄 -->
                            <!-- 將打包檔案放入dockerDirectory指定的位置 -->
                            <targetPath>/app/</targetPath>
                            <!-- 指定要複製的根目錄,這裡是target目錄 -->
                            <directory>${project.build.directory}</directory>
                            <!-- 指定需要拷貝的檔案,這裡指最後生成的jar包 -->
                            <include>${project.build.finalName}.jar</include>
                        </resource>
                    </resources>
                </configuration>
            </plugin>

<registryUrl>https://${docker.repostory}</registryUrl>

指定遠端倉庫地址,在主專案的<properties>中指定,這裡預設線上倉庫<docker.repostory>39.95.40.97:5000</docker.repostory>

<dockerHost>http://10.3.87.210:2375</dockerHost>

指定Docker映象打包伺服器,這裡指定線下伺服器。

<imageName>${docker.repostory}/${project.artifactId}:${project.version}</imageName>

指定映象名稱 倉庫/映象名:標籤

<dockerDirectory>${project.basedir}</dockerDirectory>

指定Dockerfile檔案地址,此處指定專案根目錄

 

Dockerfile內容

FROM join:0.2

MAINTAINER {description} Join

ADD /app/{artifactId}-{version}.jar /app/

ENTRYPOINT ["java", "-Xmx512m","-Dspring.profiles.active={active}",{jarparam} "-jar", "/app/{artifactId}-{version}.jar"]

  基礎映象用join:0.2,裡面包含了pinpoint和監控jvm的promethus客戶端包。

  Jarparam會在Jenkins中動態替換執行時引數,active 指定當前執行環境,這裡可能有人提議根據專案yml檔案中指定內容自動匹配,因為要考慮到如果自動匹配 更換線上線下環境就需要更改yml配置檔案後又要上傳到gitlab,如此沒有必要多做一步,直接在Jenkins中當作引數指定最為便捷。

  此處Dockerfile是通用模板,如果有特殊內容新增,可自行更改,此時的模板需要在Jenkins執行時替換引數後才有用,如果想直接在本機執行打包,可手動替換引數內容後執行:

clean package -DskipTests docker:build

推送

clean package -DskipTests docker:build -DpushImage

Jenkins釋出流程

利用Jenkins的pipeline構建流水線

  Pipeline也就是構建流水線,對於程式設計師來說,最好的解釋是:使用程式碼來控制專案的構建、測試、部署等。使用它的好處有很多,包括但不限於:

l  使用Pipeline可以非常靈活的控制整個構建過程;

l  可以清楚的知道每個構建階段使用的時間,方便構建的優化;

l  構建出錯,使用stageView可以快速定位出錯的階段;

l  一個job可以搞定整個構建,方便管理和維護等。

 

  Pipeline 支援兩種語法,宣告式和指令碼式。這兩種方法都支援構建持續交付流水線,都可以通過 web UI 或 Jenkinsfile 檔案來定義 Pipeline(通常認為建立 Jenkinsfile 檔案並上傳到原始碼控制倉庫是最佳實踐)

Jenkinsfile 就是一個包含對 Jenkins Pipeline 定義的文字檔案,會上傳到版本控制中。下面的 Pipeline 實現了基本的 3 段持續交付流水線。

 

宣告式 Pipeline:

// Jenkinsfile (Declarative Pipeline)

pipeline {

    agent any

    stages {

        stage('Build') {

            steps {

                echo 'Building..'

            }

        }

        stage('Test') {

            steps {

                echo 'Testing..'

            }

        }

        stage('Deploy') {

            steps {

                echo 'Deploying....'

            }

        }

    }

}

對應的指令碼式 Pipeline:

// Jenkinsfile (Scripted Pipeline)

node {

    stage('Build') {

        echo 'Building....'

    }

    stage('Test') {

        echo 'Building....'

    }

    stage('Deploy') {

        echo 'Deploying....'

    }

}

  注意,所有的 Pipeline 都會有這三個相同的 stage,可以在所有專案的一開始就定義好它們。下面演示在 Jenkins 的測試安裝中建立和執行一個簡單的 Pipeline。

  假設專案已經設定好了原始碼控制倉庫,並且已經按照入門章節的描述在 Jenkins 中定義好了 Pipeline。

  使用文字編輯器(最好支援 Groovy 語法高亮顯示),在專案根目錄中建立 Jenkinsfile。

  上面的宣告式 Pipeline 示例包含了實現一個持續交付流水線所需的最少步驟。必選指令 agent 指示 Jenkins 為 Pipeline 分配執行程式和工作空間。沒有 agent 指令的話,宣告式 Pipeline 無效,無法做任何工作!預設情況下 agent 指令會確保原始碼倉庫已經檢出,並且可用於後續步驟。

  stage 和 step 指令在宣告式 Pipeline 中也是必須的,用於指示 Jenkins 執行什麼及在哪個 stage 中執行。

  對於指令碼式 Pipeline 的更高階用法,上面的示例節點是至關重要的第一步,因為它為 Pipeline 分配了一個執行程式和工作空間。如果沒有 node,Pipeline 不能做任何工作!在 node 內,業務的第一階段是檢出此專案的原始碼。由於 Jenkinsfile 是直接從原始碼控制中提取的,因此 Pipeline 提供了一種快速簡單的方法來訪問原始碼的正確版本:

// Jenkinsfile (Scripted Pipeline)

node {

    checkout scm

    /* .. snip .. */

}

這個 checkout 步驟會從原始碼控制中檢查程式碼,scm 是特殊變數,它指示執行檢出步驟,複製觸發了這次 Pipeline 執行的指定版本。

最終的流程樣式:

 

 

  一般用宣告式來構建流水,實際操作過程中還是發現指令碼式構建更順手,而且Groovy語言更方便查資料,因此下面以指令碼構建為主演示一個流程。

1.新建任務

 

 

2.填寫任務名和描述,由於防止構建歷史太多,只保留3個。

 

 

3.新增構建時全域性構建引數,用來構建流程動態選擇環境,這裡有兩種方式,一種是直接在頁面上新增,如下圖,一種是在Jenkinsfile中新增(第一次構建時不會出現選項,第二次構建才會出現,因此首次構建需要試構建,暫停再重新整理頁面才會有選擇框),兩種最張效果一樣,這裡為了方便採用Jenkinsfile來新增全域性引數。

 

 

Jenkinsfile中新增

properties([
        parameters([string(name: 'PORT', defaultValue: '7082', description: '程式執行埠'),choice(name: 'ACTIVE_TYPE', choices: ['dev', 'prd', 'local'], description: '程式打包環境'),choice(name: 'ENV_TYPE', choices: ['online', 'offline'], description: '線上、還是線下環境'),booleanParam(name: 'ON_PINPOINT', defaultValue: true, description: '是否新增Pinpoint監控'),booleanParam(name: 'ON_PROMETHEUS', defaultValue: true, description: '是否新增Prometheus監控'),string(name: 'EMAIL', defaultValue: '[email protected]', description: '打包結果通知')])
])

 

4.選擇原始碼程式碼庫:

 

 

需要新增認證,將Jenkins的ssh祕鑰新增到GitLab的頁面中,且需要將此處gitlab中joint使用者新增到需要拉取程式碼的專案中才有許可權拉取程式碼。

Jenkinsfile位置放在專案的根目錄。

5. Jenkinsfile中指定maven目錄地址

MVNHOME = '/opt/maven354'

為防止手工填寫專案名和版本號等一系列資訊,因此直接讀取pom檔案中要編譯專案的這些資訊給全域性變數:

pom = readMavenPom file: 'pom.xml'
echo "group: ${pom.groupId}, artifactId: ${pom.artifactId}, version: ${pom.version} ,description: ${pom.description}"
artifactId = "${pom.artifactId}"
version = "${pom.version}"
description = "${pom.description}"

根據選擇的線上環境還是線下環境,替換映象倉庫ip

if (params.ENV_TYPE == 'offline' || params.ENV_TYPE == null) {
  sh "sed -i 's#39.95.40.97:7806#10.3.87.51:8080#g' pom.xml"
  image = "10.3.87.51:8080/${artifactId}:${version}"
}

 

6.編譯

利用maven構建,利用上面的內容先替換掉Dockerfile、Deployment中的變數,再根據選擇的條件是否啟用pinpoint和promethus,最後編譯。

def jarparam=''
def pinname = artifactId
if( pinname.length() > 23) {
  pinname = artifactId.substring(0,23)
}
//新增pinpoint
if(params.ON_PINPOINT) {
  jarparam = '"-javaagent:/app/pinpoint-agent/pinpoint-bootstrap-1.8.0.jar","-Dpinpoint.agentId={pinname}", "-Dpinpoint.applicationName={pinname}",'
}
//新增prometheus
if(params.ON_PROMETHEUS) {
  jarparam = jarparam + '"-javaagent:/app/prometheus/jmx_prometheus_javaagent-0.11.0.jar=1234:/app/prometheus/jmx.yaml",'
}

sh "sed -i 's#{jarparam}#${jarparam}#g' Dockerfile"

sh "sed -i 's#{description}#${description}#g;s#{artifactId}#${artifactId}#g;s#{version}#${version}#g;s#{active}#${params.ACTIVE_TYPE}#g;s#{pinname}#${pinname}#g' Dockerfile"

sh "sed -i 's#{artifactId}#${artifactId}#g;s#{version}#${version}#g;s#{port}#${params.PORT}#g;s#{image}#${image}#g' Deployment.yaml"

sh "'${MVNHOME}/bin/mvn' -DskipTests clean package"

 

需要注意的是pinpoint的pinpoint.applicationName不能操作24個字元,否則啟用不成功,因此超過的直接截斷。

Department檔案詳情看後文。

跳過測試編譯打包 '${MVNHOME}/bin/mvn' -DskipTests clean package 需要在Jenkins伺服器安裝maven環境,還有指定maven的jar包私有倉庫地址。

7. Docker打包

前提是上一步指定pom檔案中的映象倉庫和Dockerfile中的內容是替換後的完整內容。

sh "'${MVNHOME}/bin/mvn' docker:build"

8. 推送映象

sh "'${MVNHOME}/bin/mvn' docker:push"

如何釋出服務到K8S叢集

  前面幾步已經將專案打包並生成了映象並推送到了私有倉庫,下面就是部署服務到K8S叢集。

先看看Department.yaml檔案:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {artifactId}
  namespace: default
  labels:
    app: {artifactId}
    version: {version}
spec:
  selector:
    matchLabels:
      app: {artifactId}
  replicas: 1
  template:
    metadata:
      labels:
        app: {artifactId}
      annotations:
        prometheus.io.jmx: "true"
        prometheus.io.jmx.port: "1234"
    spec:
      containers:
      - name: {artifactId}
        image: {image}
        # IfNotPresent\Always
        imagePullPolicy: Always
        ports:
        - name: prometheusjmx
          containerPort: 1234
        livenessProbe: #kubernetes認為該pod是存活的,不存活則需要重啟
          httpGet:
            path: /health
            port: {port}
            scheme: HTTP
          initialDelaySeconds: 60 ## 設定為系統完全啟動起來所需的最大時間+若干秒
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        readinessProbe: #kubernetes認為該pod是啟動成功的 
          httpGet:
            path: /health
            port: {port}
            scheme: HTTP
          initialDelaySeconds: 40 ## 設定為系統完全啟動起來所需的最少時間
          timeoutSeconds: 5
          successThreshold: 1
          failureThreshold: 5
        env:
        - name: eureka-server
          value: "eureka-server.default.svc.cluster.local"
        - name: eureka-server-replica
          value: "eureka-server-replica.default.svc.cluster.local"
        resources:
        # 5%的CPU時間和700MiB的記憶體
          requests:
#            cpu: 50m
            memory: 700Mi
          # 最多允許它使用
          limits:
#            cpu: 100m
            memory: 1000Mi
        # 指定在容器中掛載路徑
        volumeMounts:
        - name: logs-volume
          mountPath: /logs
        - name: host-time
          mountPath: /etc/localtime
          readOnly: true
        - name: host-timezone
          mountPath: /etc/timezone
          readOnly: true
        - name: pinpoint-config
          mountPath: /app/pinpoint-agent/pinpoint.config
      volumes:
      - name: logs-volume
        hostPath:
        # 宿主機上的目錄
          path: /logs
      - name: host-time
        hostPath:
          path: /etc/localtime
      - name: host-timezone
        hostPath:
          path: /usr/share/zoneinfo/Asia/Shanghai
      - name: pinpoint-config
        configMap:
          name: pinpoint-config
       # 執行在指定標籤的節點,前提是先給節點打標  kubectl label nodes 192.168.0.113 edgenode=flow
#      nodeSelector:
#        edgenode: flow
---
apiVersion: v1
kind: Service
metadata:
  name: {artifactId}
  namespace: default
  labels:
    app: {artifactId}
    version: {version}
spec:
  selector:
    app: {artifactId}
  ports:
  - name: tcp-{port}-{port}
    protocol: TCP
    port: {port}
    targetPort: {port}

 

裡面的變數會在前面幾步自動替換掉。

添加了prometheus收集jvm的內容:

prometheus.io.jmx: "true"
prometheus.io.jmx.port: "1234"

containerPort: 1234

將pinpoint的配置內容pinpoint.config用configMap  儲存,方便更改內容。

其它內容不在此詳解,可自行google。

 

  網上資料一般釋出服務都是直接kubectl deploy,這種情況只適用於jenkins的伺服器已包含在K8S伺服器叢集中。第二種情況是在K8S叢集伺服器裡面生成Jenkins的一個slave節點,然後在pipeline裡面設定node(“k8s”){ ……} 裡面釋出,具體方法自行google。

        這裡為了避免麻煩,採用直接SSH到K8S伺服器叢集的方案發布服務。

配置sshagent

SSH Agent Plugin :sshagent方法支援,用於上傳構建產物到目標伺服器,使用詳情見:

https://wiki.jenkins.io/display/JENKINS/SSH+Agent+Plugin

在Jenkins外掛庫搜尋後直接下載安裝(需要連外網環境),生產環境已安裝,直接使用。

使用:

sshagent(credentials: ['deploy_ssh_key_23']) {
  sh "scp -P 2222 -r Deployment.yaml [email protected]:/docker/yaml/Deployment-${artifactId}.yaml"
  sh "ssh -p 2222 [email protected] 'kubectl apply -f /docker/yaml/Deployment-${artifactId}.yaml && kubectl set env deploy/${artifactId} DEPLOY_DATE=${env.BUILD_ID}'"
}

先用ssh遠端到K8S叢集中的伺服器,將Deployment檔案上傳,然後再遠端執行kubectl apply釋出服務。

        為了避免誤操作,在釋出前做了釋出確認提示判斷。

timeout(time: 10, unit: 'MINUTES') {
   input '確認要部署嗎?'
}

      以上流程已完成整個流程,然後可以去K8S環境去看服務是否有正常執行。

關於測試

  上面的過程沒有加入程式碼測試、程式碼質量分析SonarQube、釋出後服務測試的階段(Selenium是一套完整的Web應用程式測試系統http://www.51testing.com/zhuanti/selenium.html),後續可以接入。

 

如何進行多模組如何構建

  很多專案採用的是多模組構成,因此每個專案配置和釋出要求不一樣,需要單獨編譯到部署,所以每個模組都需要獨立的Dockerfile和Deployment檔案,Jenkinsfile通用一份,然後在釋出時自動彈出模組列表,選擇需要釋出的模組進行編譯釋出。

//需要處理的專案多專案時先進入子專案

projectwk = "."

mainpom = readMavenPom file: 'pom.xml'

//存在多個模組時,選擇其中一個進行編譯

if(mainpom.modules.size() > 0 ) {

  echo "專案擁有模組==${mainpom.modules}"

  timeout(time: 10, unit: 'MINUTES') {

    def selproj = input message: '請選擇需要處理的專案', parameters: [choice(choices: mainpom.modules, description: '請選擇需要處理的專案', name: 'selproj')] //, submitterParameter: 'project'

    projectwk = selproj

    echo "選擇專案=${projectwk}"

  }

}

 讀取主專案的pom中的modules判斷是否包含多個模組,供使用者選擇。

然後根據選擇的模組進行編譯,dir進入選擇的模組讀取資訊並編譯。

dir("${projectwk}") {

    pom = readMavenPom file: 'pom.xml'

    echo "group: ${pom.groupId}, artifactId: ${pom.artifactId}, version: ${pom.version} ,description: ${pom.description}"

    artifactId = "${pom.artifactId}"

    version = "${pom.version}"

    description = "${pom.description}"

}

完整的Jenkinsfile

properties([

        parameters([string(name: 'PORT', defaultValue: '7082', description: '程式執行埠'),choice(name: 'ACTIVE_TYPE', choices: ['dev', 'prd', 'local'], description: '程式打包環境'),choice(name: 'ENV_TYPE', choices: ['online', 'offline'], description: '線上、還是線下環境'),booleanParam(name: 'ON_PINPOINT', defaultValue: true, description: '是否新增Pinpoint監控'),booleanParam(name: 'ON_PROMETHEUS', defaultValue: true, description: '是否新增Prometheus監控'),string(name: 'EMAIL', defaultValue: '[email protected]', description: '打包結果通知')])

])

node {

    stage('Prepare') {

        echo "1.Prepare Stage"

        MVNHOME = '/opt/maven354'

        //echo "UUID=${UUID.randomUUID().toString()}"

        checkout scm

        //需要處理的專案多專案時先進入子專案

        projectwk = "."

        mainpom = readMavenPom file: 'pom.xml'

        repostory = "${mainpom.properties['docker.repostory']}"

        //存在多個模組時,選擇其中一個進行編譯

        if(mainpom.modules.size() > 0 ) {

          echo "專案擁有模組==${mainpom.modules}"

          timeout(time: 10, unit: 'MINUTES') {

            def selproj = input message: '請選擇需要處理的專案', parameters: [choice(choices: mainpom.modules, description: '請選擇需要處理的專案', name: 'selproj')] //, submitterParameter: 'project'

            projectwk = selproj

            echo "選擇專案=${projectwk}"

          }

        }


        dir("${projectwk}") {

            pom = readMavenPom file: 'pom.xml'

            echo "group: ${pom.groupId}, artifactId: ${pom.artifactId}, version: ${pom.version} ,description: ${pom.description}"

            artifactId = "${pom.artifactId}"

            version = "${pom.version}"

            description = "${pom.description}"

        }

        script {

            GIT_TAG = sh(returnStdout: true, script: '/usr/local/git/bin/git rev-parse --short HEAD').trim()

            echo "GIT_TAG== ${GIT_TAG}"

        }

        image = "192.168.4.2:5000/${artifactId}:${version}"

      if (params.ENV_TYPE == 'offline' || params.ENV_TYPE == null) {

        sh "sed -i 's#39.95.40.97:5000#10.3.80.50:5000#g' pom.xml"

        image = "10.3.80.50:5000/${artifactId}:${version}"

      }

    }

    if(mainpom.modules.size() > 0 ) {

       stage('編譯總專案') {

          sh "'${MVNHOME}/bin/mvn' -DskipTests clean install"

       }

    }

    dir("${projectwk}") {

        stage('編譯模組') {

            echo "2.編譯模組 ${artifactId}"

            def jarparam=''

            def pinname = artifactId

            if( pinname.length() > 23) {

              pinname = artifactId.substring(0,23)

            }

            //新增pinpoint

            if(params.ON_PINPOINT) {

              jarparam = '"-javaagent:/app/pinpoint-agent/pinpoint-bootstrap-1.8.0.jar","-Dpinpoint.agentId={pinname}", "-Dpinpoint.applicationName={pinname}",'

            }

            //新增prometheus

            if(params.ON_PROMETHEUS) {

              jarparam = jarparam + '"-javaagent:/app/prometheus/jmx_prometheus_javaagent-0.11.0.jar=1234:/app/prometheus/jmx.yaml",'

            }

            sh "sed -i 's#{jarparam}#${jarparam}#g' Dockerfile"

            sh "sed -i 's#{description}#${description}#g;s#{artifactId}#${artifactId}#g;s#{version}#${version}#g;s#{active}#${params.ACTIVE_TYPE}#g;s#{pinname}#${pinname}#g' Dockerfile"

            sh "sed -i 's#{artifactId}#${artifactId}#g;s#{version}#${version}#g;s#{port}#${params.PORT}#g;s#{image}#${image}#g' Deployment.yaml"

            sh "'${MVNHOME}/bin/mvn' -DskipTests clean package"

            stash includes: 'target/*.jar', name: 'app'

        }

        stage('Docker打包') {

            echo "3.Docker打包"

            unstash 'app'

            sh "'${MVNHOME}/bin/mvn' docker:build"

        }

        stage('推送映象') {

            echo "4.Push Docker Image Stage"

            sh "'${MVNHOME}/bin/mvn' docker:push"

        }

         timeout(time: 10, unit: 'MINUTES') {

            input '確認要部署嗎?'

         }

        stage('釋出') {

        if (params.ENV_TYPE == 'offline' || params.ENV_TYPE == null) {

              sshagent(credentials: ['deploy_ssh_key_34']) {

                sh "scp -r Deployment.yaml [email protected]:/docker/yaml/Deployment-${artifactId}.yaml"

                sh "ssh [email protected] 'kubectl apply -f /docker/yaml/Deployment-${artifactId}.yaml && kubectl set env deploy/${artifactId} DEPLOY_DATE=${env.BUILD_ID}'"

              }

           } else {

              sshagent(credentials: ['deploy_ssh_key_238']) {

                sh "scp -P 22 -r Deployment.yaml [email protected]:/docker/yaml/Deployment-${artifactId}.yaml"

                sh "ssh -p 22 [email protected] 'kubectl apply -f /docker/yaml/Deployment-${artifactId}.yaml && kubectl set env deploy/${artifactId} DEPLOY_DATE=${env.BUILD_ID}'"

              }

           }

            echo "釋出完成"

        }

    }

   stage('通知負責人'){

//    emailext body: "構建專案:${description}\r\n構建完成", subject: '構建結果通知【成功】', to: "${EMAIL}"

        echo "構建專案:${description}\r\n構建完成"

   }

}

將Jenkinsfile檔案放在專案根目錄,然後將原始碼都上傳到GitLab。

開啟BlueOcean,這是Jenkins新出的美化頁面。

選擇自己的專案。

 

進入後點擊執行,其中會彈出框選擇釋出引數(這裡需要手工填寫釋出的埠,由於採用配置中心化,埠無法自動讀取)。

 

進入檢視流程狀態,失敗會有相應的提示:

顯示釋出服務

 

在K8S內檢視部署的服務啟動情況。

 

 

Jenkinsfile Pipeline

Jenkinsfile Pipeline語法內容可參考官網:https://jenkins.io/doc/book/pipeline/jenkinsfile/

還可以進入專案後,有個流水線語法:

 

選擇想要的功能,生成:

 

  Jenkins還可用作釋出Vue前端專案,具體內容可參考 Jenkins自動化構建vue專案然後釋出到遠端伺服器 文件。

  Jenkins要釋出Net服務需要有一臺windows的Jenkins slave,還需要在此節點上安裝編譯器MSBuild框架,Git框架、更改伺服器上的IIS許可權等功能,最後檔案分發到其它windows伺服器,過程比較繁瑣,若無釋出稽核建議直接通過VS自帶釋出功能釋出程式。