Jenkins节点配置-K8S云节点

一、部署jenkins

pv/pvc

touch pv_jenkins.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: jenkins
spec:
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs-jenkins
  nfs:
    path: /data/jenkins/
    server: 10.61.150.21

---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-jenkins
  namespace: servers
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
  storageClassName: nfs-jenkins

创建jenkins的serviceaccount

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: jenkins
  name: service-reader
rules:
  - apiGroups: [""] # "" indicates the core API group
    resources: ["services"]
    verbs: ["get", "watch", "list"]
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["create","delete","get","list","patch","update","watch"]
  - apiGroups: [""]
    resources: ["pods/exec"]
    verbs: ["create","delete","get","list","patch","update","watch"]
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get","list","watch"]
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get"]
#在jenkins命名空间下创建一个服务账号jenkins
#kubectl create serviceaccount jenkins -n jenkins -o yaml
kubectl create serviceaccount jenkins -n servers

#创建一个名为“service-reader-pod”的集群角色绑定,它的“clusterrole”是“service-reader”,它的名字是“default:default”,其中第一个“default”是名空间(namespace),第二个“default”是服务账户名字

kubectl create clusterrolebinding service-reader-pod --clusterrole=service-reader  --serviceaccount=servers:jenkins

修改jenkins镜像

注意:

  • 创建dockerfile,使用root权限,否则会报错无权限
  • 最新的jenkins版本是jenkins/jenkins 别用错
FROM hub.ict.ac.cn/jenkins/jenkins:latest
USER root

svr

apiVersion: v1
kind: Service
metadata:
  name: k8sdemo-jenkins-service
  namespace: servers
  labels:
    app: k8sdemo-jenkins
spec:
  type: NodePort
  selector:
    app: k8sdemo-jenkins
  ports:
    - port: 8080
      name: http
      protocol : TCP
      nodePort: 30080
      targetPort: 8080
    - port: 50000
      name: agent
      protocol: TCP
      targetPort: 50000

访问

可以用“http://IP:30080/” 访问Jenkins。

配置插件安装代理

方案1.配置插件代理

升级站点的地址改为:
这个 URL 改成
http://mirror.xmission.com/jenkins/updates/update-center.json
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

方案2.使用反向代理连接网络:https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json
方案3.下载插件后离线安装:http://updates.jenkins-ci.org/download/plugins/

需要下载插件列表:

插件名 功能
docker docker
Localization: Chinese 汉化
thinbackup 备份
Kubernetes K8S插件
Blue Ocean 新款UI

二、配置Kubernetes Plugin

  1. name使用默认的'Kubernetes'就可以,配置Pipelines时会用到。

  2. Kubernetes URL,是要K8S集群的地址,我们的jenkins在K8S集群里部署的,所以直接用 “https://kubernetes.default” 就可以了。设置之后点击“Test Connection”,见到“
    Connected to Kubernetes 1.16”就成功了。

  3. Jenkins URL就是Jenkins的访问地址,用http://jenkins.default就可以了。可能是没在jenkins上设置的缘故,这个地址集群没有解析成功,导致在测试节点的时候JNLP一直ERROR。我修改成jenkins的访问地址就可以了(就是打开jenkins界面的地址别想多了,有反向代理的就填VIP)

  1. Jenkins tunnel”,这个参数是Jenkins Master和Jenkins Slave之间通信必须配置的。很多文章都没有说要配这个,但是很明确的告诉你,不配置不行(我把这个写上,绝对良心帖)地址也很简单,使用你jenkins的service的集群地址+50000就可以了。

三、测试

有几个需要说明的地方:

  1. pipeline有两种语法大家都是知道的,所以呢在K8S插件使用上也支持两种语法的设置。具体的格式参照K8S插件的官方
  2. 新版的K8S插件不需要设置label,jenkins会自动生成一个,节点使用POD_LABEL环境变量引用就可以了。
  3. 在pipeline中先定义podTemplate,在podTemplate中定义containerTemplate,分别有很多可设置的参数,也参照官方设定(用于脚本式)。以下例子中由于我的集群大部分服务器是离线的,为了下载镜像方便使用nodeSelector把节点固定调度到一个可连网的K8S-NODE上。

测试master

podTemplate(nodeSelector: 'kubernetes.io/hostname=ict-94',cloud: "kubernetes"){
	node(POD_LABEL){
		stage('Run shell'){
			sh 'echo hello world'
		}
	}
}

