持續部署概述
持續部署是能以自動化方式,頻繁而且持續性的,將軟件部署到生產環境。使軟件產品能夠快速迭代。
在之前部署 web 項目時,都是手動進行部署
拉取代碼 ---> 編譯項目 ---> 打包鏡像 ---> 推送鏡像倉庫 ---> 服務器拉取新鏡像 ---> 停止和移除舊容器 ---> 啟動新容器
這一整套部署步驟枯燥又費時。
持續部署就是使用工具自動處理整套步驟。代碼在提交之后自動執行整套流程將項目部署到生產環境,省去繁瑣的人工操作。
持續部署整套流程本質上是一個極其簡單的東西。可以拆解為兩個階段
- 打包階段: 拉取代碼 ---> 編譯項目 ---> 鏡像打包 ---> 推送鏡像倉庫
- 部署階段: SSH 連接服務器 ---> 拉取新鏡像 ---> 停止和移除舊容器 ---> 啟動新容器
未使用自動化部署工具時,整套套也可以使用 .sh 腳本實現半自動化。甚至可以編寫一個小程序,自動連接服務器實現全自動化。
而所謂的持續部署工具本質上做的也是這么一件事,只是提供了更強大更豐富的功能。
Drone
持續部署工具一開始打算使用 Gitlab
, Gitlab
中直接集成代碼倉庫和持續部署工具,用起來會方便很多,但部署完 Gitlab
發現小服務器真心扛不住。
后也考慮過大名鼎鼎的jenkins
,查詢資料發現 Jenkins
資源占用也挺大,最后選擇了一個輕量級的工具 Drone
Drone
也是一個優秀、開源的持續部署工具,具有很高的關注度。https://github.com/harness/drone
不過稍微遺憾的是 Drone
社區不太完善。尤其國內,資料很少。折騰部署時利用 Google
搜索也耗費了不少時間。
Drone 簡介
Drone
應用由 Server(服務器)
和 Runner(執行器)
兩種服務構成。
Server(服務器)
主要負責管理和展示, Runner(執行器)
主要負責執行操作。
Server
Server(服務器)
負責的工作主要有
- 連接集成代碼倉庫
- 提供 web 管理頁面
- 管理
Runner
代碼倉庫
Drone
可以無縫集成多種主流代碼倉庫,官方給出了具體的使用文檔。

提供 Web 頁面
Server
負責提供 web 管理頁面顯示執行情況。
管理 Runner
Server
服務可以與一個或多個 Runner
連接通信進行管理。
Runner
Runner(執行器)
是真正執行持續部署操作服務。Runner
執行時會輪詢 Server
來確定執行的操作。
Drone
官方提供了多種類型的 Runner(執行器)
,用於適配不同的運行環境。

SSH Runner
類型 Runner
可以使用容器化管理,所以可以使用 Docker Runner
代替。
Drone
提供了 管道(Pipeline)
機制,管道(Pipeline)
機制下一篇介紹
Drone 部署
Database
Drone
數據存儲默認使用 sqlite
數據庫。並且提供支持 postgres
和 mysql
。
官方文檔中強烈建議使用 postgres
而非 mysql
。 某些操作在 mysql
未得到優化。 https://docs.drone.io/server/storage/database/
PS: 支持 postgres9.6 及更高版本 、 mysql:5.6 及更高版本
Gitea 配置
在此直接集成之前部署的 Gitea
倉庫, 至於其它倉庫,有興趣的可以查詢文檔:https://docs.drone.io/server/overview/
部署 Drone
之前需要先在 Gitea
中添加一個 OAuth
登錄密鑰, Drone
使用的 OAuth
方式登錄。
登錄成功后重定向 URL 地址為 Drone
登錄頁。 /login 路由。
PS:注意,此地址必須設置公網可訪問地址。
將 客戶端 ID 和 客戶端密鑰 保存。 客戶端 ID 和 客戶端密鑰 需要在 Drone
配置中使用


