基于K8s的Jenkins持续集成实战(上)

2020-03-25 17:55:34 浏览数 (1)

Jenkins是一款广泛受到的欢迎的持续集成工具,有着丰富的插件以及扩展能力,基本上能够满足大多数团队的需求。本文将从工具使用的角度,来讲述如何在kubernetes集群中使用Jenkins作为持续集成工具。

权限控制

K8s采用RBAC进行权限管理,Jenkins流水线需要相关的权限才能正确运行。所以,我们先创建一个jenkins.yaml的文件,以便向集群申明Jenkins需要的权限,内容如下:

代码语言:javascript复制
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins
  namespace: ops

---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: jenkins
  namespace: ops
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
  resources: ["pods/portforward"]
  verbs: ["*"]
- 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: RoleBinding
metadata:
  name: jenkins
  namespace: ops
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins
subjects:
- kind: ServiceAccount
  name: jenkins
  namespace: ops

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: jenkinsClusterRole
  namespace: ops
rules:
- 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: jenkinsClusterRuleBinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: jenkinsClusterRole
subjects:
- kind: ServiceAccount
  name: jenkins
  namespace: ops

这段代码做了这么几件事情:首先是在ops命名空间下创建了一个名为jenkins的account;然后在同一个空间下创建了一个新的角色,并申明了这个角色具备的操作权限;接下来将这个角色和前面创建的账号绑定在一起;最后因为涉及到cluster级别的一些操作,因此创建了ClusterRole,并同样进行了绑定。

持久化

Jenkins中的任务状态、数据等需要持久化下来,因此有必要提前做好准备。创建了另外一个名为jenkins-pvc.yaml的文件,内容如下:

代码语言:javascript复制
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: jenkins-pvc
  namespace: ops
spec:
  storageClassName: "ceph-rbd"
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1024Gi

这一部分需要根据大家的根据实际情况变通,我这里是继续在ops中创建了一个名为jenkins-pvc的PersistentVolumeClaim,底层是使用的ceph作为StorageClass,然后这个存储的大小我申请的是1024G。

部署运行

前面万事已具备,现在只差部署Jenkins了。创建了一个名为jenkins-deployment.yaml的文件,内容如下:

代码语言:javascript复制
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: jenkins
  namespace: ops
  labels:
    app-name: jenkins
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app-name: jenkins
    spec:
      serviceAccount: jenkins
      containers:
      - name: jenkins
        image: jenkins/jenkins:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: web
          protocol: TCP
        - containerPort: 50000
          name: agent
          protocol: TCP
        volumeMounts:
        - name: jenkins-home
          mountPath: /var/jenkins_home
          readOnly: false
        env:
        - name: JAVA_OPTS
          value: "-Duser.timezone=Asia/Shanghai -XX: UnlockExperimentalVMOptions -XX: UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85"
        securityContext:
          runAsUser: 0
      volumes:
      - name: jenkins-home
        persistentVolumeClaim:
          claimName: jenkins-pvc

这里在ops命名空间创建了一个叫做jenkins的Deployment资源,然后重点看看template中的主要内容,可以看到在spec中申明了要使用前面准备好的ServiceAccount。然后这个应用需要使用两个端口,一个是8080,用于提供web界面,另外一个是50000端口,Jenkins中的slave节点和master通信的时候会用到。最后在volumes中申明了要使用前面准备好的pvc做持久化存储。

此时,你可以通过执行kubectl apply -f *来应用这些yaml文件,成功之后你会看到在ops下会有名为jenkins的deploment、以及jenkins开头的pod的存在。

Service 和 Ingress

经过前面的步骤,Jenkins已经正常启动起来了。命令行里会输出初始的密码,接下来需要做的就是用这个初始密码登录Jenkins。 那么问题就来了,我们目前仅仅是把Jenkins运行了起来,并没有办法在集群外部很方便地访问到它,也没办法完成Jenkins的初始化工作。因此,接下来需要为应用创建Ingress。创建一个新的yaml文件,内容如下:

代码语言:javascript复制
kind: Service
apiVersion: v1
metadata:
  labels:
    app-name: jenkins
  name: jenkins
  namespace: ops
spec:
  ports:
  - port: 8080
    targetPort: 8080
    name: web
  - port: 50000
    targetPort: 50000
    name: agent
  selector:
    app-name: jenkins

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: jenkins-http-route
  namespace: ops
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`jenkins.your-domain.com`)
      kind: Rule
      services:
        - name: jenkins
          port: 8080

这里只提一点,就是集群中使用的是Traefik 2.0作为Ingress Controller,所以不能在直接创建Ingress,而是要创建IngressRoute的资源才能让服务变得可访问。(关于Traefik 2.0和Ingress Route的知识,可以查看之前的文章)

现在你应该可以在浏览器里通过你的域名访问到jenkins了,按照默认向导进行初始化就可以了,如果遇到插件安装失败可以直接跳过,后面可以更换下载源或者手动安装即可。在下一篇文章中,我们将在此基础上安装需要的插件然后创建一条流水线把Jenkins用起来。

0 人点赞