测试节点

这个测试节点的自动创建、销毁、伸缩、分组。是我们最主要的目标

脚本式pipeline编写


#maven-jlnp:latest是我自己制作的镜像,下一节会说怎么制作。
podTemplate(nodeSelector: 'kubernetes.io/hostname=ict-94',cloud: 'kubernetes',containers: [
    containerTemplate(
        name: 'jnlp', 
        image: 'hub.ict.ac.cn/jenkins/maven-jlnp:latest', 
        alwaysPullImage: false, 
        args: '${computer.jnlpmac} ${computer.name}'),
  ]) {

    node(POD_LABEL) {
        stage('stage1') {
            stage('Show Maven version') {
                sh 'mvn -version'
                sh 'sleep 60s'
            }
        }
    }
}

声明式pipeline编写


#yaml对POD的定义和K8S的一样,例如imagePullPolicy
#在使用自定义镜像的时候,name只能使用jnlp。这个有待考证

pipeline {
  agent {
    kubernetes {
      yaml """
apiVersion: v1
kind: Pod
metadata:
  labels:
    agent: test
spec:
  containers:
  - name: jnlp
    image: hub.ict.ac.cn/jenkins/maven-jlnp:latest
    imagePullPolicy: IfNotPresent
    tty: true
"""
    }
  }
  stages {
    stage('Run maven') {
      steps {
        container('jnlp') {
          sh 'mvn -version'
        }
      }
    }
  }
}

测试群组

  • 查看pod可以发现同时运行了包括jnlp在内的3个pod
  • 也就是说一个任务如果需要分别编译前端的代码和后端的代码的时候,就可以分别使用两个容器编译
podTemplate(nodeSelector: 'kubernetes.io/hostname=ict-94',containers: [
    containerTemplate(name: 'maven', image: 'maven:3.3.9-jdk-8-alpine', ttyEnabled: true, command: 'cat'),
    containerTemplate(name: 'golang', image: 'golang:1.8.0', ttyEnabled: true, command: 'cat')
  ]) {

    node(POD_LABEL) {
        stage('Get a Maven project') {
            git 'https://github.com/jenkinsci/kubernetes-plugin.git'
            container('maven') {
                stage('Build a Maven project') {
                    sh 'mvn -B clean install'
                }
            }
        }

        stage('Get a Golang project') {
            git url: 'https://github.com/hashicorp/terraform.git'
            container('golang') {
                stage('Build a Go project') {
                    sh """
                    mkdir -p /go/src/github.com/hashicorp
                    ln -s `pwd` /go/src/github.com/hashicorp/terraform
                    cd /go/src/github.com/hashicorp/terraform && make core-dev
                    """
                }
            }
        }

    }
}
pipeline {
  agent {
    kubernetes {
      yaml """
apiVersion: v1
kind: Pod
metadata:
  labels:
    some-label: some-label-value
spec:
  containers:
  - name: maven
    image: maven:alpine
    command:
    - cat
    tty: true
  - name: busybox
    image: busybox
    command:
    - cat
    tty: true
"""
    }
  }
  stages {
    stage('Run maven') {
      steps {
        container('maven') {
          sh 'mvn -version'
        }
        container('busybox') {
          sh '/bin/busybox'
        }
      }
    }
  }
}

在jenkins中配置podTemplate

如果我们使用非Pipeline的方式运行任务, 比如自由风格的,就需要在K8S插件下继续配置POD模板。

  • Labels 配置pod的标签,在新建任务的时候会调用
  • Name 指定运行pod的名称,要注意的是,如果 Name 配置为 jnlp,那么 Kubernetes 会用下边指定的 Docker Image 代替默认的 jenkinsci/jnlp-slave 镜像,否则,Kubernetes plugin 还是会用默认的 jenkinsci/jnlp-sla ve 镜像与 Jenkins Server 建立连接,即使我们指定其他 Docker Image。这里我随便配置为 jnlp-slave,意思就是使用默认的 jenkinsci/jnlp-slave 镜像来运行,因为我们暂时还没制作可以替代默认镜像的镜像。
    “系统管理” —> “系统设置” —> “云” —> “Kubernetes” —> “Add Pod Template”

