Jenkins On Kubernetes---Jenkins上Kubernetes Plugin的使用

之前寫過一篇《Jenkins On Mesos—Jenkins上Mesos Plugin的使用》的博客,說的是Jenkins通過Mesos Plugin來實現slave節點的動態擴展和收縮。如果使用docker的人,不知道kubernetes的話,總是顯得有些尷尬,所以最近自己也開始在測試環境使用目前火熱的Kubernetes 1.8版(之前是在用Marathon+Mesos那一套)。Marathon、Mesos有的功能,Kubernetes當然也都有。這裏就記錄一下Kubernetes上實現slave節點動態增減的Kubernetes Plugin配置的一點實踐。

配置Jenkins Server

首先,需要有一套k8s集羣環境。之前已經部好了,這裏就不說k8s的搭建,只說Jenkins插件。我的k8s集羣是配置了SSL加密證書的,所以Jenkins Server要想能與k8s集羣的apiserver通信,需要先通過權限認證。k8s裏面有個Service Account的概念,配置使用Service Account來實現給Jenkins Server的授權。

Service Account:
相對於kubectl訪問apiserver時用的user account,service account方案是爲了給Pod中的process訪問k8s API提供的一種身份標識。簡單的說就是,通過service account可以實現給Pod中的進程授權訪問k8s API。

下面是配置Jenkins Server用到的yaml配置文件:
jenkins-rbac.yaml

---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: jenkins
  name: jenkins-admin
  namespace: kube-system

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: jenkins-admin
  labels:
    k8s-app: jenkins
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: jenkins-admin
  namespace: kube-system

說明:這裏是創建了一個名爲jenkins-admin的ServiceAccount,直接繼承了cluster-admin的權限。還可以根據自己實際情況,創建指定權限的ClusterRole,比如(僅供參考):

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  labels:
    k8s-app: jenkins
  name: jenkins
rules:
- apiGroups: ["", "extensions", "apps"]
  resources:
    - nodes
    - nodes/proxy
    - endpoints
    - secrets
    - pods
    - deployments
    - services
  verbs: ["get", "list", "watch"]

jenkins.yaml

apiVersion: apps/v1beta2 # for versions before 1.8.0 use apps/v1beta1
kind: Deployment
metadata:
  name: jenkins
  namespace: kube-system
  labels:
    k8s-app: jenkins
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: jenkins
  template:
    metadata:
      labels:
        k8s-app: jenkins
    spec:
      containers:
      - name: jenkins
        image: my.example.com/library/centos7.4-ssh-maven-jenkins:2.19
        imagePullPolicy: Always
        volumeMounts:
        - name: jenkins-home
          mountPath: /var/jenkins_home
        ports:
        - containerPort: 8080
        - containerPort: 50000
      volumes:
        - name: jenkins-home
          hostPath:
            path: /var/www/webapps/jenkins
      nodeSelector:
        jenkins: "true"
      serviceAccount: "jenkins-admin"

注: 這裏的Jenkins鏡像我是用的自己定製的,可以替換成自己需要的鏡像。serviceAccount指定上面創建的jenkins-admin賬號。

jenkins-service.yaml

jenkins-service.yaml
---
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: jenkins
  name: jenkins
  namespace: kube-system
  annotations:
    prometheus.io/scrape: 'true'
spec:
  ports:
    - port: 8080
      name: jenkins
      nodePort: 31888
      targetPort: 8080
    - port: 50000
      name: jenkins-agent
      nodePort: 50000
      targetPort: 50000
  type: NodePort
  selector:
    k8s-app: jenkins

說明:Service配置暴露兩個端口,一個是Jenkins Server的訪問端口,這裏nodePort方式指定的是31888;另一個是Jenkins Agent通信用的端口,默認是50000,如果不暴露的話,Jenkins slave節點是無法和Jenkins Server建了連接的。注:nodePort方式默認的端口範圍是30000~32767,不包含50000端口的,可以參考這裏進行修改。

配置Kubernetes Plugin

用上面的yaml配置在k8s上將Jenkins Server運行之後,在Jenkins的【插件管理】裏面搜索Kubernetes plugin並安裝。
這裏寫圖片描述
接下來,在【系統管理】-【系統設置】-【新增一個雲】-【Kubernetes】配置k8s的插件。
這裏寫圖片描述
參考上圖的說明,進行配置。三個標記到的地方,是需要配置的必須信息,可以根據自己的情況進行配置。要注意的是,這裏的Name字段配的名字,後面在配置pipeline的Jenkins任務時,是需要用到的(假設這裏使用的名字叫Kubernetes)。然後點【Test Connection】,如果前面的Service Account配置的沒問題的話,就會提示“Connection successful”,否則,會有訪問apiserver的403權限報錯。
這裏寫圖片描述
到這裏,最基本的配置其實就可以了。比如,用pipeline方式創建一個如下的Jenkins構建任務:
這裏寫圖片描述

pipeline scripts的內容如下:

/* cloud字段指定系統設置裏配置的Kubernetes雲的名字,本例用的是:Kubernetes */
podTemplate(label: 'mypod', cloud: 'Kubernetes') {
    node('mypod') {
        stage('Run shell') {
            sh 'echo hello world'
        }
    }
}

