本篇是系列中的第五篇內容,我們繼續聊聊如何把一個簡化過的私有云環境部署在筆記本里,以滿足低成本、低功耗、低延時的實驗環境。如果你有閒置的輕量雲伺服器,也可以動手試試。
寫在前面
作為“持續整合”章節的第一篇內容,我們先來聊聊在單機伺服器上的 CI 的使用。
關於基礎的搭建,之前的文章中已經多次提到,所以我就不再贅述,本文將著重介紹過程中的一些細節,如果你對 Gitea 和 Drone 或者 GitLab 感興趣,可以閱讀之前的內容:
- 《容器方式下的輕量倉庫與CI 使用方案:Gitea + Drone 基礎篇》
- 《使用容器方式編譯無功能限制的 Drone CI》
- 《輕量安全的部署方案》
- 《使用 Docker 和 Traefik v2 搭建輕量程式碼倉庫(Gitea)》
- 一些 GitLab 相關的內容
為了更低的維護成本,以及後續多機擴充套件使用,本文所有程式的使用均在容器環境下。
單機 CI 設計
在展開實踐細節之前,我們得先來聊聊“設計”。
架構設計
CI 過程中的參與者主要有下面這幾類(本篇暫不聊軟體倉庫部分):使用者、Git服務、CI 服務、CI 執行器。
簡單針對上面的參與者進行定義:“使用者”可以是有血有肉的人,也可以是自動化的指令碼或者 BOT,各種資料的創造者;“Git 服務”,用於儲存程式碼資料,提供基礎的許可權功能和介面管理的程式;“CI 服務”,提供持續整合的任務的排程和管理的程式;“CI 執行器”,用於執行具體的 CI 任務的程式。
考慮到單機伺服器上除了 Git 服務和 CI 服務之外,還會執行我們需要更新和部署的程式,為了讓資源使用效率更好、維護成本更低、避免我們為每一個 Web 程式配置 HTTPS 證書,我們可以新增一個支援服務發現的應用閘道器。
即使是單機伺服器,我們依舊需要注意 SSH 的使用安全,在多機環境下,我們會使用跳板機和雲伺服器安全策略來進行集中的安全管理,在單機場景下,我使用 SSH 服務開關來完成簡單的安全防護(不用的時候,直接關閉,也為網際網路上的嗅探機器人省點電)。
如果將上面的“參與者”用圖例來表示,一個最基礎的單機 CI 使用模式會類似下面這樣:
我將圖中不同角色的資料互動進行的數字序號標註,簡單解釋一下這些序號代表的具體內容:
- “1” 表示了使用者使用具體的域名來訪問我們的 Git 服務和 CI 服務,來進行倉庫管理或者配置 CI 任務。這類互動使用的是 HTTP 的方式,比如在瀏覽器中訪問
https://gitea.lab.com
、https://gitlab.lab.com
、https://drone.lab.com
。 - “2” 表示了使用者或者客戶端使用 SSH 的方式訪問 Git 倉庫,需要搭配 RSA Key 使用。
- “3” 和 “4” 表示了 Traefik 使用服務發現的方式,聚合 Git 服務和 CI 服務,為使用者提供域名形式的訪問方式,這裡使用的代理模式同樣也是 HTTP。
- “5” 表示了 SSH 開關和 Git SSH 服務之間的資料互動,互動形式為 TCP。
- “6” 和 “7” 表示了 CI 服務 分別和Git 服務、CI 執行器之間的資料互動,從 Git 獲取倉庫變動,然後建立 CI 任務,接著將 CI 任務執行狀態不斷推送至 Git 服務中,互動形式不限,可以使用 HTTP API,也可以使用各種基於 TCP 的 RPC 的方式。
- “8” 則表示了 CI 執行器如何從 Git 伺服器的程式碼倉庫中獲取程式碼,或者將一些資料更新回 Git 伺服器中,一般情況下是使用 HTTP 的方式,我更推薦使用 Git Over SSH 進行互動。
部署模式
在單機全容器模式下,我們一般會用兩種方式可以完成部署。
一類是基於檔案掛載的方式,比如在 CI 過程中將 CI JOB 容器中的檔案系統和宿主機打通,然後將構建產物同步到宿主機中、類似的變體還有使用各種網路檔案協議進行檔案系統掛載;另外一類,則是使用 SSH 或者 SCP 、Rsync 等方式,在容器中訪問宿主機完成資料交換或者服務初始化或啟停操作。
除此之外,如果我們藉助軟體倉庫、容器倉庫,還能夠完成純容器交付,讓互動更純粹和“乾淨”。這個話題,我們會在後續文章中展開。
單機 CI 配置實踐
接下來,我們以上文中的 “SSH 開關”這個應用,在 Gitea 和 Drone 環境中進行持續整合和部署實踐為例,來聊聊如何在單機模式下使用 CI。
因為這個專案型別是一個不支援熱載入的、需要持續執行的網路程式,程式的更新需要重啟服務。所以我們恰好可以使用“部署模式”中的掛載檔案的方式更新檔案,以及使用 SSH
的方式來進行服務的停止和重新啟動。(如果是靜態資源類的專案部署,則只需要完成資源替換更新即可)
定義 CI 配置檔案
首先將需要整合 CI 的專案放置上傳到 Gitea 中的某個倉庫中,這裡以上文中提到的 Git SSH 開關為例。在專案中建立一個名為 .drone.yml
的 CI 配置檔案。
一個相對通用的 CI 配置可以用下面的形式來表達:
---
kind: pipeline
name: default
steps:
- name: clone
- name: stop-previous-services
depends_on: [ clone ]
- name: update-services
depends_on: [ stop-previous-services ]
- name: start-new-services
depends_on: [ update-services ]
上面的配置包含了:下載倉庫程式碼、停止原先的服務、更新服務程式程式碼、重新啟動服務四個過程。在實際生產中,根據業務型別,我們的執行順序可能會有變化,甚至不再是上面的“序列”方式執行。
按照上面的配置將 CI 配置好之後,當我們推送程式碼到程式碼倉庫觸發 CI 任務後。在圖形介面中,我們將看到類似上圖的結果。
使用 SSH 協議下載程式碼
不論是使用哪一種 CI 工具,我都推薦你使用 Git Over SSH 的方式來獲取程式碼,而非使用 Git Token 或者賬號密碼的方式來進行互動。這樣可以讓你的程式對於某一種 CI 或者 Git 倉庫的依賴更低,更容易在合適的時間點、以低成本切換到更合適的工具。
在 Drone CI 中,如果想使用 SSH 方式來下載程式碼,可以使用下面的配置:(在 GitLab Runner 中同理)
---
kind: pipeline
name: default
clone:
disable: true
steps:
- name: clone
image: alpine/git
pull: if-not-exists
environment:
KEY:
from_secret: ssh_key
commands:
- GIT_HOST=$(echo $DRONE_GIT_SSH_URL | sed 's/git@/\1/' | sed 's/:.*/\1/') && mkdir "$HOME/.ssh" && echo "$KEY" > "$HOME/.ssh/id_rsa" && chmod 600 $HOME/.ssh/id_rsa && eval `ssh-agent -s` && ssh-add $HOME/.ssh/id_rsa && ssh-keyscan $GIT_HOST > ~/.ssh/known_hosts && chmod 400 "$HOME/.ssh/known_hosts";
- git clone $DRONE_GIT_SSH_URL .
- git -c advice.detachedHead=false checkout $DRONE_COMMIT
上面的程式碼中,為了使用 SSH 方式下載程式程式碼,CI 程式會做兩件事:
- 從 CI 軟體中讀取我們預先配置好的
ssh_key
環境變數,然後將變數輸出成程式可以直接使用的rsa_key
,並設定好許可權,使用ssh-agent
載入程式。 - 將倉庫使用預設的
HTTP
協議替換為Git
協議,以備程式使用。
當然,想要使用 SSH 方式下載程式碼,我們需要在 Git 軟體的賬號或者倉庫中配置 SSH Key
。
使用 SSH 方式操作服務啟停
這個應用中,我們在 docker-compose.yml
定義了容器的啟動方式,所以服務的啟動和關閉可以使用我們熟悉的命令 docker-compose up -d
和 docker-compose down
來完成。
因為 CI 在容器中執行,我們不能直接操作宿主機,所以需要藉助 SSH 或者 dind 模式的 docker.sock
來完成服務狀態的改變。
本文先聊聊如何使用 SSH 來解決基礎的部署操作:
- name: stop-or-start-services
image: deploy-tool
depends_on: [ clone ]
pull: if-not-exists
environment:
KEY:
from_secret: ssh_key
# 環境變數,除了私密的定義在 CI 軟體的環境變數中,也可顯式宣告在 CI 配置中
TARGET_HOST: user@host
TARGET_PORT: 22
commands:
- mkdir "$HOME/.ssh" && echo "$KEY" > "$HOME/.ssh/id_rsa" && chmod 600 $HOME/.ssh/id_rsa && eval `ssh-agent -s` && ssh-add $HOME/.ssh/id_rsa";
# 關閉服務
- ssh -i "$HOME/.ssh/id_rsa" -p $TARGET_PORT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $TARGET_HOST "bash -c \"cd /app-path/ && docker-compose down\""
# 啟動服務
- ssh -i "$HOME/.ssh/id_rsa" -p $TARGET_PORT -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $TARGET_HOST "bash -c \"cd /app-path/ && docker-compose up -d\""
和下載程式碼類似,我們從環境變數中初始化 rsa key
,然後在 ssh-agent
中載入私鑰。然後使用 ssh
客戶端連線宿主機,切換工作目錄,執行命令操作服務的啟動和關閉即可。
同樣的,想要使用 SSH 操作伺服器,我們需要在伺服器對應使用者的 ~/.ssh/authorized_keys
中配置對應的公鑰。
使用檔案掛載的方式更新程式碼
更新程式碼有兩種方式,一種是使用上文中提到的 SSH 的方式,遠端執行 scp
、rsync
等命令同步資料,另外一種則是使用檔案掛載的方式。因為我們的部署在同一臺機器上,所以檔案掛載不失為一個高效的方式。
以 Drone CI 配置為例,演示如何掛載宿主機目錄到容器內:
- name: update-services
image: deploy-tool
depends_on: [ stop-previous-services ]
pull: if-not-exists
commands:
- rm -rf /deploy/*
- cp -r /drone/src/* /deploy/
- cp -r /drone/src/.env /deploy/
volumes:
- name: host-dir
path: /deploy
volumes:
- name: host-dir
host:
path: /app-path
最後
在接下來的“持續整合”相關文章中,我將展開聊聊 CI 在多機和相對複雜場景下的使用,以及其他場景型別的部署實戰細節。
--EOF
我們有一個小小的折騰群,裡面聚集了幾百位喜歡折騰的小夥伴。
在不發廣告的情況下,我們在裡面會一起聊聊軟硬體、HomeLab、程式設計上的一些問題,也會在群裡不定期的分享一些技術沙龍的資料。
喜歡折騰的小夥伴歡迎掃碼新增好友。(新增好友,請備註實名,註明來源和目的,否則不會通過稽核)
如果你覺得內容還算實用,歡迎點贊分享給你的朋友,在此謝過。
本文使用「署名 4.0 國際 (CC BY 4.0)」許可協議,歡迎轉載、或重新修改使用,但需要註明來源。 署名 4.0 國際 (CC BY 4.0)
本文作者: 蘇洋
建立時間: 2022年01月02日
統計字數: 5438字
閱讀時間: 11分鐘閱讀
本文連結: https://soulteary.com/2022/01...