CI/CD Drone

三分鐘學會Drone ,CI/CD輕鬆上手!

Jesse 2020/04/14 11:00:00
469

三分鐘學會Drone CI/CD輕鬆上手!



搭好!

最近因為專案需求,需要導入ci/cd流程,開始接觸到drone這套軟體,這是一套開源的持續整合框架,可以幫工程師節省非常多上版的時間,從測試、包版、image化到部屬全部一條龍服務,而且非常容易上手,易於維護,本篇的目標就是要讓大家認識drone,希望可以透過這套工具增進工作效率,let’s get it started!



第一分鐘 drone的概觀:

drone 是一套以GO語言開發的開源專案,可以在github上看到原始碼,也有提供企業版,就我個人的體驗呢,開源版本就已經很好用了啦。

可以參考官方網站的文件:https://docs.drone.io/。

 

個人列出五大推薦使用drone的原因:

1.drone 支援各大git repositorygithubgitlabbitbucketgittea等等,只要你的專案是使用git版控,你就可以輕鬆整合drone

2.drone ci流程是以yml檔描述的,非常好理解,且可以靈活調整,只要有使用過docker-compose的經驗應該都可以快速上手。

3.drone 本身是以Go語言打造的,服務啟動速度非常快。

4.drone 是一個docker base的服務,可以快速移植到不同平台上運行,尤其非常適合在k8s叢集的環境中運行。

5.drone drone的社群上已經有各種插件可以使用,也可以用各種語言自製客製化插件,只要包裝成image就能輕鬆加入ci流程當中,非常方便。

 

最常見的版本有1.x版本以及0.8版本,兩種版本在啟動參數以及pipeline的寫法都差很多,本文使用現在最新的1.6.5版本,以bitbucket為例,demo一個spring boot的CD流程。

 

*注:0.8版已不支援bitbucket的OAuth格式,請用1.0.0以上版本


第二分鐘:drone的安裝:

drone的架構,分為drone server drone runnerserver負責收集git repo的事件,當偵測到pipeline中定義好的條件時,比如說某個branch push,就會觸發pipeline的流程,分派給runner執行。

 

 

runner(agent)是實際執行pipeline的容器,可以跟server部屬在不同台機器上,drone runner分成五種,

,適用於不同的情境,分別為:

Docker runner :drone最常見的用法,pineline中的每一個step都起一個獨立的container運行特定任務,本文即是採用docker runner

Kubernetes runner:docker runner 的功能相似,只是改成Kubernetes 版本,如果你的服務要搭建在k8s上,就用這個。

Exec runner:用於你的專案不適合跑在容器內的狀況EX:MacOs專案。

SSH runner:直接以ssh 連線到遠端以default shell 執行pipeline流程,需要使用openssh 7.9 以上版本。

Digital Ocean runner :用於當你的pipeline需要權限可以操作整台虛擬機的情況,且不適合跑在容器內。



一個server可以接多個runner分別處理不同的pipeline ,如果你的專案很複雜,也可以將一個pineline的各個step分配給多個runner,最後再整合再一起。

 

另外還有drone cli:command line的方式操作drone server ,如果你在drone serverui畫面找不到你要設定的東西,那肯定是要用drone cli設定。

 

在安裝drone 之前要先做兩件事:

 

1.那因為drone 整個服務都是依賴docker 所以在安裝drone之前一定要先裝docker  (最好也要有docker-compose,比較方便)

如果是還沒有使用過docker的讀者,我推薦你可以先參考這篇 ,所有你需要知道的docker的知識都在裡面: https://yeasy.gitbooks.io/docker_practice/introduction/

2.取得bitbucket的OAuth ID 跟SECRET

(1)登入bitbucket點選左下角有你名子的小圈圈,然後點選bitbucket settings

(2)點選setttings畫面的OAuth

(3)點選add consumer

(4)callback URL設定為你的https://<你的domain || ip+port>/login  (0.8版請用 /authorize)
bitbucket不接受localhost或是127.0.0.1,所以要開ngrok
權限設定照著勾就可以了。

 

 

還不認識ngrok的讀者,可以參考官方網站:https://dashboard.ngrok.com/get-started