這裏是一個簡單的示例,此插件的更多pipeline寫法可以參考: https://github.com/jenkinsci/kubernetes-plugin

點擊Jenkins任務構建,觀察會自動生成作爲slave節點的Pod:
這裏寫圖片描述

運行成功的Jenkins任務輸出日誌裏,可以看到運行的slave節點名:
這裏寫圖片描述

等任務構建完成之後,會發現slave節點又動態的消失了:
這裏寫圖片描述

以上,就完成了我們希望通過Kubernetes Plugin來完成Jenkins Slave節點動態創建和回收的目的。

製作自己的slave節點鏡像

上面雖然已經可以實現Jenkins Slave節點的動態創建和回收了,但是使用的是默認的slave鏡像:jenkinsci/jnlp-slave。在Jenkins觸發任務構建的時候,kubernetest plugin會先去公共的docker倉庫獲取這個鏡像,然後運行容器作爲slave節點。實際使用中,我們往往希望用自己預裝了一些軟件的鏡像來做slave節點,來完成我們需要的構建任務。這裏就可以參考jenkinsci/jnlp-slave(https://github.com/jenkinsci/docker-jnlp-slave)的製作,來做自己的slave節點鏡像。

Jenkins slave連接Server的方法

Jenkins Server和slave節點直接有幾種連接方式:ssh連接和jnlp連接。Kubernetes plugin插件用的是jnlp方式。這種方式是通過運行slave.jar,指定Jenkins Server的url參數和secret token參數,來建立連接。

jenkinsci/jnlp-slave鏡像是以jenkinsci/slave (https://github.com/jenkinsci/docker-slave)爲基礎鏡像製作的。參考這兩個鏡像的Dockerfile,做一個自己的:

FROM my.example.com/library/centos7.4-ssh-docker-maven:latest

ENV HOME /home/jenkins
ARG AGENT_WORKDIR=/home/jenkins/agent

COPY slave.jar /usr/share/jenkins/slave.jar
COPY jenkins-slave /usr/local/bin/jenkins-slave

RUN groupadd -g 1000 jenkins \
  && useradd -c "Jenkins user" -d $HOME -u 1000 -g 1000 -m jenkins \
  && chmod 755 /usr/share/jenkins \
  && chmod 644 /usr/share/jenkins/slave.jar 

USER jenkins
ENV AGENT_WORKDIR=${AGENT_WORKDIR}
RUN mkdir /home/jenkins/.jenkins && mkdir -p ${AGENT_WORKDIR}

VOLUME /home/jenkins/.jenkins
VOLUME ${AGENT_WORKDIR}
WORKDIR /home/jenkins

ENTRYPOINT ["jenkins-slave"]

說明:這裏的基礎鏡像是用的自己之前製作的基於centos的鏡像(默認的jnlp-slave鏡像是基於ubuntu系做的)。slave.jar這個包,可以在自己Jenkins Server的訪問地址後添加/jnlpJars/slave.jar路徑來獲取到(如:http://your-jenkins-server/jnlpJars/slave.jar)。jenkins-slave這個腳本,可以在 https://github.com/jenkinsci/docker-jnlp-slave/blob/master/jenkins-slave 下載到。

使用docker build命令將上面的Dockerfile製作成鏡像之後,上傳到自己的docker私有倉庫來供k8s獲取就可以了。

指定使用自制的slave節點鏡像

pipeline類型的方式

要想使用自己的slave節點鏡像,在配置pipeline腳本的時候,就需要參數指明瞭。

podTemplate(label: 'mypod-1', cloud: 'Kubernetes', containers: [
    containerTemplate(
        name: 'jnlp', 
        image: 'my.example.com/library/centos7.4-ssh-docker-maven-jenkins-slave:2.19', 
        alwaysPullImage: true, 
        args: '${computer.jnlpmac} ${computer.name}'),

  ],
  volumes: [
    hostPathVolume(mountPath: '/var/run/docker.sock', hostPath: '/var/run/docker.sock'),
],) 
{
    node('mypod-1') {
        stage('Task-1') {
            stage('show release version') {
                sh 'cat /etc/redhat-release '
            }
        }
    }
}

說明: containerTemplate的name屬性必須叫jnlp,才能用images指定的鏡像替換默認的jenkinsci/jnlp-slave鏡像。此外,還要args參數傳遞兩個jenkins-slave運行需要的參數。

非pipeline類型的方式

如果不使用pipeline類型任務的話,要想使用kubernetes plugin的雲構建任務,還需要回到【系統設置】-【雲】-【Kubernetes】-【Add Pod Template】裏面繼續配置
這裏寫圖片描述
這裏有兩點需要注意:Labels和Containers下的Name字段的名字配置。Labels名在配置非pipeline任務時,用來指定任務運行的節點。
這裏寫圖片描述
Name名則必須叫jnlp,才能用指定的Docker image代替默認的jenkinsci/jnlp-slave鏡像,否則,你配的不叫jnlp的容器會被運行,但是Kubernetes plugin還是會用默認的jenkinsci/jnlp-slave鏡像與Jenkins Server建立連接。

發佈了101 篇原創文章 · 獲贊 48 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章