<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 基于Jenkins 的CI/CD(一) ## 介紹 本文將討論和探索兩個令人驚奇和相當有趣的技術。一個是Jenkins,一個流行的持續集成/發布的工具,另一個是Kubernetes,一個流行的容器編排引擎。 持續構建與發布是我們日常工作中必不可少的一個步驟,目前大多公司都采用 Jenkins 集群來搭建符合需求的 CI/CD 流程,然而傳統的 Jenkins Slave 一主多從方式會存在一些痛點,比如:主 Master 發生單點故障時,整個流程都不可用了;每個 Slave 的配置環境不一樣,來完成不同語言的編譯打包等操作,但是這些差異化的配置導致管理起來非常不方便,維護起來也是比較費勁;資源分配不均衡,有的 Slave 要運行的 job 出現排隊等待,而有的 Slave 處于空閑狀態;最后資源有浪費,每臺 Slave 可能是實體機或者 VM,當 Slave 處于空閑狀態時,也不會完全釋放掉資源。 提到基于Kubernete的CI/CD,可以使用的工具有很多,比如Jenkins、Gitlab CI已經新興的drone之類的,我們這里會使用大家最為熟悉的Jenins來做CI/CD的工具。 ## 優點 Jenkins 安裝完成了,接下來我們不用急著就去使用,我們要了解下在 Kubernetes 環境下面使用 Jenkins 有什么好處。 我們知道持續構建與發布是我們日常工作中必不可少的一個步驟,目前大多公司都采用 Jenkins 集群來搭建符合需求的 CI/CD 流程,然而傳統的 Jenkins Slave 一主多從方式會存在一些痛點,比如: * 主 Master 發生單點故障時,整個流程都不可用了 * 每個 Slave 的配置環境不一樣,來完成不同語言的編譯打包等操作,但是這些差異化的配置導致管理起來非常不方便,維護起來也是比較費勁 * 資源分配不均衡,有的 Slave 要運行的 job 出現排隊等待,而有的 Slave 處于空閑狀態 * 資源有浪費,每臺 Slave 可能是物理機或者虛擬機,當 Slave 處于空閑狀態時,也不會完全釋放掉資源。 正因為上面的這些種種痛點,我們渴望一種更高效更可靠的方式來完成這個 CI/CD 流程,而 Docker 虛擬化容器技術能很好的解決這個痛點,又特別是在 Kubernetes 集群環境下面能夠更好來解決上面的問題,下圖是基于 Kubernetes 搭建 Jenkins 集群的簡單示意圖 ![](https://blog.qikqiak.com/img/posts/k8s-jenkins-slave.png) 從圖上可以看到 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 集群環境下面是不是都沒有了啊?看上去非常完美。 ### 安裝 聽我們課程的大部分同學應該都或多或少的聽說過Jenkins,我們這里就不再去詳細講述什么是 Jenkins 了,直接進入正題,后面我們會單獨的關于 Jenkins 的學習課程,想更加深入學習的同學也可以關注下。既然要基于Kubernetes來做CI/CD,當然我們這里需要將 Jenkins 安裝到 Kubernetes 集群當中,新建一個 Deployment:(jenkins-deployment.yaml) --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: jenkins2 namespace: kube-ops spec: template: metadata: labels: app: jenkins2 spec: terminationGracePeriodSeconds: 10 serviceAccountName: 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: 2000m memory: 4Gi requests: cpu: 1000m memory: 2Gi 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 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: jenkins2 namespace: kube-ops labels: app: jenkins2 spec: selector: app: jenkins2 ports: - name: web port: 8080 targetPort: web - name: agent port: 50000 targetPort: agent 為了方便演示,我們把本節課所有的對象資源都放置在一個名為 kube-ops 的 namespace 下面,所以我們需要添加創建一個 namespace: kubectl create namespace kube-ops 我們這里使用一個名為 jenkins/jenkins:lts 的鏡像,這是 jenkins 官方的 Docker 鏡像,然后也有一些環境變量,當然我們也可以根據自己的需求來定制一個鏡像,比如我們可以將一些插件打包在自定義的鏡像當中,可以參考文檔:https://github.com/jenkinsci/docker,我們這里使用默認的官方鏡像就行,另外一個還需要注意的是我們將容器的 /var/jenkins_home 目錄掛載到了一個名為 opspvc 的 PVC 對象上面,所以我們同樣還得提前創建一個對應的 PVC 對象,當然我們也可以使用我們前面的 StorageClass 對象來自動創建:(jenkins-pvc.yaml) apiVersion: v1 kind: PersistentVolume metadata: name: opspv spec: capacity: storage: 200Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Delete nfs: server: 10.34.11.12 path: /opt/nfs --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: opspvc namespace: kube-ops spec: accessModes: - ReadWriteMany resources: requests: storage: 200Gi 創建需要用到的 PVC 對象 $ kubectl create -f jenkins-pvc.yaml 另外我們這里還需要使用到一個擁有相關權限的 serviceAccount:jenkins2,我們這里只是給 jenkins 賦予了一些必要的權限,當然如果你對 serviceAccount 的權限不是很熟悉的話,我們給這個 sa 綁定一個 cluster-admin 的集群角色權限也是可以的,當然這樣具有一定的安全風險:(jenkins-rbac.yaml) apiVersion: v1 kind: ServiceAccount metadata: name: jenkins2 namespace: kube-ops --- kind: Role apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: jenkins2 namespace: kube-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: RoleBinding metadata: name: jenkins2 namespace: kube-ops roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: jenkins2 subjects: - kind: ServiceAccount name: jenkins2 namespace: kube-ops 創建 rbac 相關的資源對象: $ kubectl create -f jenkins-rbac.yaml 最后為了方便我們測試,我們這里通過 ingress的形式來訪問Jenkins 的 web 服務,Jenkins 服務端口為8080,50000 端口為agent,這個端口主要是用于 Jenkins 的 master 和 slave 之間通信使用的。(jenkins-ingress.yaml) apiVersion: extensions/v1beta1 kind: Ingress metadata: name: jenkins-ingress namespace: kube-ops annotations: kubernetes.io/ingress.class: "nginx" spec: rules: - host: jenkins-k8s.jiedai361.com http: paths: - backend: serviceName: jenkins2 servicePort: 8080 一切準備的資源準備好過后,我們直接創建 Jenkins 服務: kubectl create -f jenkins-deployment.yaml 最后創建ingress 路由服務 kubectl apply -f jenkins-ingress.yaml 創建完成后,要去拉取鏡像可能需要等待一會兒,然后我們查看下 Pod 的狀態: # kubectl get pods -n kube-ops NAME READY STATUS RESTARTS AGE jenkins2-58df5d8fdc-w9xqh 1/1 Running 0 7d 等到服務啟動成功后,我們就可以根據ingress 服務域名(jenkins-k8s.jiedai361.com)就可以訪問 jenkins 服務了,可以根據提示信息進行安裝配置即可: ![unlock jenkins](https://blog.qikqiak.com/img/posts/setup-jenkins-01-unlock.jpg) 初始化的密碼我們可以在 jenkins 的容器的日志中進行查看,也可以直接在 nfs 的共享數據目錄中查看 cat /opt/nfs/jenkins2/secret/initAdminPassword 然后選擇安裝推薦的插件即可。 ![](https://blog.qikqiak.com/img/posts/setup-jenkins-02-plugin.png) 安裝完成后添加管理員帳號即可進入到 jenkins 主界面: jenkins home ![](https://blog.qikqiak.com/img/posts/setup-jenkins-home.png) ## 配置 接下來我們就需要來配置 Jenkins,讓他能夠動態的生成 Slave 的 Pod jenkins依賴插件清單 - kubernetes - managed scripts **第1步**. 我們需要安裝kubernetes plugin, 點擊 Manage Jenkins -> Manage Plugins -> Available -> Kubernetes plugin 勾選安裝即可。 kubernetes plugin ![](https://blog.qikqiak.com/img/posts/setup-jenkins-k8s-plugin.png) **第2步**. 安裝完畢后,點擊 Manage Jenkins —> Configure System —> (拖到最下方)Add a new cloud —> 選擇 Kubernetes,然后填寫 Kubernetes 和 Jenkins 配置信息。 ![](https://box.kancloud.cn/ed79a0003e929e4382fd2e0d01e92479_1323x853.png) 注意 namespace,我們這里填 kube-ops,然后點擊Test Connection,如果出現 Connection test successful 的提示信息證明 Jenkins 已經可以和 Kubernetes 系統正常通信了,然后下方的 Jenkins URL 地址:http://jenkins2.kube-ops.svc.cluster.local:8080,這里的格式為:服務名.namespace.svc.cluster.local:8080,根據上面創建的jenkins 的服務名填寫,我這里是之前創建的名為jenkins,如果是用上面我們創建的就應該是jenkins2 **第3步.** 配置 Pod Template,其實就是配置 Jenkins Slave 運行的 Pod 模板,命名空間我們同樣是用 kube-ops,Labels 這里也非常重要,對于后面執行 Job 的時候需要用到該值,然后我們這里使用的是 cnych/jenkins:jnlp 這個鏡像,這個鏡像是在官方的 jnlp 鏡像基礎上定制的,加入了 kubectl 等一些實用的工具。 ![](https://box.kancloud.cn/93708d3a1c8580c67586cf532fba82d7_1339x806.png) 另外需要注意我們這里需要在下面掛載一個主機目錄,一個是 /var/run/docker.sock,該文件是用于 Pod 中的容器能夠共享宿主機的 Docker,這就是大家說的 docker in docker 的方式,Docker 二進制文件我們已經打包到上面的鏡像中了。如果在slave agent中想要訪問kubernetes 集群中其他資源,我們還需要綁定之前創建的Service Account 賬號:jenkins2 ![](https://box.kancloud.cn/a3b1e2a21d9884741b8b23921fcebcba_1072x1099.png) 另外還有幾個參數需要注意,如下圖中的Time in minutes to retain slave when idle,這個參數表示的意思是當處于空閑狀態的時候保留 Slave Pod 多長時間,這個參數最好我們保存默認就行了,如果你設置過大的話,Job 任務執行完成后,對應的 Slave Pod 就不會立即被銷毀刪除。 到這里我們的 Kubernetes Plugin 插件就算配置完成了。 ## 測試 Kubernetes 插件的配置工作完成了,接下來我們就來添加一個 Job 任務,看是否能夠在 Slave Pod 中執行,任務執行完成后看 Pod 是否會被銷毀 在 Jenkins 首頁點擊create new jobs,創建一個測試的任務,輸入任務名稱,然后我們選擇 Freestyle project 類型的任務: jenkins demo ![](https://blog.qikqiak.com/img/posts/jenkins-demo1.png) 注意在下面的 Label Expression 這里要填入haimaxy-jnlp,就是前面我們配置的 Slave Pod 中的 Label,這兩個地方必須保持一致 ![](https://blog.qikqiak.com/img/posts/jenkins-demo1-config.jpeg) 然后往下拉,在 Build 區域選擇Execute shell ![](https://blog.qikqiak.com/img/posts/jenkins-demo1-config2.jpeg) 然后輸入我們測試命令 echo "測試 Kubernetes 動態生成 jenkins slave" echo "==============docker in docker===========" docker info echo "=============kubectl=============" kubectl get pods -n kube-system 最后點擊保存 ![](https://blog.qikqiak.com/img/posts/jenkins-demo1-config3.jpeg) 現在我們直接在頁面點擊做成的 Build now 觸發構建即可,然后觀察 Kubernetes 集群中 Pod 的變化 $ kubectl get pods -n kube-ops NAME READY STATUS RESTARTS AGE jenkins2-7c85b6f4bd-rfqgv 1/1 Running 3 1d jnlp-hfmvd 0/1 ContainerCreating 0 7s 同樣也可以查看到對應的控制臺信息: ![](https://box.kancloud.cn/c1fbb56ce563b7732d221f67c27bf08a_1060x1086.png) 到這里證明我們的任務已經構建完成,然后這個時候我們再去集群查看我們的 Pod 列表,發現 kube-ops 這個 namespace 下面已經沒有之前的 Slave 這個 Pod 了。 $ kubectl get pods -n kube-ops NAME READY STATUS RESTARTS AGE jenkins2-7c85b6f4bd-rfqgv 1/1 Running 3 1d 到這里我們就完成了使用 Kubernetes 動態生成 Jenkins Slave 的方法。下節課我們來給大家介紹下怎么在 Jenkins 中來發布我們的 Kubernetes 應用
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看