架設 CI/CD 第一時間會想到老牌的 Jenkins,但他有一些缺點,比如說學習成本高、難以維護、頁面功能複雜等等。

後來逐漸出現 CI/CD 託管服務,如 github action、circle CI,引入 docker 的架構,同時 pipeline 撰寫門檻降低,功能直覺好用,但量多要付費。

有沒有可以白嫖、自己架設的呢?有,就是今天要介紹的 Drone!

Drone 的優勢

Drone 有什麼優勢呢?在這裡簡單列出幾點:

  1. 完全 Dockerize
    無論是 Drone 系統本身,以及 pipeline 的執行,都在 docker container 裡面運作。當 pipeline 結束後,過程中的資料會自動移除,再也不用像 Jenkins 時常因硬碟爆滿而罷工,增加 devops 的困擾
  2. UI 簡單直覺
    第一次用 Drone 會發現,頁面能按的東西也太少了吧!做的非常精簡,又能滿足使用者日常的需求。若需要作更多設定,Drone 提供工程師最愛的 cli 介面,敲幾下鍵盤就能搞定!
  3. 使用 yaml 檔撰寫 CI/CD 流程
    簡單清晰,和 github action 非常相似
  4. 豐富的 plugin
    Drone 提供 Plugins Marketplace,裡面有許多大神已經包好的 docker image,直接使用就能完成相當多的整合,包含 AWS 等等雲端服務。因為已經包成 docker image,也可以自己用 docker 指令來測試該 plugin,之後再寫入 yaml 檔。有需要亦可自己包 image 引入 pipeline 中!
  5. 無痛串接 github、gitlab、bitbucket
    只要提供 OAuth token,drone 都能幫你處理好!真正是無痛串接!回頭看隔壁棚的 Jenkins,當年串接的時候就搞了好久……
  6. 資源消耗極少
    Drone 是用 go 寫成,跑了幾天才使用 10 MB,轉頭看隔壁棚用 Java 寫的 Jenkins….

說了這麼多,剩下的靠各位自己去體驗!我們立刻來看怎麼架設!

如何架設 Drone

Drone 的架構分為 serverrunnerserver 的職責是提供 web 介面,和監聽 source control management 平台 webhook 的回呼,將 event 依照 .drone.yml 中的定義分配給對應的 runner 去執行。

在文件中提到 runner很多種,我們重點看以下三種:

  1. docker runner
    是今天主要示範的 runner,pipeline 跑在 docker container 裡面
  2. exec runner
    某些情境下 pipeline 需要直接跑在 host 裡(如 macOS build code),此時可以在 host 裡安裝 exec runner,並在 .drone.yml 中指名 runner 即可
  3. ssh runner
    有時需要 ssh 到遠端機器上作一些操作,此時可透過 ssh runner 來實現。ssh runner 本身也是 dockerize 的 runner。 除了官方提供的 ssh runner,亦可使用 appleboy 大大的 drone-ssh docker runner 來實現,就看大家喜好

以下以串接 github 為例。

啟動 ngrok forwarding (optional)

如果是在本機測試的話,可用以下指令先準備好 ngrok

ngrok http 8080

複製好 ngrok 提供的一次性網址備用

Session Status                online                                                                                                                                                 
Account                       xxxxxx (Plan: Free)                                                                                                                     
Update                        update available (version 3.1.0, Ctrl-U to update)                                                                                                     
Version                       3.0.6                                                                                                                                                  
Region                        Japan (jp)                                                                                                                                             
Latency                       40ms                                                                                                                                                   
Web Interface                 http://127.0.0.1:4040                                                                                                                                  
Forwarding                    https://e293-118-161-32-120.jp.ngrok.io -> http://localhost:8080

需特別注意,ngrok 重新啟動後網址會變更,若要維持正常串接,需要手動調整與 github webhook 的設定,建議正式上線時使用固定網域較佳

建立 github OAuth app

drone 的帳號系統直接整合 source control management 平台帳號(如 github login),因此我們需要為 drone 取得 github OAuth apps 的 client id 和 secret

到 github 個人設定頁面,點左下角的 Developer settings

無痛架設 Drone CI/CD

點左邊選項的 OAuth apps,再點綠色的 Register a new application

無痛架設 Drone CI/CD

依序輸入必填項目,其中 Authorization callback URL 必須填入能夠打回 drone server 的網址,並在網域後方加上 /login。如果是在自己電腦上測試,可以使用 ngrok 等服務取得一次性網址。如果已經有網域則直接填入,並建議用 nginx 為 drone 作反向代理,提供 https 對外溝通。

