K8S - Jenkins在K8S下的持续集成

image

关于搭建Kubernetes环境可以参考我前面的公众号文章:Centos7下使用kubeadm搭建Kubernetes-v1.14.2,本篇文章主要实现Jenkins在k8s集群的安装、slave节点在k8s内自动创建销毁,通过pipeline实现java项目的持续集成发布。

安装Jenkins服务到K8S集群

使用Dockerfile制作Jenkins镜像

下载war包进行的安装,Dockerfile如下,war包下载地址:https://jenkins.io/zh/download

FROM java:8
RUN echo 'hello docker, start build image'

RUN mkdir -p /app
WORKDIR /app

RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo "Asia/Shanghai" > /etc/timezone

COPY jenkins.war .

CMD ["java" ,"-Xms1024m","-Xmx1024m", "-jar","/app/jenkins.war"]

制作镜像

docker build -t registry.cn-hangzhou.aliyuncs.com/hiningmeng/jenkins:2.176.2  .

docker push registry.cn-hangzhou.aliyuncs.com/hiningmeng/jenkins:2.176.2

K8S安装Jenkins应用

在k8s集群内创建Jenkins工作的namespace,我这边统一放在devops这个ns底下;

kubectl create ns devops

我这里把Jenkins工作目录单独挂载到PVC,需要先创建pv-pvc,挂载点是使用的nfs服务,请先创建好服务,jenkins-pv-pvc.yaml如下:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: jenkins-home-pv
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 192.168.1.100
    path: "/data/jenkins_home"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-home-pvc
  namespace: devops
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 100Gi

为Jenkins创建单独的ServiceAccount,这里的ClusterRole直接使用的cluster-admin,jenkins-serveraccount.yaml如下;

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

编写Deployment文件,我使用到了node标签apps.k8s.icjl/devops,打标签的命令如下:

kubectl label node your-node-name apps.k8s.icjl/devops=

jenkins-deployment.yaml如下:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: jenkins
  namespace: devops
  labels:
    app: jenkins
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      serviceAccountName: jenkins-admin
      imagePullSecrets:
        - name: ram-secret
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: apps.k8s.icjl/devops
                operator: Exists
      containers:
      - name: jenkins
        image: registry.cn-hangzhou.aliyuncs.com/hiningmeng/jenkins:2.176.2
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: jenkins-home
          mountPath: /root/.jenkins
          readOnly: false
        ports:
        - containerPort: 8080
        - containerPort: 50000
      volumes:
      - name: jenkins-home
        persistentVolumeClaim:
          claimName: jenkins-home-pvc

创建service,这边使用了NodePort,jenkins-service.yaml如下;

apiVersion: v1
kind: Service
metadata:
  labels:
    app: jenkins
  name: jenkins
  namespace: devops
  annotations:
    prometheus.io/scrape: 'true'
spec:
  type: NodePort
  ports:
  - name: jenkins-web
    port: 8080
    targetPort: 8080
    nodePort: 31442
  - name: jenkins-agent
    port: 50000
    targetPort: 50000
    nodePort: 30005
  selector:
    app: jenkins

也可以使用ingress暴露的方式,jenkins-ingress.yaml如下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: jenkins
  labels:
    name: jenkins
  namespace: devops
spec:
  rules:
  - host: jenkins.hiningmeng.cn
    http:
      paths:
      - path: /
        backend:
          serviceName: jenkins
          servicePort: 8080

执行

 kubectl apply -f jenkins-pv-pvc.yaml
 kubectl apply -f jenkins-serveraccount.yaml
 kubectl apply -f jenkins-deployment.yaml
 kubectl apply -f jenkins-service.yaml
 kubectl apply -f jenkins-ingress.yaml
image-20190806145150888

Jenkins配置

系统管理 --> 插件管理 --> available,安装需要的插件,有的插件下载不下来可以去官网下载之后上传安装。

  • Kubernetes
  • pipeline
  • Git Parameter
配置Kubernetes云信息

在系统管理 --> 系统设置 ,最后面有个Cloud设置,Add a new cloud


image

