首頁 > 軟體

容器雲平臺No.10~通過gogs+drone+kubernetes實現CI/CD

2020-09-23 09:30:36

什麼是CI/CD

持續整合(Continous Intergration,CI)是一種軟體開發實踐,即團隊開發成員經常整合它們的工作,通常每個成員每天至少整合一次,也就意味著每天可能會發生多次整合。每次整合都需要通過自動化的編譯、釋出、自動化迴歸測試來驗證,從而儘快地發現整合錯誤。而這些自動化的操作則由CI軟體進行執行。

持續部署(Continous Delivery,CD)在持續整合的基礎上,將整合後的程式碼部署到真實運行環境中(本文指部署到kubernetes叢集)。交付團隊 ->版本控制 ->構建和單元測試 ->自動驗收測試 -> 釋出

什麼是Drone

Drone 是一個基於Docker容器技術的可擴展的持續整合引擎,用於自動化測試、構建、釋出。每個構建都在一個臨時的Docker容器中執行,使開發人員能夠完全控制其構建環境並保證隔離。開發者只需在項目中包含 .drone.yml檔案,將程式碼推送到 git 倉庫,Drone就能夠自動化的進行編譯、測試、釋出。

使用drone實現CD/CD

首先來看下醜陋的圖

簡單梳理流程:

1、開發人員向git(gitlab/github/gogs)提交程式碼,程式碼中必須包含Dockerfile和.drone.yml檔案。
2、將程式碼commit到遠端倉庫;釋出應用時需要填寫服務類型、服務名稱、資源數量、例項個數等資訊
3、gogs觸發drone自動構建
4、Drone的CI流水線中包括了自定義指令碼,根據準備好的kubernetes的YAML模板,將其中的變數替換成使用者輸入的選項
生成應用的kubernetes YAML配置檔案
5、Drone的CI流水線自動編譯程式碼並打包成docker映象推送到Harbor映象倉庫
6、更新DNS,插入一條DNS記錄,IP地址是ingress節點的IP地址。
7、Drone的CI流水線中自定義指令碼呼叫kubernetes的API,部署應用;更新Ingress的配置,根據新部署的應用的名稱,在ingress的配置檔案中增加一條路由資訊
接下來,開始實戰

部署程式碼倉庫gogs

本文使用gogs,當然你可以選擇gitlab,github等程式碼倉庫
1、創建gogs.yaml

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: gogs
  labels:
    app: gogs
spec:
  serviceName: gogs
  replicas: 1
  selector:
    matchLabels:
      app: gogs
  template:
    metadata:
      labels:
        app: gogs
    spec:
      terminationGracePeriodSeconds: 180
      containers:
      - name: gogs
        image: gogs/gogs
        imagePullPolicy: Always
        ports:
        - containerPort: 3000
          name: port
        - containerPort: 22
          name: ssh-port
        volumeMounts:
        - name: volume
          mountPath: /data
      volumes:
      - name: volume
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: gogs
  labels:
    app: gogs
spec:
  type: NodePort
  ports:
  - port: 3000
    targetPort: 3000
  selector:
    app: gogs

2、執行部署並檢視結果

[root@k8s-node001 gogs]# kubectl  apply -f gogs.yaml 
statefulset.apps/gogs created
service/gogs created

[root@k8s-node001 gogs]# kubectl  get po,svc -o wide 
NAME         READY   STATUS    RESTARTS   AGE    IP               NODE          NOMINATED NODE   READINESS GATES
pod/gogs-0   1/1     Running   0          2m2s   100.68.150.197   k8s-node001   <none>           <none>

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE     SELECTOR
service/gogs         NodePort    10.106.102.74   <none>        3000:30526/TCP   2m3s    app=gogs

3、瀏覽器開啟,並配置gogs,然後就可以登入gogs了

4、登入gogs

至此,gogs配置完畢。
Tips:本文的gogs,是測試環境,使用卷類型為:emptyDir,生產環境最好單獨部署或者使用StorageClass保證資料持久可用性
接下來部署drone

部署CI工具Drone

1、編寫drone.yaml檔案

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: drone
  labels:
    app: drone
spec:
  serviceName: drone
  replicas: 1
  selector:
    matchLabels:
      app: drone
  template:
    metadata:
      labels:
        app: drone
    spec:
      terminationGracePeriodSeconds: 180
      containers:
      - name: drone
        image: drone/drone:1
        imagePullPolicy: Always
        env:
          - name: DRONE_AGENTS_ENABLED
            value: "true"
          - name: DRONE_GOGS_SERVER
            value: http://192.168.100.181:30526/  # 注意這裡填的是gogs的地址
          - name: DRONE_RPC_SECRET
            value: qawsedrftg
          - name: DRONE_SERVER_HOST
            value: drone.company.com
          - name: DRONE_SERVER_PROTO
            value: http
        ports:
        - containerPort: 80
          name: port
        - containerPort: 443
          name: ssl-port
        volumeMounts:
        - name: volume
          mountPath: /data
      volumes:
      - name: volume
        emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: drone
  labels:
    app: drone
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: drone

