介绍

本文是基于云原生概念使用jenkins **Pipeline流水线 **项目声明式脚本形式进行SpringBoot项目持续构建和发布的实战教程.

环境

项目需要环境 Gitlab、Kubernetes集群、Jenkins
k8s集群和Gitlab 搭建将在后续整理,本次只介绍Jenkins的安装配置以及Pipeline的使用

Jenkins安装

GitHub jenkinsci kubernetes-plugin 官网提供的 jenkins.yamlservice-account.yaml 文件,这里官网使用的是比较规范的 StatefulSet(有状态集群服务)方式进行部署,并配置了 Ingress 和 RBAC 账户权限信息。

创建jenkins-1-namespace.yaml 创建新的命名空间

apiVersion: v1
kind: Namespace
metadata:
  name: jenkins

创建jenkins-2-rbac.yaml RBAC账户权限信息

apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-sa
  namespace: jenkins

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: jenkins-cr
rules:
  - apiGroups: ["extensions", "apps"]
    resources: ["deployments"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
  - 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"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: jenkins-crd
roleRef:
  kind: ClusterRole
  name: jenkins-cr
  apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
  name: jenkins-sa
  namespace: jenkins

创建jenkins-3-storage.yaml pvc

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: jenkins-pv
  labels:
    app: jenkins
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  glusterfs:
      endpoints: glusterfs-cluster
      path: k8s-jenkins
      readOnly: false
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-pvc
  namespace: jenkins
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  selector:
    matchLabels:
      app: jenkins

创建jenkins-4-deploy.yaml jenkins服务

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins
  namespace: jenkins
spec:
  replicas: 1
  selector:
    matchLabels:
      app: jenkins
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      terminationGracePeriodSeconds: 10
      serviceAccount: jenkins-sa
      containers:
      - name: jenkins
        image: 192.168.*.*/dev/jenkins:jdk8
        imagePullPolicy: IfNotPresent
        command: [ "/bin/bash", "-ce", "/usr/local/bin/jenkins.sh" ]
        env:
        - name: JAVA_OPTS
          value: -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 -Duser.timezone=Asia/Shanghai
        ports:
        - containerPort: 8080
          name: web
          protocol: TCP
        - containerPort: 50000
          name: agent
          protocol: TCP
        #resources:
        #  limits:
        #    cpu: 1000m
        #    memory: 1Gi
        #  requests:
        #    cpu: 500m
        #    memory: 512Mi
        livenessProbe:
          httpGet:
            path: /login
            port: 8080
          initialDelaySeconds: 60
          timeoutSeconds: 5
          failureThreshold: 12
        #readinessProbe:
        #  httpGet:
        #    path: /login
        #    port: 8080
        #  initialDelaySeconds: 60
        #  timeoutSeconds: 5
        #  failureThreshold: 12
        volumeMounts:
        - name: jenkinshome
          mountPath: /var/jenkins_home
      securityContext:
        fsGroup: 1000
      volumes:
      - name: jenkinshome
        persistentVolumeClaim:
          claimName: jenkins-pvc

---
apiVersion: v1
kind: Service
metadata:
  name: jenkins
  namespace: jenkins
  labels:
    app: jenkins
spec:
  selector:
    app: jenkins
  type: NodePort
  ports:
  - name: web
    port: 8080
    targetPort: web
    nodePort: 32000
  - name: agent
    port: 50000
    targetPort: agent

创建jenkins-5-ingress.yaml Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: jenkins-ingress
  namespace: jenkins
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: "jenkins.hifun.prod"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: jenkins
            port:
              number: 8080

** 创建jenkins-6-maven-pvc.yaml** maven挂载pvc

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: jenkins-maven-pvc
  namespace: jenkins
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn
  resources:
    requests:
      storage: 10Gi

切换新的命名空间, 创建jenkins服务

 kubectl create -f jenkins-1-namespace.yaml
 kubectl config set-context $(kubectl config current-context) --namespace=jenkins
 kubectl create -f jenkins-2-rbac.yaml
 kubectl create -f jenkins-3-storage.yaml
 kubectl create -f jenkins-4-deploy.yaml
 kubectl create -f jenkins-5-ingress.yaml
 kubectl create -f jenkins-6-maven-pvc.yaml

运行命令查看服务

kubectl get pod,service,pvc,deployment -n jenkins

NAME                           READY   STATUS    RESTARTS   AGE
pod/jenkins-65fd8c5cd6-sp82c   1/1     Running   0          24h

NAME                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                          AGE
service/jenkins             NodePort    0.0.0.0   <none>        8080:32000/TCP,50000:30573/TCP   36d

NAME                                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/jenkins-maven-pvc   Bound    pvc-67d7cc98-315e-45fb-9b63-93df3a45768e   10Gi       RWO            longhorn       154m
persistentvolumeclaim/jenkins-pvc         Bound    jenkins-pv                                 10Gi       RWX                           43d

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/jenkins   1/1     1            1           36d

通过浏览器打开 http://:32000

初始化过程中,让输入 /var/jenkins_home/secret/initialAdminPassword 初始密码, 执行

$ kubectl exec -it jenkins-65fd8c5cd6-sp82c cat /var/jenkins_home/secrets/initialAdminPassword

获取密码后下一步, 开始初始化插件安装, 等安装完成后(如部分插件安装失败可以先跳过, 之后在系统设置>插件管理 继续安装)
在这里插入图片描述
登录后, 查看插件
在这里插入图片描述
在这里插入图片描述

Pipeline流水线

新建任务, 选择流水线项目
在这里插入图片描述
在流水线定义栏选择 Pipeline script ,输入以下内容, 点击应用>保存.(其他忽略)

pipeline{
    agent any
    stages{
        stage("demo"){
            steps{
                echo "hello pipeline"
            }
        }
    }
}

在这里插入图片描述
创建完成后, 点击立即构建, 可以看到输出以下内容
在这里插入图片描述
至此jenkins安装, 测试Pipeline结束

配置Kubernetes集群

在jenkins控台搜索kubernetes插件并下载,安装成功后重启jenkins
然后进入系统管理>节点管理>配置集群
在这里插入图片描述
添加一个新的集群
在这里插入图片描述
配置集群, 应用并保存,证书详见下方生成说明
在这里插入图片描述
在这里插入图片描述
点击连接测试, 出现k8s信息则表示成功

kubernetes集群证书生成

在Kubernetes Master

cat /root/.kube/config
# 复制client-certificate-data的内容,运行以下命令生成client.crt
echo "<client-certificate-data>" | base64 -d > client.crt
# 复制client-key-data的内容,运行以下命令生成client.key
echo "<client-key-data>" | base64 -d > client.key
# 复制certificate-authority-data的内容,运行以下命令生成ca.crt
echo "<certificate-authority-data>" | base64 -d > ca.crt
# 根据前面步骤生成的ca.crt, client.crt和client.key来生成PKCS12格式的cert.pf
# 运行以下命令
openssl pkcs12 -export -out cert.pfx -inkey client.key -in client.crt -certfile ca.crt
#输入证书密码

将生成的Kubernetes Client P12 Certificate cert.pfx 证书下载到本地, 在集群配置选择添加jenkins凭据

在这里插入图片描述
在这里插入图片描述
将ca.crt内容填充到 Kubernetes 服务证书 key

cat ca.crt

添加构建pod模板

为了能够完成项目构建, 我们需要 jenkins-slave子节点、maven环境、docker环境,为了第一次方便一步步尝试, 我们需要创建三个 Pod Template
在这里插入图片描述

jenkins-slave
我们最先需要的是一个jenkins的构建节点,配置如下
在这里插入图片描述
在这里插入图片描述
此时我们可以新建一个pipeline项目demo2, 来测试jenkins-slave,这个容器中会有一个jdk环境,可以进行如下测试, kubernetes为集群, inheritfrom指定我们构建使用的pod标签, 在容器内运行 java -version

pipeline{
    agent {
        kubernetes{
            inheritFrom 'jenkins-slave'
        }
    }
    
    stages {
        stage ("dierci") {
            steps {
                sh 'java -version'
            }
        }
    }
}

在这里插入图片描述
maven pod
创建构建需要的maven环境, 配置如下
在这里插入图片描述
maven每次构建项目都要去拉取jar包,重复构建肯定会浪费很多时间, 因此我们为pod添加一个pvc, 此处的 jenkins-maven-pvc就是上面jenkins-6-maven-pvc.yaml创建的pvc
在这里插入图片描述
创建新的pipeline工程进行测试, 这里注意我们用的就是集群里我们刚刚创建的maven-3.6 pod了,可以看下mvn 的版本

pipeline{
    agent {
        kubernetes{
            inheritFrom 'maven-3.6'
        }
    }
    
    stages{
        stage("maventest"){
            steps{
                container('maven'){
                    sh 'mvn -version'
                } 
            }
        }
    }
}

在这里插入图片描述
docker pod
在jenkins管理中心安装插件 docker 和 docker pipeline
配置docker pod
在这里插入图片描述
此处我们还要配置一个特殊的卷,使得我们的容器内的docker能够访问到宿主机上面的docker.sock文件
在集群主节点运行命令获取文件目录, 获取到的路径直接添加到pod模板新增卷 Host Path Volume下

find / -iname "*docker.sock"

在这里插入图片描述
我们在准备好的springboot项目文件夹根目录创建DockerFile文件

FROM java:8 
EXPOSE 8080 
VOLUME /slm 
ADD boot-docker-0.0.1-SNAPSHOT.jar boot-docker.jar 
RUN sh -c 'touch /boot-docker.jar' 
ENV JAVA_OPTS="" 
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /boot-docker.jar" ] 

创建新的jenkins工程boot-docker流水线任务
环境变量environment
agent使用kubernetes集群下我们刚建的pod模板docker-and-maven
此处为了方便, 我们没有配置git凭据, 而是采用了http方式使用gitlab账户的token进行代码拉取
编译项目
创建docker镜像, 登录docker, 推送镜像
在这里插入图片描述
构建完成后,就可以登录Harbor查看自己的镜像了, 后续还会持续构建, 并在pipeline中完成项目的启动与健康检查

此博文部分参考自b站马哥教育基于Kubernetes和Jenkins的GitOps实战

Logo

开源、云原生的融合云平台

更多推荐