添加具体的Kubernetes信息,K8S服务器可以是Jenkins本身所在的服务器,也可以是其他集群(需要配置证书),这里以本身所在集群为例。

  • 名称 :用于pipeline调用云名称
  • Kubernetes地址:可以通过kubectl cluster-info命令获取
  • Kubernetes 服务证书 key:本身所在的集群因为我们通过sa所以不需要
  • Kubernetes 命名空间:Jenkins的nodePod节点启动的namespace
  • Jenkins 地址:主节点8080端口通过nodeport暴露出来的,地址:端口
  • Jenkins 通道:主节点50000端口通过nodeport暴露出来的,地址:端口
image
创建pipeline任务

选择新建任务,构建流水线。


image

安装了Git Parameter插件之后,可以进行分支的选择,需要进行参数化构建,这个可以在页面设置,也可以放到pipeline里面,这边直接在页面配置参数。


image

其中Use repository如果不设置,后面的Pipeline from SCRM的时候,就会取不到分支;

指定pipeline地址,可以直接在页面写,做好是通过Git的方式管理。


image

Git管理Pipeline的Jenkinsfile文件,需要提供证书拉取


image
编写Jenkinsfile文件
#定义参数label,K8S启动的pod名称通过这个来制定
def label = "JenkinsPOD-${UUID.randomUUID().toString()}"
#定义jenkins的工作目录
def jenworkspace="/home/jenkins/workspace/${params.PROJECT}"
#maven项目缓存,提供编译速度
def mvnrepo="/tmp/repository"
#kubectl和docker执行文件,这个可以打到镜像里面,这边直接共享的方式提供
def sharefile="/tmp/sharefile"
#deployment等K8S的yaml文件目录
def k8srepo='/tmp/k8s_repos'

#cloud为我们前面提供的云名称,nodeSelector是K8S运行pod的节点选择
podTemplate(label: label, cloud: 'kubernetes-hiningmeng',nodeSelector: 'devops.k8s.icjl/jenkins=jnlp',
    containers: [
        containerTemplate(
            name: 'jnlp',
            image: 'registry-vpc.cn-hangzhou.aliyuncs.com/hiningmeng/jnlp:v1',
            ttyEnabled: true,
            alwaysPullImage: false),
        containerTemplate(
            name: 'jnlp-maven',
            image: 'jenkins/jnlp-agent-maven',
            //image:'ungerts/jnlp-agent-maven',
            ttyEnabled: true,
            alwaysPullImage: false,
            command: 'cat')
    ],
    volumes: [
        hostPathVolume(hostPath: '/var/run/docker.sock', mountPath:'/var/run/docker.sock'),
        persistentVolumeClaim(mountPath: "$mvnrepo", claimName: 'maven-repo-pvc', readOnly: false),
        persistentVolumeClaim(mountPath: "$sharefile", claimName: 'sharefile-repo-pvc', readOnly: false),
    ]
)
{

    node (label) {
        stage('Hello World'){
            container('jnlp'){
                echo "hello, world"
                sh "ln -s $sharefile/kubectl  /usr/bin/kubectl"
                sh "ln -s $sharefile/docker /usr/bin/docker"

            }
        }
        stage('Git Pull'){
            dir("$jenworkspace"){
                git branch: "${params.BRANCH}", changelog: false, credentialsId: 'jenkins-pull-key', poll: false, url: "${params.CODE_URL}"
            }
        }
        stage('Mvn Package'){
            container('jnlp-maven'){
                dir("$jenworkspace"){
                    sh "mvn clean install -Dmaven.test.skip=true  -U  -s  $sharefile/settings.xml"
                }
            }
        }
        stage('Docker build'){
            ...
        }
        stage('K8S Deploy'){
            ...
        }
    }
}


具体的脚本还是自己摸索一下,不同的项目定制即可,大体的架子如上面的实例

构建项目
image

任务一次都没构建的时候会出现报错,构建一次就没问题了;

image

如果一切正常的话,在K8S的devops命名空间会创建出新的POD


image

至此,简单的可伸缩的基于K8S的Jenkins就完成了,如有问题欢迎交流。

你可能感兴趣的:(K8S - Jenkins在K8S下的持续集成)