kubernetes(32):持續集成(1)-k8s集群中搭建Jenkins


k8s集群中搭建Jenkins

https://www.qikqiak.com/k8s-book/docs/36.Jenkins%20Slave.html

https://help.aliyun.com/document_detail/106712.html?spm=a2c4g.11186623.6.813.626e4330lQtSFi

 

基於Kubernete的CI/CD,可以使用的工具有很多,比如Jenkins、Gitlab CI已經新興的drone之類的,我還是最為熟悉的Jenkins來做CI/CD的工具。

Jenkins簡介jenkins(一):持續集成和Jenkins簡介

1 K8s集群安裝jenkins

1.1 新建命名空間

添加創建一個 namespace:

kubectl create namespace kube-ops

 

1.2 創建pv-pvc

我們將容器的 /var/jenkins_home 目錄掛載到了一個名為 opspvc 的 PVC 對象上面,所以我們同樣還得提前創建一個對應的 PVC 對象

kubernetes(13):k8s數據持久化-pv和pvc—NFS實現

 

mkdir /data/k8s
chown -R 1000 /data/k8s  #后面有坑,Jenkins權限問題,提前執行
apiVersion: v1
kind: PersistentVolume
metadata:
  name: opspv
spec:
  capacity:
    storage: 20Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Delete
  nfs:
    server: 10.6.76.25
    path: /data/k8s

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

 

 

[root@k8s-master ops]# kubectl  apply -f  pvc.yaml
persistentvolume/opspv created
persistentvolumeclaim/opspvc created
[root@k8s-master ops]#
[root@k8s-master ops]# kubectl get  pvc -n kube-ops
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
opspvc   Bound    opspv    20Gi       RWX                           60s
[root@k8s-master ops]# kubectl get  pv | grep ops
opspv                                                                               20Gi       RWX            Delete           Bound        kube-ops/opspvc                                                           73s
[root@k8s-master ops]# kubectl get  pvc -n kube-ops
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
opspvc   Bound    opspv    20Gi       RWX                           75s
[root@k8s-master ops]#

 

 

1.3 創建ServiceAccount配置權限

 

需要使用到一個擁有相關權限的 serviceAccount:jenkins,這里只是給 jenkins 賦予了一些必要的權限,給這個 sa 綁定一個 cluster-admin 的集群角色權限也是可以的,當然這樣具有一定的安全風險:(rbac.yaml)

 

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

---

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

 

[root@k8s-master ops]# kubectl  apply -f  rbac.yaml
serviceaccount/jenkins2 created
clusterrole.rbac.authorization.k8s.io/jenkins2 created
clusterrolebinding.rbac.authorization.k8s.io/jenkins2 created

 

1.4  創建Jenkins

通過 NodePort 的形式來暴露 Jenkins 的 web 服務,固定為30002端口,另外還需要暴露一個 agent 的端口,這個端口主要是用於 Jenkins 的 master 和 slave 之間通信使用的。

 

# cat jenkins2.yaml
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: jenkins2
  namespace: kube-ops
spec:
  template:
    metadata:
      labels:
        app: jenkins2
    spec:
      terminationGracePeriodSeconds: 10
      serviceAccount: jenkins2
      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: jenkins2
          mountPath: /var/jenkins_home
      securityContext:
        fsGroup: 1000
      volumes:
      - name: jenkinshome
        persistentVolumeClaim:
          claimName: opspvc

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

 

 

[root@k8s-master ops]# kubectl  apply -f  jenkins2.yaml
deployment.extensions/jenkins2 created
service/jenkins2 created
[root@k8s-master ops]#

 

創建完成后,要去拉取鏡像可能需要等待一會兒,然后我們查看下 Pod 的狀態

[root@k8s-master ops]# kubectl -n kube-ops get pod
NAME                       READY   STATUS             RESTARTS   AGE
jenkins2-59764f8f65-rcvh5   0/1     CrashLoopBackOff   4          4m20s
[root@k8s-master ops]#