無痛架設 Drone CI/CD

點按紐 Generate a new client secret ,把 client id 和 secret 複製下來,等一下要放到 docker-compose.yml 檔中

無痛架設 Drone CI/CD

啟動 drone container

回到 console 利用以下 docker-compose.yml 起 drone server 和 drone docker runner:

範例原始碼在此下載:github

version: "3"
services:
  drone:
    image: drone/drone:2.15
    container_name: drone.server
    restart: always
    ports:
      - 8080:80 # 對外的 port 可自由修改,這邊以 8080 為例
    networks:
      - drone
    volumes:
      - ./data:/data
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "3"
    deploy:
      resources:
        limits:
          memory: 2G
    environment:
      DRONE_SERVER_HOST: xxx.xxx.xxx # your domain,填與 github webhook callback url 一樣即可
      DRONE_SERVER_PROTO: https # 與外界溝通使用 https
      DRONE_RPC_SECRET: xxxxxxxx # 可自行產生一串亂碼作為 drone rpc token
      # github
      DRONE_GITHUB_CLIENT_ID: <CLIENT_ID> # 填入 github OAuth 提供的 client id
      DRONE_GITHUB_CLIENT_SECRET: <CLIENT_SECRET> # 填入 github OAuth 提供的 client secret
      # log, for debug use
      DRONE_DEBUG: true
      DRONE_LOGS_PRETTY: true
      DRONE_LOGS_COLOR: true
      DRONE_LOGS_TRACE: true
    
  drone-runner:
    image: drone/drone-runner-docker:1.8.2
    container_name: drone.runner
    restart: always
    networks:
      - drone
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "3"
    deploy:
      resources:
        limits:
          memory: 2G
    environment:
      DRONE_RPC_HOST: drone
      DRONE_RPC_SECRET: xxxxxxxx # 填入和上面 drone server 一樣的值
      DRONE_RPC_PROTO: http # 與 drone server 是透過 docker 內網溝通,使用 http 即可
      DRONE_RUNNER_CAPACITY: 5
      DRONE_RUNNER_NAME: drone-docker-runner
      # log, for debug use
      DRONE_DEBUG: true
      DRONE_LOGS_PRETTY: true
      DRONE_LOGS_COLOR: true
      DRONE_LOGS_TRACE: true
      

networks:
  drone:
    name: drone
    driver: bridge

儲存後 up 一下就可以囉!

docker compose up -d

進入 Drone Web Dashboard

在瀏覽器填入 drone 所在網址(如果是用 ngrok 作代理,填入 ngrok 提供的一次性網址),即可看到以下畫面

無痛架設 Drone CI/CD

點 continue 會跳轉 github 授權畫面

無痛架設 Drone CI/CD

授權後簡單填一下註冊資訊,就能在 drone dashboard 看到你所有的 repo 了!

無痛架設 Drone CI/CD

如何設定 drone CI/CD 與 github 整合?

選擇你想要啟動 drone pipeline 的 repo,切換至 setting 頁面,點選 Activate Repository 按鈕,就….就完成了!drone 會自動幫你處理對應 repo webhook 的設定,轉頭看看 Jenkins 的設定過程,這UX體驗實在太讚了!

無痛架設 Drone CI/CD

啟動後,選項保持預設就能使用,有需要再額外調整

無痛架設 Drone CI/CD

實際寫一份 drone pipeline 試試

在 activate pipeline 的 repo 根目錄下新增 .drone.yml撰寫 pipeline

這邊就略過 hello world 等級的示範,以我實際的需求為例:想要 tag release 版號後,自動 build code ,並上傳 build artifact 到 github release 中

範例原始碼在此下載:github

---
# 指定 pipeline,且由 docker runner 執行
kind: pipeline
type: docker
name: default

# 如果 docker runner 都跑在 arm64 的機器上(如 m1, raspberry pi),這邊一定要給定 arm64
# 否則預設 linux / amd64 會導致 pipeline 一直 pending
platform:
  os: linux
  arch: arm64

# 指定 pipeline trigger 的條件
# 這邊想要在 tag release 版號後觸發 pipeline build code 並 upload
# 因此 event 填入 tag
trigger:
  event:
    - tag

# for build code 使用,clone 時抓 depth = 1 即可,加快速度
clone:
  depth: 1