2、執行部署並檢視結果

[root@k8s-node001 drone]# kubectl  apply -f drone.yaml

[root@k8s-node001 drone]# kubectl get po,svc  -o wide
NAME          READY   STATUS    RESTARTS   AGE     IP   NODE          NOMINATED NODE   READINESS GATES
pod/drone-0   1/1     Running   0          4m40s   100.68.150.198   k8s-node001   <none>           <none>

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE     SELECTOR
service/drone        NodePort    10.100.77.138   <none>        80:31681/TCP     4m40s   app=drone

3、現在就可以用瀏覽器訪問http://192.168.100.181:31681 ,使用gogs的賬號就可以登入drone了

4、登入後可以看到,現在並沒有任何項目,後續再gogs新建項目,就能看到了

部署Drone Runner

Runner的作用是詢問Drone Server,然後執行pipeline,更多資訊請檢視官網
1、編寫drone-runner.yaml

---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: default
  name: drone
rules:
- apiGroups:
  - ""
  resources:
  - secrets
  verbs:
  - create
  - delete
- apiGroups:
  - ""
  resources:
  - pods
  - pods/log
  verbs:
  - get
  - create
  - delete
  - list
  - watch
  - update
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: drone
  namespace: default
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
roleRef:
  kind: Role
  name: drone
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: drone-runner
  labels:
    app.kubernetes.io/name: drone-runner
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: drone-runner
  template:
    metadata:
      labels:
        app.kubernetes.io/name: drone-runner
    spec:
      containers:
      - name: drone-runner
        image: drone/drone-runner-kube:latest
        ports:
        - containerPort: 3000
        env:
        - name: DRONE_RPC_HOST
          value: 192.168.100.181:31681  # Drone Server地址
        - name: DRONE_RPC_PROTO
          value: http
        - name: DRONE_RPC_SECRET
          value: qawsedrftg         # Drone Server部署時候填寫的secret

2、執行部署並檢視結果

[root@k8s-node001 drone]# kubectl  apply -f drone-runner.yaml

[root@k8s-node001 drone]# kubectl  get po
NAME                            READY   STATUS    RESTARTS   AGE
drone-runner-7c64bffb45-dh2dn   1/1     Running   0          11m

至此,實現CI/CD的環境都準備好了,現在來跑一個demo

CI/CD示例

1、gogs新建項目demo

2、drone上點sync,就可以看到demo項目

3、啟用demo項目,儲存

4、在gogs的demo項目中,新增.drone.yml檔案,新增一個pipeline

5、提交程式碼,但是不觸發CI,Commit的時候填寫[CI SKIP]就可以跳過觸發CI

如果這裡直接Commit提交程式碼,就直接觸發CI功能,Drone就開始執行這個pipeline了
[CI SKIP]的作用就是如果需要修改多個檔案,這時候會很有用;
當然在實際開發過程中,都是把項目clone到本地,編輯好所有檔案,再push到程式碼倉庫,這樣就不需要[CI SKIP]了
6、我們這裡隨便修改 README,然後知己commit,不是用[CI SKIP]看下效果

7、執行結果,這裡失敗了,後面再解決

8、如果您commit以後並沒有觸發Drone,需要在gogs檢視webhooks時候正常,如下圖

9、這裡我們來解決pipeline執行失敗的問題
我們通過drone介面可以看到項目pipeline報錯如下,顯示runner clone程式碼失敗了

Initialized empty Git repository in /drone/src/.git/
+ git fetch origin +refs/heads/master:
fatal: unable to access 'http://192.168.100.181:3000/scofield/demo.git/': Failed to connect to 192.168.100.181 port 3000: Connection refused

首先看下這個pipeline,很簡單,使用映象alpine執行兩條輸出語句

kind: pipeline
type: kubernetes
name: default

steps:
- name: greeting
  image: alpine
  commands:
  - echo hello
  - echo world

但是預設情況下,Drone執行pipeline之前會克隆項目,url就是gogs的http地址,這裡是http://192.168.100.181:3000/scofield/demo.git 因為我這裡測試環境使用NodePort暴露的服務,Drone需要使用http://192.168.100.181:30526/scofield/demo.git 這個地址才能克隆到項目,如果使用ingress暴露gogs服務,這個url就是域名而不是IP,就不會出現這個問題。
那現在需要解決這個問題,我們就自定義clone,修改預設的克隆地址,修改如下,修改完直接commit程式碼,觸發CI

通過drone頁面檢視結果,可以看到clone成功

而且執行的echo命令也成功執行

至此本文實戰結束

總結

本文是“基於Docker及Kubernetes構建的容器雲平臺”系列第十篇,也是最後一篇,如果您看完了整個系列文章,在此感謝。
通過這十篇文章,您應該可以構建出一個測試環境的容器平臺。關於容器雲平臺更多內容,後續會繼續分享,盡請持續關注。

PS:後續文章會同步到dev.kubeops.net


IT145.com E-mail:sddin#qq.com