[root@k8s-master ops]# kubectl -n kube-ops describe pod jenkins2-59764f8f65-rcvh5
    Liveness:     http-get http://:8080/login delay=60s timeout=5s period=10s #success=1 #failure=12
    Readiness:    http-get http://:8080/login delay=60s timeout=5s period=10s #success=1 #failure=12
    Environment:  <none>
    Mounts:
      /var/jenkins_home from jenkinshome (rw,path="jenkins")
      /var/run/secrets/kubernetes.io/serviceaccount from jenkins2-token-97q9h (ro)

 

#查看日志

[root@k8s-master ops]# kubectl -n kube-ops logs jenkins2-59764f8f65-rcvh5
Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied
[root@k8s-master ops]#

 

沒有權限在 jenkins 的 home 目錄下面創建文件,這是因為默認的鏡像使用的是 jenkins 這個用戶,而我們通過 PVC 掛載到 nfs 服務器的共享數據目錄下面卻是 root 用戶的,所以沒有權限訪問該目錄,要解決該問題,也很簡單,我只需要在 nfs 共享數據目錄下面把我們的目錄權限重新分配下即可:

chown -R 1000 /data/k8s/jenkins2

 

 

 

#再次執行

[root@k8s-master ops]# kubectl delete -f jenkins2.yaml
deployment.extensions "jenkins2" deleted
service "jenkins2" deleted
[root@k8s-master ops]# kubectl apply -f jenkins2.yaml
deployment.extensions/jenkins2 created
service/jenkins created
[root@k8s-master ops]#

 

 

#等待個2分鍾

[root@k8s-master ops]# kubectl -n kube-ops get pod
NAME                       READY   STATUS    RESTARTS   AGE
jenkins2-59764f8f65-62r5w   1/1     Running   0          3m31s

 

 

 

1.5  密碼登陸

任意節點的 IP:30002 端口就可以訪問 jenkins 服務

 

 

 

初始化的密碼我們可以在 jenkins 的容器的日志中進行查看,也可以直接在 nfs 的共享數據目錄中查看:

 

[root@k8s-master ops]# cat /data/k8s/jenkins/secrets/initialAdminPassword
739b9126bc23434495a96d5d65619e70
[root@k8s-master ops]#

[root@k8s-master ops]# kubectl -n kube-ops logs jenkins2-59764f8f65-62r5w
…..
739b9126bc23434495a96d5d65619e70

This may also be found at: /var/jenkins_home/secrets/initialAdminPassword
….

 

 

然后選擇安裝推薦的插件即可

 

 

 

 

安裝完成后添加管理員帳號即可進入到 jenkins 主界面:

 

 

 

 

 

2  k8s環境使用Jenkins優點

傳統的 Jenkins Slave 一主多從方式會存在一些痛點,比如:

  • 主 Master 發生單點故障時,整個流程都不可用了
  • 每個 Slave 的配置環境不一樣,來完成不同語言的編譯打包等操作,但是這些差異化的配置導致管理起來非常不方便,維護起來也是比較費勁
  • 資源分配不均衡,有的 Slave 要運行的 job 出現排隊等待,而有的 Slave 處於空閑狀態
  • 資源有浪費,每台 Slave 可能是物理機或者虛擬機,當 Slave 處於空閑狀態時,也不會完全釋放掉資源。

正因為上面的這些種種痛點,我們渴望一種更高效更可靠的方式來完成這個 CI/CD 流程,而 Docker 虛擬化容器技術能很好的解決這個痛點,又特別是在 Kubernetes 集群環境下面能夠更好來解決上面的問題,下圖是基於 Kubernetes 搭建 Jenkins 集群的簡單示意圖:

 

 

 

 

從圖上可以看到 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 到集群中,從而實現擴展。

是不是以前我們面臨的種種問題在 Kubernetes 集群環境下面是不是都沒有了啊?看上去非常完美。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM