DroneCI 串接流程 (1) - CI 建置

CI (Continuous Integration) / CD (Continuous Delivery)

這系列 Drone 的文章是我在公司中因為需要優化開發流程而寫的 CI / CD 工具架設過程紀錄,給有需要的人參考,其中很感謝我的架構師夥伴 Jackie-Cheng 的技術協助,幫我一起研究文件、做了許多嘗試,最後才有這系列的文章。

Outline

  • 什麼是 CI / CD ?
  • CI 流程 - 流程設計
  • CI 流程 - 與 Bitbucket 串接
  • CI 流程 - 執行程式碼測試
  • CI 流程 - 整合至 Docker Hub

什麼是 CI / CD ?

身為一個程式開發者,在產品開發完畢後多少都會碰到環境架設的工作,規模小一點的專案,其實我自己以前也都是手動連上主機去拉最新版本下來更新的。但是稍微有一點規模的專案,很可能同時是會需要不同環境(正式/測試/開發環境)來配合的,所以上述說的舊做法可能就不再適用。

為了節省時間,我們需要引入 CI / CD(持續整合 / 持續發佈 )。

什麼是 CI 呢 ? CI 存在的目的就是為了創造一系列能夠自動化建置、打包、或測試專案的方式,如此一來團隊在開發產品的時候就能夠更頻繁的提交進度,然後系統透過監測每次的變動,就能夠持續地自動測試並驗證以確保品質和穩定性。

在 CI 階段結束,整合完畢確定沒問題之後,就可以透過 CD 流程來把新釋出的版本推送到測試/正式環境上,讓相關專案人員可以直接瀏覽更新後的結果,而這中間從推送新版本、測試程式碼功能及可讀性、到環境測試及部署,完全都是可以持續進行且自動化的,這就是 CI / CD 現在這麼熱門的原因。

我自己比較常聽見的 CI / CD 工具有 Travis CI / Jekins / Drone CI 三套,而 Drone CI 因為架設快速,設定撰寫方便, 又是開源免費的,所以我最近也對這套工具產生興趣,在這系列文章裡面,我打算以Drone為例,把整個建置流程記錄下來與大家分享。

CI 流程 - 流程設計

先構想一下整個 CI 流程, 一個可能的CI 流程如下:

  1. 發送 Commit / Merge / PR 到 Git Remote Repo
  2. 該 Repo 偵測到改變,通知 Drone Server 根據 drone.yml 做出相對應的 Task
  3. 開始跑測試及建置
  4. 沒問題之後發佈到 Docker Registry (ex. Docker Hub) 上推出新版本

整合新版本到 Docker Hub 之後其實還可以讓 Docker Registry 偵測更變然後自動部署到串接好的機器上,就像 Bitbucket 偵測程式碼的改變然後做動作一樣,不過這應該屬於 CD 的部分,先不深究,附上流程圖:

CI 流程圖

CI 流程 - 與 Bitbucket 串接

CI 通常會跟版本控制的流程綁在一起,而版控則有許多雲端服務,例如 Github / Gitlab / Gitlab 等幾個,透過這些 Git 服務,就能夠讓開發者可以把自己的專案源碼存放在第三方(較安全),這些服務基本上都是免費的,除非有需要使用到比較進階的功能。在這裡我們會用 Bitbucet 為例子來跟自己架設的 Drone Server 做串接來做到第一階段的 CI 部分。

Step 1. Bitbucket OAuth Setting

首先要在Bitbucket個人設定頁面新增一組 OAuth 的 Secret-Key Pair 來讓之後架設的 Drone CI 能夠得到對本人帳戶拉取 Git Repo 的權限。

進入新增頁面之後把Name / Description / Callback Url 寫一寫,記得 Callback Url 要填寫之後預計要架設 Drone Server 的位置後面加上 ‘/login’,才能讓 Drone Server 的 UI 正常運作!填好之後就可以送出了,會拿到一組 Key 跟 Secret,記得記下來。

Step 2. Drone Server 安裝及部署

之後可以連到你預計要跑 CI 測試的機器上,先把 Drone 的 Image 拉下來:

 docker pull drone/drone:1.0.0-rc.1

之後就可以把 Drone 的 Container 起起來了,用docker run 搭配對應的參數來啟動 Drone Server :

   docker run \
     --volume=/var/run/docker.sock:/var/run/docker.sock \
     --volume=/var/lib/drone:/data \
     --env=DRONE_BITBUCKET_CLIENT_ID={% your-bitbucket-key %} \
     --env=DRONE_BITBUCKET_CLIENT_SECRET={% your-bitbucket-secret %} \
     --env=DRONE_RUNNER_CAPACITY=2 \
     --env=DRONE_SERVER_HOST={% your-drone-server-host %} \
     --env=DRONE_SERVER_PROTO={% your-drone-server-protocol %} \
     --env=DRONE_AGENTS_DISABLED=true \
     --env=DRONE_TLS_AUTOCERT=false \
     --env=DRONE_USER_CREATE=username:{% your-repo-host-user%},admin:true \
     --publish=80:80 \
     --publish=443:443 \
     --restart=always \
     --detach=true \
     --name=drone \
     drone/drone:1

上述參數說明 :

  • your-bitbucket-key / secret : 在第一步驟時 Bitbucket OAuth 設定完成後取得的 Key Pair
  • your-drone-server-host : 在 Bitbucket OAuth 設定時所輸入的 Redirect Url 的 Host,如果使用 IP 位址的話可以把 Port 帶進來
  • your-drone-server-protocol : 你的 Drone Server 所使用的傳輸協定,輸入 http 或 https
  • your-repo-host-user : 對你的 repository 有控制權的使用者名稱,以這個專案為例,就是 Bitbucket 的使用者名 ,這行等於是讓自己對 Drone Server 有最高的存取權限,使用 GUI 時才能看到完整設定。

順利啟動之後,應該就可以在你所設定的位置看到 Drone 的操作介面了,第一次進入時會跳出跟 Bitbucket 要求權限的確認視窗,之後就不會有了。示意圖:

CI 流程 - 執行程式碼測試

把基本設定做完之後,Drone 在被觸發時,會自己找專案根目錄裡面的 .drone.yml 去做相對應的 Pipeline 動作,一個最基本 Drone Pipeline 的範例如下:

kind: pipeline
name: default

steps:
- name: frontend
  image: node
  commands:
  - npm install
  - npm test
...

steps 是一個 list ,用來描述你要做哪些事情。 你可以寫好幾個 step 分別執行不同的動作,每個 step 都會根據你 image 的設定,啟動一個包含你 Repo 的新 container ,然後根據 commands 執行你想做的事情,範例中的 step 就會安裝完專案所需的 module 之後,執行測試,然後結束。

CI 流程 - 自動發布到 Docker Hub

當 Drone Server 上面跑完測試,並且確認沒問題之後,我還希望 Drone 可以幫我自動推到 Ducker Hub 上發出新版本的 Image ,這一樣可以透過 drone.yml 設定檔完成。 加上一個新的 step 並且搭配 drone 的 Docker plugin ,然後把你 Docker Hub 帳號密碼 跟 Repo 名稱填入之後即可。

steps:
...
- name: docker  
  image: plugins/docker
  settings:
    repo: your-dockerhub-name / repo-name
    target: production
    username: herocat
    password: 123456
    tags: latest

這樣設定好以後每次有新的更動,我就能夠自動地 docker build 然後推新的 image 到我給的位置,這邊的帳號密碼如果沒有搭配其他工具,就只能用明碼寫入,非常不安全,不過這邊只是為了說明所以這樣做。後面我們會講到如何搭配 Drone 內建的機密資訊管理工具來確保專案資訊的隱密性(讓密碼或token這類資訊在 drone.yml 內可以不用明碼紀錄)。

補充一下,如果不想要每次推上新的 Commit 都跑 Docker 相關 task,則可以用 when 關鍵字來限定某些 branch 才會觸發。