Dockerfile
version: '3.9'
# 創建自定義網絡
networks:
drone:
name: drone
driver: bridge
services:
# 數據庫服務
db:
image: postgres:latest
container_name: drone_db
restart: always
networks:
- drone # 加入到drone網絡
ports:
- '7931:5432'
environment:
- POSTGRES_USER=drone # PGSQL默認用戶
- POSTGRES_PASSWORD=drone # PGSQL默認密碼
- POSTGRES_DB=drone # PGSQL默認數據庫
volumes:
- /volumes/drone/db:/var/lib/postgresql/data
# Drone Server 服務
server:
image: drone/drone:2.8.0 # 目前drone最新版本為 2.8.0
container_name: drone_server
restart: always
networks:
- drone # 加入到drone網絡
ports:
- '7929:80'
environment:
- DRONE_SERVER_PROTO=http # 訪問協議,創建webHooks和重定向
- DRONE_SERVER_HOST=82.157.55.94:7929 # 主機名稱,創建webHooks和重定向
- DRONE_RPC_SECRET=e1ad8a7f3dbc68ca9c21bcc949335009 # 與 drone runner 通訊的密鑰
- DRONE_USER_CREATE=username:yxs970707,admin:true # 管理員賬戶
- DRONE_DATABASE_DRIVER=postgres # 數據庫類型
- DRONE_DATABASE_DATASOURCE=postgres://drone:drone@db/drone?sslmode=disable # 數據庫連接
- DRONE_GIT_ALWAYS_AUTH=true # 使用 oauth 身份驗證信息拉取代碼
- DRONE_GITEA_SERVER=https://gitea.mwjz.live # gitea服務器地址
- DRONE_GITEA_CLIENT_ID=2c921d85-e40e-41f8-90e0-c77c383786b5 # gitea 客戶端 id
- DRONE_GITEA_CLIENT_SECRET=ZVZoRWK6jR5mqgAIm6sB5VX6C2LPK1sYKv4hQWyTdULu # gitea 客戶端 密鑰
- DRONE_GITEA_SKIP_VERIFY=false # 禁用 gitea 鏈接時 tls 驗證
volumes:
- /volumes/drone/server:/data
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
- db
# Drone Docker Runner
runner:
image: drone/drone-runner-docker:1.8.0 # 目前drone-runner-docker最新版本為 1.8.0
container_name: drone_runner
restart: always
networks:
- drone # 加入到drone網絡
ports:
- '7930:3000'
environment:
- DRONE_RUNNER_NAME=docker-runner
- DRONE_RUNNER_CAPACITY=10 # 限制runner可執行的並發管道數量
- DRONE_RPC_PROTO=http # 訪問drone server 協議
- DRONE_RPC_HOST=server # 訪問drone server 服務器地址
- DRONE_RPC_SECRET=e1ad8a7f3dbc68ca9c21bcc949335009 # 與 drone server 通訊的密鑰
- DRONE_UI_USERNAME=yxs970707 # Drone Runner 的 UI 用戶賬號
- DRONE_UI_PASSWORD=yxs970707 # Drone Runner 的 UI 用戶密碼
volumes:
- '/var/run/docker.sock:/var/run/docker.sock'
depends_on:
- server
Dockerfile
中部署了三個服務:
- 數據庫(
postgres
) - Server(
drone/drone:2.8.0
) - Runner(
drone/drone-runner-docker:1.8.0
)
數據庫使用的是 postgres
。三個服務之間通信使用的是自定義 network
。
PS: 多個應用服務可以共享同一個數據庫服務,也可以創建獨立的數據庫服務。在當前服務器中,
Gitea
應用和Drone
應用創建了各自獨立的數據庫服務,這種方式會浪費一些服務器資源。但是維護起來比較方便。
具體采用哪種方案可以根據不同場景選擇
部署 Drone
的 environment 屬性有些麻煩,在此簡單介紹下某些屬性。
Server
DRONE_SERVER_PROTO 、 DRONE_SERVER_HOST
這兩個屬性是設置 Webhook
重定向 URL 的訪問協議和主機名稱。 Webhook
在下面會介紹到。
DRONE_RPC_SECRET
此屬性是設置 Server(服務器)
與 Runner(執行器)
之間通訊的密鑰,Server(服務器)
與 Runner(執行器)
必須設置相同的密鑰值才允許通信。
可以在 服務器(Linux) 中使用 openssl
生成密鑰
openssl rand -hex 16

DRONE_USER_CREATE
此屬性是設置 Drone
管理員。
注意:username 必須設置為 OAuth
用戶(Gitea
的用戶名),否則不具有管理員權限。
非管理員會少部分功能,例如不許設置 Trusted 屬性

DRONE_DATABASE_DRIVER 、 DRONE_DATABASE_DATASOURCE
這兩個屬性是設置數據庫類型和數據庫連接。
具體連接配置可以參考官方文檔
DRONE_GIT_ALWAYS_AUTH
此屬性是設置 OAuth
登錄用戶進行拉取代碼
默認情況下 OAuth
只作用於登錄操作。但存儲庫設置為私有時,需要登錄用戶才允許拉取代碼,此時需要將此屬性設置為 true
可以參考 https://discourse.drone.io/t/fatal-could-not-read-username-for/6198
默認值為 false
DRONE_GITEA_SERVER 、 DRONE_GITEA_CLIENT_ID 、DRONE_GITEA_CLIENT_SECRET
這幾個屬性是設置 Gitea
地址和 OAuth
ID、密鑰。
DRONE_GITEA_SKIP_VERIFY
此屬性是設置禁用 Gitea
的 TLS
驗證,
此屬性為 false 時,當 Gitea
使用 HTTPS
協議但證書有問題,會出現授權驗證失敗,報 x509 錯誤。
下圖是將 網關(Nginx)
中 Gitea
證書特意處理無效后進行的授權驗證測試。 有興趣的朋友可以自行測試。

當存儲庫使用 HTTPS
協議但沒有證書情況下,此屬性設置設置為 true 跳過 TLS
驗證。
默認值為 false
Runner
DRONE_RUNNER_CAPACITY
此屬性是設置 Runner(執行器)
並發管道數量
默認值為 2
DRONE_RPC_PROTO 、DRONE_RPC_HOST
這兩個屬性設置通信 Server(服務器)
的協議和主機名。 主機名使用 server-name
DRONE_UI_USERNAME、DRONE_UI_PASSWORD
Runner(執行器)
也具有 UI 展示頁面,可以查看當前執行器的執行信息。這兩個屬性是設置 UI 展示頁面的用戶名稱和密碼
執行部署
使用 Dockerfile
進行部署,大概率不會出現問題,我進行了多次測試,
但部署 Drone
難免會碰到問題,每個人碰到的問題還不盡相同。所以需要善用 Google
查詢
部署成功后訪問,會跳轉到歡迎頁面,點擊按鈕就會進行 Gitea
登錄

登錄成功后會跳轉到主頁面,主頁面上只有一項,就是 Gitea
中目前的存儲庫(web),這個存儲庫當前為未激活狀態。

未激活情況下進入當前項目會跳轉到 settings 頁面,當前頁面具有一個激活按鈕,點擊就可以激活此存儲庫
激活后會向 Gitea
注入一個 Webhook
。
這個 Webhook
會監聽倉庫的變更情況,當代碼倉庫發生變化時, Webhook
會向 Drone
推送消息。
Drone
接收到消息之后便可以執行,這也就是持續部署的第一步。



