天天看點

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

本文主要示範如何在阿裡雲Kubernetes服務上快速搭建jenkins持續內建環境,并基于提供的示例應用快速完成應用源碼編譯、鏡像建構和推送以及應用部署的流水線。

先決條件:

阿裡雲Kubernetes叢集。

建議: 建議使用者先按照以下文檔安裝部署ack-jenkins應用, 然後成功運作建構任務示例demo-pipeline, 再依照此建構任務示例改造自己的建構任務配置。

1. 快速部署ack-jenkins

容器服務-Kubernetes -> 市場 -> 應用目錄 -> ack-jenkins:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

點選 參數 菜單修改 AdminPassword 字段, 選擇Kubernetes叢集、填寫命名空間和釋出名稱并點選 建立:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

通路jenkins服務并登陸:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

ps:如未設定登陸密碼,則可在部署完畢後使用如下命名檢視:

$ printf $(kubectl get secret --namespace ci jenkins-ci-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
           

2. 配置 Kubernetes Cloud

2.1 配置 Kubernetes Cloud

Jenkins使用Kubernetes Plugin連接配接Kubernetes叢集并動态生成和釋放slave pod,關于slave pod的模闆配置需要在 系統管理 -> 系統配置 -> 雲 中進行配置

  • 名稱:kubernetes;
  • Kubernetes 位址: https://kubernetes.default.svc.cluster.local:443 ;jenkins 系統安裝在目前叢集中,可以使用内部服務端點通路叢集的 API Server
  • Kubernetes 命名空間:jenkins;動态 slave pod 會在命名空間 jenkins 下生成和銷毀

    點選

    測試

    按鈕驗證連接配接無誤:
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
  • Jenkins 位址: http://ack-jenkins-default:8080 ;slave pod連接配接jenkins master使用的服務端點
  • Jenkins 通道:ack-jenkins-default-agent:50000;slave pod使用jnlp連接配接jenkins master
    阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
  • Pod Templates -> 名稱: slave-pipeline; slave pod名稱
  • Pod Templates -> 命名空間:jenkins
  • Pod Templates -> 标簽清單:slave-pipeline;jenkins 建構任務通過此标簽選擇使用哪個模闆生成slave pod
    阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
  • Pod Templates -> 容器清單 -> jnlp;用于jnlp連接配接jenkins master
    阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
  • Pod Templates -> 容器清單 -> kaniko;用于建構和推送容器鏡像
    阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
  • Pod Templates -> 容器清單 -> maven:用于maven建構和打包應用
    阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
  • Pod Templates -> 容器清單 -> kubectl:用于kubectl指令行部署應用
    阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
  • Pod Templates -> 環境變量;為kaniko設定DOCKER_CONFIG指定docker.json檔案路徑

    建立jenkins-docker-cfg secret用于鏡像倉庫權限設定

本示例中使用了阿裡雲鏡像服務提供的杭州區域鏡像倉庫:

$ docker login -u xxx -p xxx registry-vpc.cn-beijing.aliyuncs.com
Login Succeeded
$ kubectl create secret generic jenkins-docker-cfg -n ci --from-file=/root/.docker/config.json           

配置slave pod啟動時挂載 secret jenkins-docker-cfg:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

如果需要設定maven緩存目錄,可以挂載hostPath volume 或者共享存儲卷到/root/.m2/repository:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

如果需要更改 settings.xml,先建立 ConfigMap:

kubectl create configmap maven-config --from-file=settings.xml -n jenkins           

再配置挂載到slave pod:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

如果需要部署應用到本叢集,可以在slave pod中使用ServiceAccount通過kubectl部署,配置ServiceAccount:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

2.2 建立建構任務

建立建構任務cicd-pipeline,拉取源碼項目

https://github.com/haoshuwei/jenkins-demo.git

,分支master;maven打包建構,kaniko建構和推送容器鏡像;kubectl部署到本叢集。

在本示例中,需要打包容器鏡像為:registry-vpc.cn-beijing.aliyuncs.com/haoshuwei24/application-demo:20200915

則配置建構參數如下:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

建構任務配置如下:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

執行建構:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

可以在

中檢視Jenkinsfile内容。

3 連接配接外部叢集

連接配接外部叢集需要建立和使用證書

示例:建立k8sCertAuth證書

在此步驟中,我們需要先建立和配置一個名稱為

k8sCertAuth

的叢集證書, 點選 憑證 添加證書:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

儲存。

3. 詳解建構任務示例demo-pipeline

demo-pipeline

建構任務完成的持續內建/持續傳遞任務為:拉取源碼、建構應用war包、打包和推送容器鏡像以及部署應用到k8s叢集。示例源碼項目位址為

https://github.com/AliyunContainerService/jenkins-demo.git

, 整個建構流程會按照示例項目中

Jenkinsfile

聲明的内容執行建構。

3.1 demo-pipeline的任務配置

demo-pipeline設定了4個建構參數,分别為

origin_repo

repo

image_tag

branch

branch

用于指定本次建構拉取應用源碼倉庫的哪個分支, 另外3個變量用于建構和推送應用容器鏡像的位址,例如示例應用的容器鏡像要推送到

registry.cn-hangzhou.aliyuncs.com/ack-cicd/ack-jenkins-demo:latest

, 則

origin_repo

registry.cn-hangzhou.aliyuncs.com/ack-cicd

,

repo

ack-cicd

image_tag

latest

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

建構任務中配置從Git倉庫拉取源碼并指定Jenkinsfile路徑:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

3.2 Jenkinsfile解析

我們在示例源碼項目的Jenkinsfile

jenkins-demo/Jenkinsfile

中定義了以下内容:

pipeline{
      // 定義groovy腳本中使用的環境變量
      environment{
        // 将建構任務中的建構參數轉換為環境變量
        IMAGE_TAG =  sh(returnStdout: true,script: 'echo $image_tag').trim()
        ORIGIN_REPO =  sh(returnStdout: true,script: 'echo $origin_repo').trim()
        REPO =  sh(returnStdout: true,script: 'echo $repo').trim()
        BRANCH =  sh(returnStdout: true,script: 'echo $branch').trim()
      }

      // 定義本次建構使用哪個标簽的建構環境,本示例中為 “slave-pipeline”
      agent{
        node{
          label 'slave-pipeline'
        }
      }

      // "stages"定義項目建構的多個子產品,可以添加多個 “stage”, 可以多個 “stage” 串行或者并行執行
      stages{
        // 定義第一個stage, 完成克隆源碼的任務
        stage('Git'){
          steps{
            git branch: '${BRANCH}', credentialsId: '', url: 'https://github.com/AliyunContainerService/jenkins-demo.git'
          }
        }

        // 添加第二個stage, 運作源碼打包指令
        stage('Package'){
          steps{
              container("maven") {
                  sh "mvn package -B -DskipTests"
              }
          }
        }


        // 添加第三個stage, 運作容器鏡像建構和推送指令, 用到了environment中定義的groovy環境變量
        stage('Image Build And Publish'){
          steps{
              container("kaniko") {
                  sh "kaniko -f `pwd`/Dockerfile -c `pwd` --destination=${ORIGIN_REPO}/${REPO}:${IMAGE_TAG} --skip-tls-verify"
              }
          }
        }

        // 添加第四個stage, 部署應用到指定k8s叢集
        stage('Deploy to Kubernetes') {
            parallel {
                    steps {
                        container('kubectl') {
                            step([$class: 'KubernetesDeploy', authMethod: 'certs', apiServerUrl: 'https://kubernetes.default.svc.cluster.local:443', credentialsId:'k8sCertAuth', config: 'deployment.yaml',variableState: 'ORIGIN_REPO,REPO,IMAGE_TAG'])
                        }
                    }
            }
        }
      }
}           
3.2.1

environment{}

代碼塊

用于擷取建構參數并轉換為Jenkinsfile中使用的環境變量。

3.2.2

agent{}

用于指定本次建構使用的建構節點标簽為

slave-pipeline

。 進入 系統管理 -> 系統設定 -> 雲 可以看到Kubernetes雲的配置, 此配置用于定義如何動态建立建構節點:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

我們可以從上圖的Kubernetes雲配置中看到, 當我們執行建構任務時,jenkins會動态連接配接本叢集的api server url:

https://kubernetes.default.svc.cluster.local:443

jenkins

命名空間下建立 slave pod

slave-pipeline-xxx

, 此slave pod包含4個containers, 分别為用于slave連接配接master的

jnlp

、用于maven編譯打包java源碼的

maven

、用于容器鏡像建構和部署的

kaniko

以及用于部署k8s應用的

kubectl

當使用kaniko容器進行容器鏡像建構和推送時, 我們需要擷取鏡像推送到倉庫的權限, 這個權限是以k8s secret的方式挂載到slave-pipeline-xxx的pod裡的,環境變量

DOCKER_CONFIG

則定義了kaniko擷取鏡像倉庫推送權限檔案的預設路徑。 在此我們需要建立名為

jenkins-docker-cfg

的secret:

在一台linux機器上執行以下指令:

$ docker login -u xxx -p xxx registry.cn-hangzhou.aliyuncs.com
$ kubectl create secret generic jenkins-docker-cfg -n ci --from-file=/root/.docker/config.json           
3.2.3

stages{}

stages{}

代碼塊定義了多個stage,分别完成持續內建/持續部署過程中的不同步驟。

3.2.3.1 源碼拉取

源碼倉庫中一般包含

Jenkinsfile

Dockerfile

deployment.yaml

等檔案

stage('Git'){
  steps{
    git branch: '${BRANCH}', credentialsId: '', url: 'https://github.com/AliyunContainerService/jenkins-demo.git'
  }
}           

3.2.3.2 maven編譯和打包源碼

maven編譯的時候,使用者通常會想使用緩存功能, maven緩存需要使用NAS共享存儲,建立nas volume并挂載到Kubernetes雲的slave-pipeline模闆上, 類似jenkins-docker-cfg的挂載。

stage('Package'){
  steps{
    container("maven") {
      sh "mvn package -B -DskipTests"
    }
  }
}           

3.2.3.3 kaniko建構和推送鏡像

kaniko工具建構容器鏡像可以不依賴docker daemon程序,在使用者态空間完成鏡像建構和推送, 更安全可靠。

stage('Image Build And Publish'){
  steps{
    container("kaniko") {
      sh "kaniko -f `pwd`/Dockerfile -c `pwd` --destination=${ORIGIN_REPO}/${REPO}:${IMAGE_TAG} --skip-tls-verify"
    }
  }
}           

3.2.3.4 kubectl部署k8s應用

stage('Deploy to Kubernetes') {
  steps {
    container('kubectl') {
      step([$class: 'KubernetesDeploy', authMethod: 'certs', apiServerUrl: 'https://kubernetes.default.svc.cluster.local:443', credentialsId:'k8sCertAuth', config: 'deployment.yaml',variableState: 'ORIGIN_REPO,REPO,IMAGE_TAG'])
    }
  }
}           

k8sCertAuth

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

variableState: 'ORIGIN_REPO,REPO,IMAGE_TAG'

字段聲明需要替換

deployment.yaml

檔案中的哪些環境變量。

4. 系統配置詳解

4.1 建構環境配置說明

(1)kubernetes叢集動态配置設定建構pod的配置;

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

(2)slave-pipeline 使用了4個container分别完成流水線中各個stage的建構,Kubernetes Pod Templates配置

container jnlp:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

container kaniko:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

container kubectl:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

container maven:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

(3) 使用到的建構鏡像:

  • jnlp 用于建構節點jnlp連接配接master:
    jenkinsci/jnlp-slave:3.35-5           
  • maven 用于mvn打包建構:
    maven:3.6.2-jdk-14           
  • kaniko 用于鏡像建構和推送:
    registry.cn-hangzhou.aliyuncs.com/acs/kaniko:v0.14.0           
  • kubectl 用于kubectl部署應用:
    registry.cn-hangzhou.aliyuncs.com/acs/kubectl:1.14.8           
    (4) kaniko配置鏡像倉庫權限:
阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

4.2 示例項目說明

(1)示例項目中使用的源碼倉庫

https://github.com/AliyunContainerService/jenkins-demo.git           

(2)kaniko 建構和推送docker鏡像說明

kaniko可以不依賴docker daemon并在使用者空間執行完成Dockerfile中的每一行指令,最終完成docker鏡像的建構和推送。

kaniko -f `pwd`/Dockerfile -c `pwd` --destination=${origin_repo}/${repo}:${image_tag}           

(3)部署應用到Kubernetes叢集插件說明

插件配置如下:

阿裡雲Kubernetes服務上搭建jenkins環境并完成應用建構到部署的流水線作業

對應的Pipeline文法為:

step([$class: 'KubernetesDeploy', authMethod: 'certs', apiServerUrl: 'https://kubernetes.default.svc.cluster.local:443', credentialsId:'k8sCertAuth', config: 'deployment.yaml',variableState: 'ORIGIN_REPO,REPO,IMAGE_TAG'])           

聲明的變量ORIGIN_REPO,REPO,IMAGE_TAG可在建構執行時把deployment.yaml檔案中對應的變量值替換為實際值:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: jenkins-java-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: jenkins-java-demo
  template:
    metadata:
      labels:
        app: jenkins-java-demo
    spec:
      containers:
      - name: jenkins-java-demo
        image: ${ORIGIN_REPO}/${REPO}:${IMAGE_TAG}
        imagePullPolicy: Always
        ports:
        - containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: jenkins-java-demo
spec:
  ports:
  - port: 80
    targetPort: 8080
    name: jenkins-java-demo
  selector:
    app: jenkins-java-demo
  type: LoadBalancer           

(4)Jenkinsfile說明

pipeline{
      // 定義groovy腳本中使用的環境變量
      environment{
        // 本示例中使用DEPLOY_TO_K8S變量來決定把應用部署到哪套容器叢集環境中,如“Production Environment”, “Staging001 Environment”等
        IMAGE_TAG =  sh(returnStdout: true,script: 'echo $image_tag').trim()
        ORIGIN_REPO =  sh(returnStdout: true,script: 'echo $origin_repo').trim()
        REPO =  sh(returnStdout: true,script: 'echo $repo').trim()
        BRANCH =  sh(returnStdout: true,script: 'echo $branch').trim()
      }

      // 定義本次建構使用哪個标簽的建構環境,本示例中為 “slave-pipeline”
      agent{
        node{
          label 'slave-pipeline'
        }
      }

      // "stages"定義項目建構的多個子產品,可以添加多個 “stage”, 可以多個 “stage” 串行或者并行執行
      stages{
        // 定義第一個stage, 完成克隆源碼的任務
        stage('Git'){
          steps{
            git branch: '${BRANCH}', credentialsId: '', url: 'https://github.com/AliyunContainerService/jenkins-demo.git'
          }
        }

        // 添加第二個stage, 運作源碼打包指令
        stage('Package'){
          steps{
              container("maven") {
                  sh "mvn package -B -DskipTests"
              }
          }
        }


        // 添加第四個stage, 運作容器鏡像建構和推送指令, 用到了environment中定義的groovy環境變量
        stage('Image Build And Publish'){
          steps{
              container("kaniko") {
                  sh "kaniko -f `pwd`/Dockerfile -c `pwd` --destination=${ORIGIN_REPO}/${REPO}:${IMAGE_TAG}"
              }
          }
        }


        stage('Deploy to Kubernetes') {
            parallel {
                stage('Deploy to Production Environment') {
                    when {
                        expression {
                            "$BRANCH" == "master"
                        }
                    }
                    steps {
                        container('kubectl') {
                            step([$class: 'KubernetesDeploy', authMethod: 'certs', apiServerUrl: 'https://kubernetes.default.svc.cluster.local:443', credentialsId:'k8sCertAuth', config: 'deployment.yaml',variableState: 'ORIGIN_REPO,REPO,IMAGE_TAG'])
                        }
                    }
                }
                stage('Deploy to Staging001 Environment') {
                    when {
                        expression {
                            "$BRANCH" == "latest"
                        }
                    }
                    steps {
                        container('kubectl') {
                            step([$class: 'KubernetesDeploy', authMethod: 'certs', apiServerUrl: 'https://kubernetes.default.svc.cluster.local:443', credentialsId:'k8sCertAuth', config: 'deployment.yaml',variableState: 'ORIGIN_REPO,REPO,IMAGE_TAG'])
                        }
                    }
                }
            }
        }
      }
    }           

了解更多阿裡雲容器服務内容,請通路

https://www.aliyun.com/product/containerservice

了解更多kaniko内容請參考:

https://github.com/GoogleContainerTools/kaniko