jenkins pipeline

Jenkins流水线是一套插件,它支持实现和集成持续交付流水线到 Jenkins。流水线提供了一组可扩展的工具,用于通过流水线 DSL将简单到复杂的交付流水线建模为 “代码”。官网详解

持续集成和交付或CI / CD是DevOps最重要的部分,也是云原生的。CI / CD连接所有位。使用Kubernetes集群部署Jenkins服务器非常简单,允许在Kubernetes Pods内部构建和测试,重用kubernetes功能,如pod,构建映像,服务帐户,卷和秘密,同时提供弹性从属池(每个构建在新pod中运行).

Jenkins 安装

这里将 Jenkins 安装到 Kubernetes 集群当中,jenkinsci 地址

“为Jenkins创建一个namespace”

1
2
3
4
5
6
vim ns.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: kube-ops

“创建 jenkins deployment”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
vim jenkins-deploy.yaml

---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: jenkins
  namespace: kube-ops
spec:
  template:
    metadata:
      labels:
        app: jenkins
    spec:
      terminationGracePeriodSeconds: 10
      serviceAccountName: jenkins
      containers:
      - name: jenkins
        image: jenkins/jenkins:lts
        imagePullPolicy: IfNotPresent
        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
          subPath: jenkins
          mountPath: /var/jenkins_home
        env:
        - name: LIMITS_MEMORY
          valueFrom:
            resourceFieldRef:
              resource: limits.memory
              divisor: 1Mi
        - name: JAVA_OPTS
          value: -Xmx$(LIMITS_MEMORY)m -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 -Duser.timezone=Asia/Shanghai
      securityContext:
        fsGroup: 1000
      volumes:
      - name: jenkinshome
        persistentVolumeClaim:
          claimName: opspvc

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

“创建pvc”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
vim pvc.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: opspv
spec:
  capacity:
    storage: 20Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Delete
  nfs:
    server: 192.168.1.226
    path: /nfs/k8s

---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: opspvc
  namespace: kube-ops
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 20Gi

“给jenkins赋予权限”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
vim rbac.yam

apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins
  namespace: kube-ops

---

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: jenkins
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/v1beta1
kind: ClusterRoleBinding
metadata:
  name: jenkins
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: jenkins
subjects:
  - kind: ServiceAccount
    name: jenkins
    namespace: kube-ops
创建服务
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[[email protected] jenkins]# ls
jenkins-deploy.yaml  ns.yaml  pvc.yaml  rbac.yaml

[[email protected] jenkins]# kubectl create -f ns.yaml 
namespace/kube-ops created

[[email protected] jenkins]# kubectl create -f rbac.yaml
serviceaccount/jenkins created
clusterrole.rbac.authorization.k8s.io/jenkins created
clusterrolebinding.rbac.authorization.k8s.io/jenkins created

[[email protected] jenkins]# kubectl create -f pvc.yaml 
persistentvolume/opspv created
persistentvolumeclaim/opspvc created

[[email protected] jenkins]# kubectl create -f jenkins-deploy.yaml 
deployment.extensions/jenkins created
service/jenkins created

查看镜像已经拉下来了,但是pod还没有启起来,检查一下

1
2
3
4
5
6
kubectl describe po -n kube-ops jenkins-6f8db6c7fb-f9hfw
Warning  BackOff    2m27s (x18 over 5m9s)  kubelet, k8s-n4    Back-off restarting failed container

kubectl logs jenkins-6f8db6c7fb-f9hfw -n kube-ops
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?

思就是我们没有权限在 jenkins 的 home 目录下面创建文件,这是因为默认的镜像使用的是 jenkins 这个用户,而我们通过 PVC 挂载到 nfs 服务器的共享数据目录下面却是 root 用户的,所以没有权限访问该目录,要解决该问题,也很简单,我只需要在 nfs 共享数据目录下面把我们的目录权限重新分配下即可

1
2
3
4
5
chown -R 1000 /nfs/k8s/jenkins

kubectl get po -n kube-ops -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
jenkins-6f8db6c7fb-f9hfw   1/1     Running   0          22m   10.244.215.69   k8s-n1   <none>           <none>

打开浏览器 IP:30002 端口就可以访问 jenkins 服务了,可以根据提示信息进行安装配置即可,安装推荐插件 初始化的密码可以在 jenkins 的容器的日志中进行查看,也可以直接在 nfs 的共享数据目录中查看:

1
2
cat /nfs/k8s/secrets/initialAdminPassword 
1ea6e542fa4949c39db0c9488181d0bd

jenkins-dashbord

Jenkins 概述

传统的 Jenkins Slave 一主多从方式会存在一些缺点: - 主 Master 发生单点故障时,整个流程都不可用了 - 每个 Slave 的配置环境不一样,来完成不同语言的编译打包等操作,这些差异化的配置导致管理起来非常不方便,维护起来比较费劲 - 资源分配不均衡,有的 Slave 要运行的 job 出现排队等待,而有的 Slave 处于空闲状态 - 资源有浪费,每台 Slave 可能是物理机或者虚拟机,当 Slave 处于空闲状态时,也不会完全释放掉资源

在 Kubernetes 集群环境下面能够更好来解决上面的问题,Jenkins Master 和 Jenkins Slave 以 Pod 形式运行在 Kubernetes 集群的 Node 上,Master 运行在其中一个节点,并且将其配置数据存储到一个 Volume 上去,Slave 运行在各个节点上,并且它不是一直处于运行状态,它会按照需求动态的创建并自动删除

工作流程大致为:当 Jenkins Master 接受到 Build 请求时,会根据配置的 Label 动态创建一个运行在 Pod 中的 Jenkins Slave 并注册到 Master 上,当运行完 Job 后,这个 Slave 会被注销并且这个 Pod 也会自动删除,恢复到最初状态

服务高可用,当 Jenkins Master 出现故障时,Kubernetes 会自动创建一个新的 Jenkins Master 容器,并且将 Volume 分配给新创建的容器,保证数据不丢失,从而达到集群服务高可用 动态伸缩,合理使用资源,每次运行 Job 时,会自动创建一个 Jenkins Slave,Job 完成后,Slave 自动注销并删除容器,资源自动释放,而且 Kubernetes 会根据每个资源的使用情况,动态分配 Slave 到空闲的节点上创建,降低出现因某节点资源利用率高,还排队等待在该节点的情况 扩展性好,当 Kubernetes 集群的资源严重不足而导致 Job 排队等待时,可以很容易的添加一个 Kubernetes Node 到集群中,从而实现扩展

Jenkins Kubernetes 配置

点击系统管理-插件管理-可选插件,搜素kubernetes plugin 安装插件即可,完成安装后,点击系统管理-系统设置-下拉到最下方点击 新增一个云 选择kubernetes 然后填写信息 jenkins-pipeline

保存,新建一个pipeline任务 jenkins-pipelin-demo ,在下方流水线定义 pipeline script 脚本如下

1
2
3
4
5
6
7
podTemplate(label: 'jenkins-pod', cloud: 'kubernetes') {
    node('jenkins-pod') {
        stage('Run shell') {
            sh 'echo hello world'
        }
    }
}

保存配置,立即构建,观察k8s集群中pod的变化

1
kubectl get po -n kube-ops

我们可以看到一个新的pod被创建了,这就是我们的jenkins slave,任务执行完成后,我们可以看到任务在控制台的输出 pipeline-demo

到这里我们的任务已经构建完成,观察集群pod列表,发现kube-ops下面的slave自动终止