裝在筆記本里的私有云環境:持續整合(上)

soulteary發表於2022-01-03

本篇是系列中的第五篇內容,我們繼續聊聊如何把一個簡化過的私有云環境部署在筆記本里,以滿足低成本、低功耗、低延時的實驗環境。如果你有閒置的輕量雲伺服器,也可以動手試試。

寫在前面

作為“持續整合”章節的第一篇內容,我們先來聊聊在單機伺服器上的 CI 的使用。

關於基礎的搭建,之前的文章中已經多次提到,所以我就不再贅述,本文將著重介紹過程中的一些細節,如果你對 Gitea 和 Drone 或者 GitLab 感興趣,可以閱讀之前的內容:

為了更低的維護成本,以及後續多機擴充套件使用,本文所有程式的使用均在容器環境下。

單機 CI 設計

在展開實踐細節之前,我們得先來聊聊“設計”。

架構設計

CI 過程中的參與者主要有下面這幾類(本篇暫不聊軟體倉庫部分):使用者、Git服務、CI 服務、CI 執行器。

簡單針對上面的參與者進行定義:“使用者”可以是有血有肉的人,也可以是自動化的指令碼或者 BOT,各種資料的創造者;“Git 服務”,用於儲存程式碼資料,提供基礎的許可權功能和介面管理的程式;“CI 服務”,提供持續整合的任務的排程和管理的程式;“CI 執行器”,用於執行具體的 CI 任務的程式。

考慮到單機伺服器上除了 Git 服務和 CI 服務之外,還會執行我們需要更新和部署的程式,為了讓資源使用效率更好、維護成本更低、避免我們為每一個 Web 程式配置 HTTPS 證書,我們可以新增一個支援服務發現的應用閘道器。

即使是單機伺服器,我們依舊需要注意 SSH 的使用安全,在多機環境下,我們會使用跳板機和雲伺服器安全策略來進行集中的安全管理,在單機場景下,我使用 SSH 服務開關來完成簡單的安全防護(不用的時候,直接關閉,也為網際網路上的嗅探機器人省點電)。

如果將上面的“參與者”用圖例來表示,一個最基礎的單機 CI 使用模式會類似下面這樣:

CI 的基礎使用模式

我將圖中不同角色的資料互動進行的數字序號標註,簡單解釋一下這些序號代表的具體內容:

  • “1” 表示了使用者使用具體的域名來訪問我們的 Git 服務和 CI 服務,來進行倉庫管理或者配置 CI 任務。這類互動使用的是 HTTP 的方式,比如在瀏覽器中訪問 https://gitea.lab.comhttps://gitlab.lab.comhttps://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 等方式,在容器中訪問宿主機完成資料交換或者服務初始化或啟停操作。

單機模式下基於Docker 的 CI 部署模式

除此之外,如果我們藉助軟體倉庫、容器倉庫,還能夠完成純容器交付,讓互動更純粹和“乾淨”。這個話題,我們會在後續文章中展開。

單機 CI 配置實踐

接下來,我們以上文中的 “SSH 開關”這個應用,在 Gitea 和 Drone 環境中進行持續整合和部署實踐為例,來聊聊如何在單機模式下使用 CI。

配置好 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 ]

上面的配置包含了:下載倉庫程式碼、停止原先的服務、更新服務程式程式碼、重新啟動服務四個過程。在實際生產中,根據業務型別,我們的執行順序可能會有變化,甚至不再是上面的“序列”方式執行。

Gitea 倉庫配置好 CI 之後

按照上面的配置將 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 程式會做兩件事:

  1. 從 CI 軟體中讀取我們預先配置好的 ssh_key 環境變數,然後將變數輸出成程式可以直接使用的 rsa_key ,並設定好許可權,使用 ssh-agent 載入程式。
  2. 將倉庫使用預設的 HTTP 協議替換為 Git 協議,以備程式使用。

當然,想要使用 SSH 方式下載程式碼,我們需要在 Git 軟體的賬號或者倉庫中配置 SSH Key

使用 SSH 方式操作服務啟停

這個應用中,我們在 docker-compose.yml 定義了容器的啟動方式,所以服務的啟動和關閉可以使用我們熟悉的命令 docker-compose up -ddocker-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 的方式,遠端執行 scprsync 等命令同步資料,另外一種則是使用檔案掛載的方式。因為我們的部署在同一臺機器上,所以檔案掛載不失為一個高效的方式。

以 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...

相關文章