
Photo by Markus Winkler on Unsplash
因為近期正在尋找有什麼能夠使用在 Kubernetes 上,同時具備輕巧且功能又全面的儲存方案。這時從 CNCF 的 landscape 中看到了一個名為 Longhorn 的項目。稍微查了一下後發現這個項目在 2019 年的時候就已經被納入 CNCF 中。沒想到這都已經過去兩年了,人家都已經從 Sandbox 升到 Incubating 了。雖然感嘆自己的情報落後,但還是要轉換心情好好研究一下。
Longhorn 是一個由 Rancher Labs 建立的開源專案,其目的在於為 Kubernetes 提供雲原生的分散式儲存系統。除了部署簡單之外,同時也透過快照、副本以及遠端備份等機制保證了資料的安全性。
接下來的篇章,將會簡單介紹一下 Longhorn,並且示範如何部署以及怎麼將 Longhorn 建立出來的 volume 掛載到 Pod 裡使用。
測試環境
- Node 數量: 1
- Ubuntu 16.04
- Docker 20.10.7
- Kubernetes v1.16.15
- Helm v2.8.1
- Longhorn v1.1.3 (從 v1.2.0 之後只支援 Kubernetes v1.18+)
簡介
Longhorn 主要包含了以下兩個組件:
Longhorn Manager
Longhorn manager 是以 Kubernetes Operator 的形式,以 DaemonSet 的方式部署在所有的節點上。Longhorn Manager 同時也作為一個 API 服務,接收從 UI 或是 CSI plugin 發送過來的 API 請求。
當 Longhorn Manager 接收到建立 volume 的請求時,Longhorn Manager 會透過 Kubernetes API server 建立一個 Volume 及其它相關的 CRD 物件。在 volume 被掛載到某個節點上後,Longhorn Manager 會在這個節點上啟動一個 Longhorn Engine (Controller) 程序,然後在每台存放副本的節點上建立相對應的 Replica 程序。
Longhorn Engine
Longhorn Engine 主要包含了 Controller 和 Replica 兩個部分:
Controller: 透過 iSCSI 介面,將 volume 的讀寫操作轉換成內部的請求發送給 Replica,再由 Replica 實際在節點上的檔案處理完需求後將結果回報。此外也負責 Replica 的狀態檢測和重建,及處理 volume 的快照與備份等操作。
Replica: 接收來自 Controller 的請求,實際在節點上讀寫資料及執行快照或備份等動作。

以上圖為例,圖中的每個 Pod 各自佔用一個獨立的 volume。每個 volume 都會有一個專屬的 Longhorn Engine (Controller) 接收 volume 的讀寫請求。假如設定每個 volume 都會保存兩個副本,則 Controller 底下就會有兩個 Replica 程序,且每個 Replica 會負責在不同的節點上 (同一個 volume 的 Replica 預設不能執行在同一台節點上) 管理各自的資料副本。
除了上述提到的兩個核心組件,Longhorn 也有提供:
UI 介面: 可讓管理員能以更簡便的方式管理目前系統中的 volume 、快照及備份,或是調整可以調度的節點和節點上可供使用的磁碟。
CSI plugin: 讓 Kubernetes 可以透過 CSI 介面管理 Longhorn 的 volume。
安裝 Longhorn
在真正進入到 Longhorn 的部署之前,首先要依照 官方文件 的指示,安裝好必要的套件。
Longhorn 官方也有提供一個 shell script 能事先確認環境是否有符合需求。
$ curl -sSfL https://raw.githubusercontent.com/longhorn/longhorn/v1.1.3/scripts/environment_check.sh | bash
一切準備妥當後就可以開始 Longhorn 的部署。Longhorn 的安裝方式有三種:
- 透過 Rancher Catalog App 安裝
- 透過 Kubectl 使用 Manifest File 安裝
- 透過 Helm Chart 安裝
因為我們並沒有使用到 Rancher 的關係,所以第一種方式可以暫不考慮。
- 透過 Kubectl 使用 Manifest File 安裝
$ kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.1.3/deploy/longhorn.yaml
輸入上面的指令後,會創建一個叫 longhorn-system
的 namespace,並且將 Longhorn 相關的資源建立在該 namespace 下。接著可以再使用指令確認服務是否已經都準備完畢。
$ kubectl get po -n longhorn-system

