1. 程式人生 > >基於K8s的動態Jenkins Slave構建實踐

基於K8s的動態Jenkins Slave構建實踐

前言

環境

這裡Jenkins Master的安裝沒有采用容器映象的方式,直接就是rpm包安裝。
版本資訊:
Jenkins 2.107.1
Kubernetes plugin 1.4
kubernetes叢集 1.5.2

這裡就不詳細說明安裝過程了。

配置

環境都安裝好後,配置Jenkins,進入系統管理—>系統設定—>雲
新增一個雲Kubernetes,配置如下:
cloud
配置比較簡單,這裡也沒有采用自定義的slave模板,預設Jenkins使用的是jenkins/jnlp-slave:alpine映象作為動態的執行的slave。
其中Kubernetes URL也可以通過命令檢視:
# kubectl cluster-info


Kubernetes master 所在的地址即可,比如:

Kubernetes master is running at https://10.1.241.82:8080/r/projects/1a7/kubernetes:6443

這裡的URL就填 https://10.1.241.82:8080/r/projects/1a7/kubernetes:6443

測試

這裡測試全部使用pipeline進行構建。
新建一個Pipeline流水線專案,配置Pipeline執行指令碼:
pipeline-test
指令碼內容:

podTemplate(label: 'mypod', cloud: 'kubernetes')
{
    node ('mypod'
) { stage('test') { echo "hello, world" sleep 60 } } }

label:Jenkins執行的節點標籤,可以隨意起;
cloud:就是我們上面配置雲的名字標識;
node:執行構建任務的slave節點,需要跟上面的label一致

非常簡單的一個測試用例,讓我們來跑一下看看。
首先看一下構建執行狀態:
slave-build
可以看到Jenkins自動建立了一個Slave節點在執行我們的構建任務,
我們再通過k8s看下執行的pod情況:

# kubectl get pod
NAME                        READY     STATUS    RESTARTS   AGE
jenkins-slave-5
d8m2-jzxk7 1/1 Running 0 38s # kubectl describe pod jenkins-slave-5d8m2-jzxk7 。。。 Events: FirstSeen LastSeen Count From SubObjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 46s 46s 1 {default-scheduler } Normal Scheduled Successfully assigned jenkins-slave-5d8m2-jzxk7 to master 44s 44s 1 {kubelet master} spec.containers{jnlp} Normal Pulled Container image "jenkins/jnlp-slave:alpine" already present on machine 44s 44s 1 {kubelet master} spec.containers{jnlp} Normal Created Created container with docker id 7cbdbd4ea859; Security:[seccomp=unconfined] 44s 44s 1 {kubelet master} spec.containers{jnlp} Normal Started Started container with docker id 7cbdbd4ea859

通過上面的k8s的pod資訊我們可以看到,pod名字就是Jenkins slave節點的名字。通過READY欄位,我們也能發現pod中只有一個容器在跑,最後看下詳細資訊,發現k8s確實是去拉取jenkins/jnlp-slave:alpine 映象了。

這裡再貼一下Jenkins的控制檯列印資訊:
console

專案實踐

真正的專案中實踐肯定不是這麼簡單的,我們這裡就以一個簡單maven構建專案為例。
步驟如下:

  • 製作maven映象,設定maven倉庫私服mirror,新增ssh-key方便無密碼拉取倉庫程式碼
  • 編寫Jenkinsfile,配置構建流程
  • 執行構建

製作maven映象

FROM maven:latest

ADD settings.xml /root/.m2/

RUN mkdir /root/.ssh/

ADD .ssh /root/.ssh/

RUN chmod 600 /root/.ssh/id_rsa

其中settings.xml包含了maven倉庫私服mirror、sonarqube等等一些maven相關的配置,
這裡需要注意的是ssh的私鑰許可權必須是600的,這個是配置無密碼從gitlab倉庫拉取原始碼的。
通過Dockerfile來製作我們自己的maven映象:
docker build . -t e5:8889/maven:1.0

上傳到我們私服倉庫:
docker push e5:8889/maven:1.0

編寫Jenkinsfile

Jenkinsfile是jenkins pipeline構建的一種指令碼,其中定義了構建流程。

podTemplate(label: 'mypod', cloud: 'kubernetes', containers: [
   containerTemplate(
         name: 'maven',
         image: 'e5:8889/maven:1.0',
         ttyEnabled: true,
         command: 'cat'
     )
])
{
    node ('mypod') {
     container('maven') {
         git url: '[email protected]:maven/springboot-archetype.git', 
                credentialsId: '6033483b-5125-4ce1-941d-83b23ae64ba6'

         stage('create-archetype') {

            sh 'mvn archetype:create-from-project'

        }

        stage('update-local-catalog') {
            sh 'cd target/generated-sources/archetype'
            sh 'mvn clean install'
            sh 'mvn archetype:update-local-catalog'
        }

        stage('deploy') {
            sh 'mvn deploy'
        }

        stage('build-tag') {
            build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
            echo build_tag
        }

     }
 }
}

我們通過containers.containerTemplate指定了我們程式碼是在哪個容器內進行構建的,其他的就都是一些簡單的構建流程,這裡就不細說了。

執行構建

我們最後再執行一次構建,看下Jenkins和k8s一些執行情況。
Jenkins Console控制檯列印:
git-jenkins

K8s的pod資訊:

# kubectl get pod
NAME                        READY     STATUS    RESTARTS   AGE
jenkins-slave-wm980-2v01l   2/2       Running   0          5s

通過READY欄位,發現這時pod執行的就有2個容器了,我們可以猜測一個是slave容器,一個是我們自定義的maven容器。
再來看下pod建立的詳細資訊:

# kubectl describe pod jenkins-slave-wm980-2v01l
Events:
  FirstSeen     LastSeen        Count   From                    SubObjectPath           Type            Reason          Message
  ---------     --------        -----   ----                    -------------           --------        ------          -------
  17s           17s             1       {default-scheduler }                            Normal          Scheduled       Successfully assigned jenkins-slave-wm980-2v01l to master
  15s           15s             1       {kubelet master}        spec.containers{maven}  Normal          Pulled          Container image "e5:8889/maven:1.0" already present on machine
  15s           15s             1       {kubelet master}        spec.containers{maven}  Normal          Created         Created container with docker id 85c8547aa047; Security:[seccomp=unconfined]
  15s           15s             1       {kubelet master}        spec.containers{maven}  Normal          Started         Started container with docker id 85c8547aa047
  15s           15s             1       {kubelet master}        spec.containers{jnlp}   Normal          Pulled          Container image "jenkins/jnlp-slave:alpine" already present on machine
  15s           15s             1       {kubelet master}        spec.containers{jnlp}   Normal          Created         Created container with docker id c10cc2694b05; Security:[seccomp=unconfined]
  14s           14s             1       {kubelet master}        spec.containers{jnlp}   Normal          Started         Started container with docker id c10cc2694b05

通過這行資訊:"e5:8889/maven:1.0" already present on machine
我們發現果然有使用到自己的maven映象了。

結語

其實真正實踐起來還是會發現很多坑的,之前網上搜到很多教程都還需要自定義slave映象亦或者將Jenkins Master節點也作為容器放入k8s中,但是感覺一來麻煩,二來也沒太大必要就沒弄了。其實後面更關鍵是在應用的部署上面,這裡只是將構建工具鏈都準備好,提供一個應用乾淨的構建環境。

寫完之後還發現有許多可以優化的地方,比如maven本地快取倉庫的掛載等等。。