持續部署概述
持續部署是能以自動化方式,頻繁而且持續性的,將軟體部署到生產環境。使軟體產品能夠快速迭代。
在之前部署 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 超時時間