- 透過 Helm Chart 安裝
# Add the Longhorn Helm repository
$ helm repo add longhorn https://charts.longhorn.io
# Fetch the latest charts from the repository
$ helm repo update
# Install Longhorn in the longhorn-system namespace
$ helm install longhorn/longhorn -n longhorn --namespace longhorn-system --version 1.1.3
從 repository 下載 helm chart 預設會使用最新的版本進行安裝,所以必須額外指定安裝版本為 1.1.3。 如果安裝環境沒辦法使用外部網路的話,官方也有提供相關的步驟說明如何進行離線安裝。如果有需要請自行參閱官方文件,這裡就不再深入介紹。
客制化安裝
Longhorn 預設會為每個 volume 建立三個副本到不同的節點上,但是目前我們只是為了做實驗,整個 Kubernetes 環境裡又只有一個節點。因此想要把預設的三個副本改成一個就好。
- 透過 Kubectl 使用 Manifest File 安裝
首先將 Longhorn 的 manifest file 下載回來:
$ wget https://raw.githubusercontent.com/longhorn/longhorn/v1.1.3/deploy/longhorn.yaml -O longhorn.yaml
打開下載回來的 longhorn.yaml,尋找 numberOfReplicas
這個關鍵字,把原本的值從 3 改成 1:
...
data:
storageclass.yaml: |
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: longhorn
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "1" # 3 -> 1
staleReplicaTimeout: "2880"
fromBackup: ""
...
接著用這個修改過後的檔案部署:
$ kubectl apply -f longhorn.yaml
- 透過 Helm Chart 安裝
首先把 helm chart 下載回來:
$ helm fetch longhorn/longhorn --version 1.1.3 --untar
進到下載回來的 longhorn 目錄下,編輯 values.yaml,將 defaultClassReplicaCount
的值改成 1:
...
persistence:
defaultClass: true
defaultClassReplicaCount: 1 # 3 -> 1
reclaimPolicy: Delete
recurringJobs:
enable: false
jobList: []
...
安裝修改後的 helm chart:
$ helm install longhorn -n longhorn --namespace longhorn-system
除了修改安裝時的參數,在安裝完成之後,也可以直接修改 Longhorn 設定:
$ kubectl -n longhorn-system edit cm longhorn-storageclass
與修改 kubectl 的 manifest file 類似,只要改掉 numberOfReplicas
的值就可以了。
設定 UI 介面
Longhorn 雖然有提供 UI 介面,但預設是沒有對外接口也沒有任何權限認證的。所以官方建議是另外安裝一個 Nginx Ingress Controller。除了作為對外的入口之外,同時 Nginx Ingress Controller 也有提供認證機制,避免管理介面對外後被人隨便連進來亂搞。
Ingress controller 的安裝請參考官方的文件進行。另外雖然 Nginx Ingress Controller 有提供其它的認證方式,但這邊還是採用最簡單的帳密認證形式來操作。
# Create a basic auth file
$ USER=<USERNAME_HERE>; PASSWORD=<PASSWORD_HERE>; echo "${USER}:$(openssl passwd -stdin -apr1 <<< ${PASSWORD})" >> auth
# Create a secret
$ kubectl -n longhorn-system create secret generic basic-auth --from-file=auth
首先透過上面的指令建立一組帳密並且輸出到一個名為 auth 的檔案中。 接著再用 kubectl 指令將檔案內容儲存成一個 Kubernetes secret 物件。
最後再建立 ingress 物件:
# ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: longhorn-ingress
namespace: longhorn-system
annotations:
# type of authentication
nginx.ingress.kubernetes.io/auth-type: basic
# prevent the controller from redirecting (308) to HTTPS
nginx.ingress.kubernetes.io/ssl-redirect: 'false'
# name of the secret that contains the user/password definitions
nginx.ingress.kubernetes.io/auth-secret: basic-auth
# message to display with an appropriate context why the authentication is required
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required '
spec:
rules:
- http:
paths:
- backend:
serviceName: longhorn-frontend
servicePort: 80
此為我從 官網 的範例根據目前的 Kubernetes 版本 (v1.16.15) 修改過的模版
$ kubectl apply -f ingress.yaml
上述步驟完成後就可以透過 ingress controller 連到 Longhorn UI 了。只是一般而言存取 ingress controller 必須透過 node port。要記 node port 對我來說有點麻煩,而且這也只是個實驗環境,所以可以讓我隨便亂玩,因此我選擇將 ingress controller 的 Deployment 修改成直接使用主機網路,好讓我可以直接用 443 port 存取服務。
# kubectl -n ingress-nginx edit deploy ingress-nginx-controller
...
spec:
containers:
- name: controller
hostNetwork: true # set hostNetwork to true
nodeSelector:
kubernetes.io/os: linux
restartPolicy: Always
schedulerName: default-scheduler
...
實際連上 UI 試試

在嘗試連上 UI 時會跳出視窗要求輸入帳號密碼。在登入成功後便可以看到 Longhorn 的 UI 介面。
以上就完成了 Longhorn 的安裝,實際操作與應用方式,請繼續閱讀 Longhorn — 雲原生儲存系統試玩(中)
Reference
- Longhorn | The Longhorn Documentation
- CNCF接納Rancher Longhorn為沙箱項目,加速K8S持久化儲存發展
- Day 12 Kubernetes 持久戰 - Rancher Longhorn 安裝基礎操作篇
- Longhorn 微服務化儲存初試
- longhorn-engine 源碼分析