Drone 設置
激活完畢之后 settings 頁面就會出現很多設置
Protected
此屬性是設置 是否要驗證 配置文件(.drone.yml)
中的簽名,開啟后簽名驗證錯誤則不允許構建
Trusted
此屬性設置是否允許使用掛載權限,掛載在之后會介紹。
不開通此權限,volumes 掛 host path 時報 Linter: untrusted repositories cannot mount host volumes 錯誤
注意:非管理員用戶不具有此屬性。
Auto cancel pushes、Auto cancel running
這兩個屬性是優化操作的屬性。
開啟這兩個屬性,當執行構建任務時,會自動取消之前未執行完畢的構建任務。
當合並多個 commit 時,這個屬性具有很好的效果。
Timeout、Configuration
timeout 是設置構建任務執行的超時時間。
Configuration 是設置配置文件文件,默認為 .drone.yml。 這個一般不需要改動。
PS: 注意:配置文件必須設置根目錄
Secrets
secrets 是用來設置敏感屬性的。
編寫配置時,有些敏感數據需要隱藏,如賬號密碼,這些屬性可以配置 Secrets 使用

測試執行
現在對 Gitea
中 web 項目提交就可以觸發 Webhook
發送消息,
也可以在 Gitea
中主動觸發 Webhook
測試
但當前推送會返回一個 context deadline exceeded (Client.Timeout exceeded while awaiting headers) 錯誤。
這個錯誤是因為根目錄中沒有找到 配置文件(.drone.yml),
https://discourse.gitea.io/t/client-timeout-exceeded-while-awaiting-headers/4148/4


在根目錄創建 .drone.yml 文件並添加了一個測試配置,配置文件中內容下一篇介紹
kind: pipeline # 定義一個管道
type: docker # 當前管道的類型
name: test # 當前管道的名稱
steps: # 定義管道的執行步驟
- name: test # 步驟名稱
image: node:latest # 當前步驟使用的鏡像
commands: # 當前步驟執行的命令
- echo 測試drone執行

提交代碼,Webhook
會主動推送到 Drone
,Drone
會成功構建任務。


PS:有可能還是會推送失敗或者構建失敗,可能會發生各種各樣的問題。
在頁面中, 具有兩個 steps,這是因為默認第一個會拉取倉庫代碼,當然這個操作也可以禁用。
網關配置
server {
#SSL 訪問端口號為 443
listen 443 ssl http2;
#填寫綁定證書的域名
server_name drone.mwjz.live;
#日志
error_log /var/log/nginx/drone/error.log;
access_log /var/log/nginx/drone/access.log;
#證書文件
ssl_certificate /etc/nginx/conf.d/ssl/drone/drone.mwjz.live_bundle.crt;
#證書密鑰文件
ssl_certificate_key /etc/nginx/conf.d/ssl/drone/drone.mwjz.live.key;
ssl_ciphers SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!3DES:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://10.0.24.12:7929;
}
}
Drone
方面,我沒有找到怎么修改配置,所以直接使用了暴力方式,重新部署。
部署的時候不需要清理 volume
, 不清理重新部署還會保留之前的記錄,當然也可以清理后重新部署。
如果沒有刪除 volume
的話,需要在 Gitea
中手動修改一下 Webhook
的推送地址
server:
image: drone/drone:2.8.0 # 目前drone最新版本為 2.8.0
container_name: drone_server
restart: always
networks:
- drone # 加入到drone網絡
ports:
- '7929:80'
environment:
- DRONE_SERVER_PROTO=https # 訪問協議,創建webHooks和重定向
- DRONE_SERVER_HOST=drone.mwjz.live # 主機名稱,創建webHooks和重定向



無證書 HTTPS 觸發 Webhook
在部署時碰到這樣一種情況,當 Drone
使用 HTTPS
但是沒有證書情況下,Webhook
推送也會出現 X509 錯誤。


解決這個問題需要設置 Gitea
的配置, 在 /data/gitea/conf/app.ini 配置文件中設置跳過驗證
[webhook]
SKIP_TLS_VERIFY = true

也可以在部署 Gitea
時直接添加在 Dockerfile
中 environment 屬性
#gitea服務
server:
image: gitea/gitea:latest
container_name: gitea_server
restart: always
environment:
- GITEA__webhook__SKIP_TLS_VERIFY=true # webhook 跳過 tls 驗證
- GITEA__webhook__DELIVER_TIMEOUT=10 # webhook 超時時間