簡單來說就是載一個ngrok.exe  啟動後在cmd介面上輸入 ngrok http <你想對外開放的port號>,它就會把你的port開放給全世界

 

官方推薦用docker run 的方式來安裝drone,我將官方的docker run 指令寫成docker-compose.yml 如下:

version: '2'

  services:

    drone-server:

      image: drone/drone:1

      ports:

      - 8081:80 #drone sever http port

      volumes:

      - ./:/data # sqlite的檔案,裡面存一些drone server的訊息

      restart: always

      environment:

       - DRONE_USER_CREATE=username:<你的bitbuckert帳號的username>,machine:false,admin:true # 建立admin權限的使用者  cli登入用

       - DRONE_SERVER_HOST=xxxx.ngrok.io  # 指定Drone server URL(domain || ip+port)  

       - DRONE_SERVER_PROTO=https # 指定Drone server URL連線協議(http || https)

       - DRONE_TLS_AUTOCERT=false# 自動生成 ssl 證書,並接受 https 連線,默認為false

       - DRONE_RPC_SECRET=<自訂一個SECRET># PRC連線密鑰

 

# BITBUCKET Config

       - DRONE_BITBUCKET_CLIENT_ID=<你的OAuth ID> # OAuth Application ID

       - DRONE_BITBUCKET_CLIENT_SECRET=<你的 OAuth Secret> # OAuth Secret

 

# log

       - DRONE_DEBUG=true # 開啟debug mod

       - DRONE_LOGS_PRETTY=true # 開啟log pettify

       - DRONE_LOGS_COLOR=true # 開啟log區分顏色

       - DRONE_LOGS_TRACE=true # 開啟日誌



    drone-runner:

      image: drone/drone-runner-docker:1

      restart: always

      ports:

      - 3000:3000

      depends_on:

      - drone-server # 指定在drone-server啟動之後才會啟動drone-runner 

      volumes:

       - /var/run/docker.sock:/var/run/docker.sock # 將本機dockersock mount給內部docker

      environment:

      - DRONE_RPC_HOST=xxxx.ngrok.io # 指定Drone server URL(drone-server設定一致即可)

      - DRONE_RPC_PROTO=https # 指定與Drone server 的連線協議(http || https)

     - DRONE_RPC_SECRET=<上面server設定的SECRET> # PRC連線密鑰(須與drone-server設定一致)

     - DRONE_RUNNER_CAPACITY=3 # 可以同時執行的任務數

     - DRONE_LOGS_TRACE=true # 開啟日誌

    - DRONE_RUNNER_NAME=dev_depoly #Optional string value. Sets the name of the runner

 

*注:drone 1.0以後支援單機版本,就是drone-server可以同時擔任runner的腳色,
    配置的話就把上面的drone-runner區塊刪掉,然後在drone-server區塊加入一些原本在runner的參數:

      environment:

      - DRONE_AGENTS_DISABLED=true

      - DRONE_RUNNER_CAPACITY=3

     volumes:

       - /var/run/docker.sock:/var/run/docker.sock

*注:drone的sqlite是用來儲存user,bulid log之類的資訊,也可以改存在mysql或Postgres

    environment:

    -  DRONE_DATABASE_DRIVER=mysql

    - DRONE_DATABASE_DATASOURCE=root:password@tcp(1.2.3.4:3306)/drone?parseTime=true 

*注:如果某帳號已經登入過了,DRONE_USER_CREATE不會在新建一個使用者,必須要以cli登入。

更多配置可以參考:https://docs.drone.io/server/reference/

 

docker-compose.yml配置完成之後,以cmd cd 到該yml所在目錄 輸入 docker-compose up -d指令

如果沒有意外,應該可以看到兩個綠綠的done,就表示安裝完成了。

如果沒起起來,可以往以下幾個方面排查:
1.先確認docker 可以正常運作

2.在win10上執行,docker desktop要開啟share drives 的設定
3.配置有誤,看看yml檔有沒有多打tab,各參數是否都正確

4.確認port號是否已經被占用(用檢查一下  netstat -nao |find "0.0.0.0:8081")

5.如果有奇怪的錯誤,可以上社群看有沒有人問過同樣的問題:https://discourse.drone.io/

6.如果有些設定沒有如預期中生效,也可以搜尋一下drone 的changelog,看是不是已經改參數但文檔還沒更新:https://github.com/drone/drone/blob/master/CHANGELOG.md

 

OK 如果server 順利啟動,打開瀏覽器輸入剛剛設定host url 就會出現一個授權畫面,按下confirm然後你就會跳轉到首頁:

這邊就會列出你在bitbucket裡面所有的專案,選擇一個你想要加入CI/CD流程的專案按下active (你必須要有此專案的admin權限),然後進入專案

然後你會看到一些設定,project setting trusted一定要勾起來,不然會沒辦法進行cache操作,其餘設定的基本上不用去更改,用default值就可以了

這邊可以看到configuration指定的是.drone.yml,意思是drone server會去讀取這個檔案,決定你的專案pipeline的流程怎麼跑

假如你有特殊需求,你也可以設多個yml檔,讓每個server 跑不一樣的pipeline。

網頁上的設定蠻陽春的,如果想了解更多可以參考appleboy大大的這部影片:https://www.youtube.com/watch?v=OlucMSF1Xss

其他更多的設定都需要cli才可以使用。

 

 

第三分鐘:drone pipeline

OK, 接下來我們開始寫.drone.yml,也就是drone的精華所在

這邊就是看你的專案需要什麼CI/CD的步驟就加什麼步驟近來

以我的專案來說,最基本的需求,我需要自動化 測試 -> 打包 -> 佈署 

看起來就會像醬子:

kind: pipeline

name: dev_depoly

 

steps:

  #1.maven 測試

- name: maven-test

  image: maven:3.6.1-jdk-8

  commands:

  - cd ./MyProject

  - mvn test

 

  #2.maven 打包

- name: maven-build

  image: maven:3.6.1-jdk-8

  commands:

  - cd ./MyProject

  - mvn clean package  -DskipTests=true -Dmaven.javadoc.skip=true -B -V 

 

  #3.upload jar file

- name: scp

  image: appleboy/drone-scp

  settings:

    host:

      from_secret: host_ip

    username: 

      from_secret: host_user

    password:

      from_secret: host_password

    port: 22

    command_timeout: 2m

    target: 

      - <yourPath>

    source:

      - <yourTargetPath>/<yourProjectFinalName>.jar

 

 

  #4.deploy

- name: ssh commands

  image: appleboy/drone-ssh

  settings:

    host:

      from_secret: host_ip

    username: 

      from_secret: host_user

    password: 

      from_secret: host_password

    port: 22

    script:

      - echo ====开始部署=======

      - cd <yourPath>

      - kill $(cat ./pid.file)

      - java -jar <yourProjectFinalName>& echo $! > ./pid.file &

      - echo ====部署成功======

 

trigger:

  branch:

  - master

  event:

  - tag

  - push

================================

 

pipeline一樣是一個yml格式

kind:可以填三種值,pipeline,secret,signature

分別代表三種物件類型

signature: 是透過cli指令生成,用來保護你的pipeline不要被隨意串改用的。

secret: 類似宣告變數概念,用來儲存一些可變動的資訊

大概長這樣

如果資訊你不希望被別人看到,你可以把secret存在drone  server上:


 

 

pipeline: 是最常用的,用來定義流程

有分成五種type,對應前面介紹的五種runner,預設用type為docker。

name:可以指定runner name,表示此pipeline分派給特定runner執行,defualt會隨機指派。

 

step:定義pipeline流程的各個步驟

有一個預設的step會先自動clone 你的專案下來,放在runner image的工作目錄,不用寫他也會執行。

一般的step,只要三個參數就可以work

                                name(單一pipeline內不重複),

                                image:<imageName>:<tag>,

                                command:在image內部執行指令

如範例的maven-test

這樣runner 就會起一個image,並且將image工作目錄mount 到runner image的工作目錄。

pipeline 過程中就是透過這個機制傳遞每個階段的執行結果。

 

另外step 還可以設定,volumes跟environment,作用就跟docker run -e -v 參數的效果一樣

,比較特別的是使用volumes還需寫要在pipeline底下加一個volumes屬性,volume可以設多個以不同的name區分,範例如下。

.......

steps:

- name: Maven install

  image: maven

  volumes:

  - name: cache

    path: /root/.m2

  commands:

    - mvn clean install

 

- name: ...

...

...

volumes:

- name: cache

  host:

    path: /tmp/cache/.m2

 

trigger:

...

==================

 

其實大部分CI/CD會需要的的功能官方或社群的支持者已經有提供各式各樣的plugin,如範例裡面第3,4步,只要指定image name,按照文檔裡的格式帶入參數就可以work,非常省時省力,而且可以依照需求隨時置換不同的plugin,使用起來非常舒服。
這邊提供官方plugins給大家參考:http://plugins.drone.io/

 

再來如果要控制流程的step的執行時機,可以設置when屬性

- name: Maven install

  image: maven

  commands:

    - mvn clean install

when:

  event:

    include:

    - push

條件的設計很靈活,可以指定特定的event、branch、repository、status才執行,或特定條件不執行

可以參考官方文件自行組合:https://docs.drone.io/pipeline/docker/syntax/conditions/

如果沒有特別指定的話,預設是前面的step fail的話,後面的step就不會執行。

 

如果是要控制整個pipeline的執行條件,就要使用pipeline的trigger屬性,用法跟when屬性大同小異,可以用來區別不同環境的pipeline流程。
詳見官方文件:https://docs.drone.io/pipeline/triggers/

 

你也可以在drone server 的setting頁面加入cron job,然後在pipeline的trigger加入event:- cron,就可以在特定的時間觸發pipeline

 

最後如果流程中需要用到本次建置的metadata,如branch、commit hash 、repository等等,官方提供了${變數名稱}的語法,可以在pipeline中調用

例如:

- name: publish

  image: plugins/docker

  settings:

    #這樣可以取commit sha-1的前八碼

    tags: ${DRONE_COMMIT_SHA:0:8}

    repo: xxxuser/xxxxrepo

 

官方文件有列出所有可以使用的變數名稱:https://docs.drone.io/pipeline/environment/reference/

 

如果運行順利,就可以看到本次bulid過程,各個階段的console,有出現錯誤也會有錯誤訊息

 

如果說,現有的plugin都不符合你的需求,你想自己做一個image加入你的ci/cd流程,也很簡單。

首先執行docker login ,輸入以下指令:

docker login -p <password> -u <dockerhubAccount>
登入你的dockerhub帳號

然後bulid一個客製化的images,通常使用一個Dockerfile

==================

## maven image 為基底

FROM maven:latest

## PLUGIN_開頭的環境變數,可以在step中 用setting置換

ENV PLUGIN_HELLO=hi

## 改寫image啟動後的指令

ENTRYPOINT [ "/bin/sh", "-c", "echo $PLUGIN_HELLO" ]

=================

使用指令build docker image 

docker build -t <dockerhubAccount>/drone-plugin-test .

 

然後上傳docker image

docker push <dockerhubAccount>/drone-plugin-test

 

就可以在流程中使用囉!

- name: test

  image: <your Account>/drone-plugin-test

  pull: false

  settings:

    hello: testting

  commands:

  - echo $PLUGIN_HELLO

 

上面的範例只是單純的echo 一個環境變數,實際運用可以run一個腳本或程式去完成你在CI/CD流程中要做的事。

 

總結一下本篇重點,drone 是一套非常輕量化CI工具,兼容各大git repository,利用docker-compose 可以快速搭建,也很適合在容器化的環境運行,pipeline內容是以yml檔描述,易於閱讀也很好維護,有多樣的plugins可以套用,快速開發出適合專案的pipeline。OK !以上就drone的簡單介紹,有任何問題歡迎留言指教,謝謝!




 

 

Jesse
曹應忠
2020/04/14 11:18:56

介紹得很詳盡!但是我沒辦法三分鐘就學會(笑)

Jesse
2020/04/16 10:04:18

哈哈,標題是有點太浮誇XD