steps:
...
- name: docker  
  image: plugins/docker
  settings:
    repo: your-dockerhub-name / repo-name
    target: production
    username: herocat
    password: 123456
    tags: latest
    when:
      branch:
      - master
      - feature/*

OK,目前已經完成我們設計的 CI 流程,在下一章節我會繼續往下補充如何完成 CD 的流程讓專案的新版本能夠自動部署到另外一台 Server 上。

下一篇: DroneCI 串接流程 (2) - CD 建置

參考文章:

什麼是 CI / CD ?

What is CI/CD? Continuous integration and continuous delivery explained

Drone CI Document

DroneCI 串接流程 (2) - CD 建置

上一篇: DroneCI 串接流程 (1) - CI 建置

在上一篇,我介紹了如何在自己的 Server 上架設 Drone 的主機,並與 Bitbucket 串接,從測試到專案建置、再到 Docker 的整合。到這裡我們已經完成了 CI 的部分,在第二個章節,我會跟大家分享如何繼續搭配 Drone 建置後續的 CD 流程。

Outline

  • CD 流程設想
  • Drone Agent 架設
  • Drone Secret 管理
  • 使用 drone-ssh plugin 部署新版本

CD 流程設想 (Continuous Delivery )

目前我們已經有了第一台 Drone Server ,後續其實可以再多架 Agent Server,而在跑 CI 測試流程的時候,可以把不同的 Pipeline 交給不同的主機去跑。指定 Pipeline 的設定一樣可以單單只由 drone.yml 完成。

在後面的章節中我們也會講到如何透過 Drone 來管理機密資訊,讓這些 Service 用到的密碼可以被隱蔽。而在所有的測試通過並跑完之後,我打算搭配 drone-ssh 這個套件來讓我能夠登入另一台 Server 並從 Docker Hub 上拉下最新版本的 Image 並完成部署:

以下是預計的架構裡面會需要的部分:

  • Drone (Master) Server : 最一開始架設,最主要專門 跑 Drone Pipeline 的 Server。
  • Drone Agent Server : 當 Pineline 需要做的事情比較多時用來幫忙分擔 Loading 的Server。
  • Secret 管理工具 : 有一些功能需要登入第三方服務的話,這個時候如果將密碼直些寫在 .drone.yml 檔案裡面(明文),那其實是非常不安全的行為,因此我們會需要工具來讓我們安全的在設定檔裡面使用這些密碼。
  • plugins/docker : Drone 裡面的 docker 插件, 使專案能夠快速推送新版至遠端 Docker Registry
  • drone-ssh : Drone 搭配的 ssh 工具,使專案能夠登入遠端另外一台主機執行寫好的指令

Agent Server 架設 ( 以Docker Compose 為例 )

Agent 的架設整體上可以分為幾個步驟:

  1. Agent Server 架設
  2. 設定 Agent Server 的 label 名稱 ,用以辨識
  3. 專案內 .drone.yml 檔案指定 跑 pipeline 的 Agent Server

補充:由於 Drone 的 Master 跟 Agent 之間是透過 RPC 溝通的,所以在啟動 Master 及 Agent 的 Container 時,記得要加上 RPC Token 相關的設定,這點可以參考 官方文件

Agent Server 架設- Docker Compose File :

基本上 Drone Agent 的架設跟第一章節提到的 Master Server 的設定相去不遠,差別只在使用的 Image 不同,其他部分 Drone 都幫我們做好了,我們只要提供相關的 RPC Token 再設定好 Server 的 Label ,以方便後面指定即可。

    version: "2.0"
    
    services:
      drone-agent:
        image: drone/agent
        restart: always
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
        environment:
          DRONE_RPC_PROTO: http
          DRONE_RPC_HOST: 125.227.167.242:5999
          DRONE_RPC_SECRET: c5b06c767123123ddd763b8e8
          DRONE_RUNNER_CAPACITY: 2
          DRONE_RUNNER_NAME: drone-agent-130
          DRONE_RUNNER_LABELS: hostname:drone-agent-130

重要參數說明 :

  1. DRONE_RPC_HOST : Drone Master Server 的位置,Agent才知道要聽誰的話
  2. DRONE_RUNNER_LABELS : 用來指定 Pipeline 的識別名稱,預設是主機名。
  3. DRONE_RPC_SECRET: 與 Drone Master Server 溝通的 Token ,用來讓兩邊互相溝通,Master 端也會有相同的設定,可以用以下指令來產生 Token :
        openssl rand -hex 16

其他 Agent 相關參數說明可以參考官方文件

寫好相關設定之後就可以透過 docker-compose 啟動 container 囉!

     docker-compose up -d ./docker-compose.yml

Drone Secret 管理

Drone 內建就有 Secret 管理功能,你也可以自己架第三方的工具,如 Vault 或是 AWS Secret Manager 等…來管理,在每個 Drone 管理介面上 Repository 的 Setting 點進去之後,就可以很快找到 Secret 管理的區塊,只要輸入對應的 Secret ,後續就可以直接在 drone.yml 檔案裡面引用囉。

在 drone.yml 裡面使用 from_secret 關鍵字引用剛剛設定好的密碼:

使用 Drone SSH Plugin 部署新版本至遠端 Server

在所有流程的最後,我想要把測試完畢沒有問題的版本部署到正式環境上,我找到了一個適合的套件讓我能夠直接登入 Production 環境的主機並且執行寫好的指令,所以我只要直接從 Docker Registry 上拉下最新版並重新啟動,就完成了最後部署的部分!

到這邊我們已經從 CI 測試流程,推到 Docker 儲存庫,並且全程搭配 Drone 的 Secret Management ,所以我在寫 drone.yml 的設定時,如果有些插件必須使用密碼登入,這些資訊就能夠安全的被使用,不會輕易外流。最後使用 drone-ssh 插件,直接在 Production 環境上部署,完成 最簡單的一個 CI/CD 流程。

完整的 CI/CD 流程應該會隨著團隊專案規模而改變,例如中大型專案常常搭配 Git Flow 或是 Github Flow ,然後會搭配 PR 觸發測試,通過以後才推送到 Dev 環境,減少錯誤機率,不過把基本功能跟流程理過一次後,後面怎麼變化就看使用者的需求了,非常感謝大家看到最後,以後有發現有興趣或有需要的工具再上來跟大家分享囉!

參考文章

https://www.slideshare.net/Robert_McDermott/anatomy-of-a-continuous-integration-and-delivery-cicd-pipeline

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×