# 這邊開始定義 pipeline 的每個步驟
steps:
  - name: build
    image: node:14.17.6-buster-slim
    environment:
      CRX_KEY:
        # 重要資訊可以從 web 介面建立 secret 後,將 secret name 填入
        from_secret: crx_key
    commands:
      # 在這個 step, container 要跑的 shell command
      - npm install
      - npm run build
      - npm run crx
      - tar zcvf dist.tar.gz dist

  - name: publish
    # 官方提供的 plugin,可以將 build assets 上傳到 github release
    image: plugins/github-release
    settings:
      api_key:
        # 填入在 github 的 personal access token,文後教學如何取得
        from_secret: github_api_token
      files:
        - dist.tar.gz
        - crx/dist.crx
      # 給定 release name,這邊直接採用 tag 的名稱
      # 透過 drone 提供的環境變數,帶入目前 tag name(只有 tag event 才會有)
      title: ${DRONE_TAG}

因使用實際的 .drone.yml 為範例,這邊補充一些背景資訊

如何在 pipeline 中指定 platform

使用以下語法在 yml 中給定

platform:
  os: linux
  arch: arm64

詳細可參考文件語法

如前面 yml 中註解提到,如果沒有給定 platform,drone 預設是 linux / amd64,若恰好 runner 都不在這平台上,pipeline 就會一直 waiting 下去,讓人誤以為哪裡設定錯誤了,這邊一定要特別注意!(尤其是使用 m1 的朋友們)

如何在 drone 建立 secret

到 repo 下的 Settings > Secrets,點 New Secret,填入 Name 和對應 Value

無痛架設 Drone CI/CD

比如 Name = github_api_token Value = xxxxx

.drone.yml 中用以下語法即可帶入

# 明碼方式帶入值,不安全
api_key: xxxxx

# 使用 drone secret 帶入
api_key:
  from_secret: github_api_token

如何取得 github personal access token

和剛剛建立 OAuth Apps 一樣頁面,但改選左邊的 Personal access tokens ,輸入想要的 scope 後即可取得。此 token 是提供 create release 和 upload build assets 使用

無痛架設 Drone CI/CD

如何建立並上傳 build asset 到 github release

使用官方提供的 plugin github-release

image: plugins/github-release
settings:
  api_key:
    from_secret: github_api_token
  files:
    - dist.tar.gz
    - crx/dist.crx
  title: ${DRONE_TAG}

api_key 填入 github personal access token, files 填入需要上傳的檔案們,最後 title 給定 release 的名稱。這邊由 drone 提供的環境變數 DRONE_TAG 代入 tag 的名稱。

實際跑 pipeline 看看

.drone.yml 寫好後 commit 進去,並且對某一個 commit 下 tag,就會看到 drone 開始跑起來了!

無痛架設 Drone CI/CD

如何透過 drone cli 控制 drone server

首先依照文件指令在本機安裝 drone cli,並在架設好的 drone web 介面查詢 drone personal token

點畫面左下角帳號的頭像,就能找到自己的 token

無痛架設 Drone CI/CD

到 console 中設定環境變數並測試,若設定正確則回傳帳號名稱與信箱

$ export DRONE_SERVER=https://<your_drone_url>
$ export DRONE_TOKEN=<your_personal_token>
$ drone info

User: Jim
Email: [email protected]

如果覺得每次設定很麻煩,可以寫成一份 sh 檔,需要時 source 他即可

$ nano drone.sh

----------------------

#!/bin/zsh
export DRONE_SERVER=https://<your_drone_url>
export DRONE_TOKEN=<your_personal_token>

----------------------
$ source drone.sh
$ drone info

User: Jim
Email: [email protected]

剩下的指令就讓大家自行去文件中翻翻囉!

drone 還有很多好用的功能可以仔細研究,大家趕緊試試看吧!

延伸閱讀

如何建立 MySQL Replica DB?

Written by J
雖然大學唸的是生物,但持著興趣與熱情自學,畢業後轉戰硬體工程師,與宅宅工程師們一起過著沒日沒夜的生活,做著台灣最薄的 intel 筆電,要與 macbook air 比拼。 離開後,憑著一股傻勁與朋友創業,再度轉戰軟體工程師,一手扛起前後端、雙平台 app 開發,過程中雖跌跌撞撞,卻也累計不少經驗。 可惜不是那 1% 的成功人士,於是加入其他成功人士的新創公司,專職開發後端。沒想到卻在採前人坑的過程中,拓寬了眼界,得到了深層的領悟。