新建一个自由风格的任务
指定label,需要和上述配置pod模板的label一致,和k8S的节点没有关系。我这里的label值就是一个k8s节点的label,测试和K8S节点无关,需要和上述的label一致。

构建

输出

四、制作自己的slave节点

通过 kubernetest plugin 默认提供的镜像 jenkinsci/jnlp-slave 可以完成一些基本的操作,它是基于 openjdk:8-jdk 镜像来扩展的,但是对于我们来说这个镜像功能过于简单,比如我们想执行 Maven 编译或者其他命令时,就有问题了,那么可以通过制作自己的镜像来预安装一些软件,既能实现 jenkins-slave 功能,又可以完成自己个性化需求,那就比较不错了。如果我们从头开始制作镜像的话,会稍微麻烦些,不过可以参考 jenkinsci/jnlp-slave 和 jenkinsci/docker-slave 这两个官方镜像来做,注意:jenkinsci/jnlp-slave 镜像是基于 jenkinsci/docker-slave 来做的。这里我简单演示下,基于 jenkinsci/jnlp-slave:latest 镜像,在其基础上做扩展,安装 Maven 到镜像内,然后运行验证是否可行吧。

maven

#制作镜像
FROM jenkins/jnlp-slave:latest
MAINTAINER huwanyang168@163.com
LABEL Description="This is a extend image base from jenkins/jnlp-slave which install maven in it."
# 切换到 root 账户进行操作
USER root
# 安装 maven-3.3.9
RUN wget http://mirrors.sonic.net/apache/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz && \
    tar -zxf apache-maven-3.3.9-bin.tar.gz && \
    mv apache-maven-3.3.9 /usr/local && \
    rm -f apache-maven-3.3.9-bin.tar.gz && \
    ln -s /usr/local/apache-maven-3.3.9/bin/mvn /usr/bin/mvn && \
    ln -s /usr/local/apache-maven-3.3.9 /usr/local/apache-maven
USER jenkins
~~~
`docker build -t maven-jlnp:latest .`

kubectl create secret docker-registry secret-harbor --namespace=my-docs
--docker-server=http://harbor.shanhy.com:81 --docker-username=admin
--docker-password=harbor123456789

测试

def label = "mypod-${UUID.randomUUID().toString()}"
podTemplate(label: label, cloud: 'kubernetes',containers: [
    containerTemplate(
        name: 'jnlp', 
        image: 'hub.ict.ac.cn/jenkins/maven-jlnp:latest', 
        alwaysPullImage: false, 
        args: '${computer.jnlpmac} ${computer.name}'),
  ]) {
    node(label) {
        stage('stage1') {
            stage('Show Maven version') {
                sh 'mvn -version'
                sh 'sleep 60s'
            }
        }
    }
}

npm

#dockerfile
FROM jenkins/jnlp-slave:latest
USER root
RUN wget https://nodejs.org/dist/v12.18.4/node-v12.18.4-linux-x64.tar.gz && \
    tar -zxvf node-v12.18.4-linux-x64.tar.gz && \
    mv node-v12.18.4-linux-x64 nodejs && \
    rm -f apache-maven-3.3.9-bin.tar.gz && \
    ln -s /home/jenkins/nodejs/bin/npm /usr/bin/npm && \
    ln -s /home/jenkins/nodejs/bin/node /usr/bin/node

USER jenkins
#pipeline
pipeline {
  agent {
    kubernetes {
      yaml """
apiVersion: v1
kind: Pod
metadata:
  labels:
    agent: jlnp_npm
spec:
  containers:
  - name: jnlp
    image: hub.ict.ac.cn/jenkins/jlnp-nmp:v1
    imagePullPolicy: IfNotPresent
    imagePullSecrets:
    - name: harbor31
    tty: true
"""
    }
  }
  stages {
    stage('Run npm') {
      steps {
        container('jnlp') {
          sh 'npm -v'
        }
      }
    }
  }
}

参考文章:
https://blog.csdn.net/aixiaoyang168/article/details/79767649
https://plugins.jenkins.io/kubernetes/
https://www.cnblogs.com/shawhe/p/11313633.html
https://blog.csdn.net/weixin_38748858/article/details/102898043
http://updates.jenkins-ci.org/download/plugins/

posted @ 2020-09-29 18:07  名字很长容易被惦记  阅读(3922)  评论(0编辑  收藏  举报