LonghornでおうちラボのKubernetesクラスタにストレージを用意する
この記事では、Kubernetes環境で利用できるストレージソリューションLonghornのセットアップ方法を解説します。
Longhornは、バックアップやスナップショット、レプリケーションといった機能を持つ多機能なストレージシステムですが、最も重要な役割はPersistent Volumeの管理です。KubernetesでPodがデータを永続化するために必要なPersistent Volume Claim(PVC)を作成し、「2GBのストレージが欲しい」「10GBのストレージが欲しい」とリクエストするだけで、Longhornが自動的にディスク容量を割り当ててくれます。このシンプルな機能によって、Kubernetesのストレージ管理が格段に楽になります。
Cloud native distributed block storage for Kubernetes
なおウェブサイトのトップには分散ブロックストレージと記載がありますが、ブロックストレージとして構築しようとするとKernelのバージョンやマシンリソースの要件が上がり、私のおうちラボでは厳しいです。今回はファイルシステム型のストレージとしてセットアップしていきます。
Kubernetesクラスタはcontrol plane 3台、worker 3台で組んであります。今年の別のポストではetcdクラスタを別の3台で用意し、そこにcontrol plane 3台とworker 1台でやっていましたが、今年にこれ以降Kubernetes関連でポストする際はx3 cp, x3 workerでやっていくと思います。
environment check script
Longhornを載せるのにKubernetesクラスタの各ノードは要件を満たしているのか、これをチェックするスクリプトが用意されています。
実施ログは以下の通りで、これら3点のエラー、警告がありました。
- kernel module iscsi_tcp missing
- cryptsetup package missing
- warning in regard with multipathd on Ubuntu hosts
$ curl -sSfL https://raw.githubusercontent.com/longhorn/longhorn/v1.8.1/scripts/environment_check.sh | bash
[INFO] Required dependencies 'kubectl jq mktemp sort printf' are installed.
[INFO] All nodes have unique hostnames.
[INFO] Waiting for longhorn-environment-check pods to become ready (0/0)...
[INFO] Waiting for longhorn-environment-check pods to become ready (0/6)...
[INFO] All longhorn-environment-check pods are ready (6/6).
[INFO] MountPropagation is enabled
[INFO] Checking kernel release...
[INFO] Checking iscsid...
[ERROR] kernel module iscsi_tcp is not enabled on lab-cp3
[ERROR] kernel module iscsi_tcp is not enabled on lab-cp1
[ERROR] kernel module iscsi_tcp is not enabled on lab-worker2
[ERROR] kernel module iscsi_tcp is not enabled on lab-worker1
[ERROR] kernel module iscsi_tcp is not enabled on lab-cp2
[ERROR] kernel module iscsi_tcp is not enabled on lab-worker3
[INFO] Checking multipathd...
[WARN] multipathd is running on lab-cp3 known to have a breakage that affects Longhorn. See description and solution at https://longhorn.io/kb/troubleshooting-volume-with-multipath
[INFO] Checking packages...
[ERROR] cryptsetup is not found in lab-cp1.
[ERROR] cryptsetup is not found in lab-worker2.
[ERROR] cryptsetup is not found in lab-worker1.
[ERROR] cryptsetup is not found in lab-cp2.
[ERROR] cryptsetup is not found in lab-worker3.
[INFO] Checking nfs client...
[INFO] Cleaning up longhorn-environment-check pods...
[INFO] Cleanup completed.
multipathd remed on lab-cp3
WARNメッセージ内に参照すべきURLも記載されていますが、/etc/multipath.conf
ファイルに以下を記載し、サービスリスタートしておきました。
blacklist {
devnode "^sd[a-z0-9]+"
}
cryptsetup package
cryptsetup
が見つからないという問題に関してはaptなりdnfなり、パッケージマネージャでインストールしました。
kernel modules
Kernelモジュールに監視て、/etc/modules-load.d/longhorn-requirements.conf
というファイルを用意し、以下の2行を記載してシステムを再起動してあります。
事前チェックスクリプトではiscsi_tcp
しか挙げられていませんが、実際にセットアップした後、Longhornのダッシュボードで各ノードを確認するとdm_crypt
に関しても見つからないというメッセージが出ていたので加えています。
iscsi_tcp
dm_crypt
その他の今回除外した要件について
Storage Performance Developer Kit, SPDKを利用したLonghorn V2 Data Engineではブロックストレージが使えるようですが、先にも触れたとおり要件が重いので今回は見送りました。
- SSE4.2 instruction set support
grep sse4_2 /proc/cpuinfo
- 5.19 or later is required for NVMe over TCP support
- v6.7 or later is recommended for improved system stability
- linux kernel modules
- vfio_pci
- uio_pci_generic
- nvme-tcp
- Huge page support, 2 GiB of 2 MiB-sized pages
Longhornのインストール
ステップとしては次の通りです。
- longhorn-system namespace作成
- longhornのhelm chartのバージョン確認
- valuesファイルに必要な変更を書いてGitOpsレポジトリに載せ
- fluxのHelmRepositoryおよびHelmReleaseマニフェストを用意し、infra-controllers kustomizationに追加
Longhornのhelm chartをfluxcdで導入する手順となっています。
longhorn-system namespace作成
HelmReleaseにnamespaceを作ってくれるオプションがありますが、namespaceは独立して管理したいのでflux-system kustomization下のディレクトリにマニフェストを用意します。
Cilium gatewayを利用してlonghornのダッシュボードへのアクセスを用意する予定ですので、必要なラベルを書き加えておきます。
# ./clusters/lab-hlv3/namespaces/longhorn-system.yaml
---
kind: Namespace
apiVersion: v1
metadata:
name: longhorn-system
labels:
service: longhorn
type: infrastructure
gateway: cilium
Longhornのhelmチャートとvalues
Helmレポジトリを追加し、バージョンを確認します。ついでにvaluesファイルもダウンロードします。
helm repo add longhorn https://charts.longhorn.io
helm search repo longhorn
# helm repo update
# store values file locally
helm show values --version 1.8.1 longhorn/longhorn > longhorn-1.8.1-values.yaml
valuesファイルへの変更点
私の場合、次の内容を変更しました。
- 各イメージをローカルのHarborより取得するよう更新
- longhorn ui replicaを2から1へ
- persistence settings
- レプリカカウントを3から2へ
- data localityをbest-effortへ
Flux helmrepo & helmrelease
詳細はスキップします。flux
コマンドでfluxのhelmrepoおよびhelmreleaseマニフェストが作成できるのですが、シェルスクリプトとしてコマンドを用意しています。このスクリプトで生成されたマニフェストをinfra-controllers kustomizationに追加するとインストールが進みます。複数のマイクロサービスが実行され、VMオンリーのラボ環境ではインストール開始から20分くらいで落ち着きました。
以下はインストール後のflux tree
出力の一部です。
$ flux tree ks infra-controllers
Kustomization/flux-system/infra-controllers
├── HelmRelease/flux-system/longhorn
│ ├── PriorityClass/longhorn-critical
│ ├── ServiceAccount/longhorn-system/longhorn-service-account
│ ├── ServiceAccount/longhorn-system/longhorn-ui-service-account
│ ├── ServiceAccount/longhorn-system/longhorn-support-bundle
│ ├── ConfigMap/longhorn-system/longhorn-default-resource
│ ├── ConfigMap/longhorn-system/longhorn-default-setting
│ ├── ConfigMap/longhorn-system/longhorn-storageclass
│ ├── CustomResourceDefinition/backingimagedatasources.longhorn.io
│ ├── CustomResourceDefinition/backingimagemanagers.longhorn.io
│ ├── CustomResourceDefinition/backingimages.longhorn.io
│ ├── CustomResourceDefinition/backupbackingimages.longhorn.io
│ ├── CustomResourceDefinition/backups.longhorn.io
│ ├── CustomResourceDefinition/backuptargets.longhorn.io
│ ├── CustomResourceDefinition/backupvolumes.longhorn.io
│ ├── CustomResourceDefinition/engineimages.longhorn.io
│ ├── CustomResourceDefinition/engines.longhorn.io
│ ├── CustomResourceDefinition/instancemanagers.longhorn.io
│ ├── CustomResourceDefinition/nodes.longhorn.io
│ ├── CustomResourceDefinition/orphans.longhorn.io
│ ├── CustomResourceDefinition/recurringjobs.longhorn.io
│ ├── CustomResourceDefinition/replicas.longhorn.io
│ ├── CustomResourceDefinition/settings.longhorn.io
│ ├── CustomResourceDefinition/sharemanagers.longhorn.io
│ ├── CustomResourceDefinition/snapshots.longhorn.io
│ ├── CustomResourceDefinition/supportbundles.longhorn.io
│ ├── CustomResourceDefinition/systembackups.longhorn.io
│ ├── CustomResourceDefinition/systemrestores.longhorn.io
│ ├── CustomResourceDefinition/volumeattachments.longhorn.io
│ ├── CustomResourceDefinition/volumes.longhorn.io
│ ├── ClusterRole/longhorn-role
│ ├── ClusterRoleBinding/longhorn-bind
│ ├── ClusterRoleBinding/longhorn-support-bundle
│ ├── Service/longhorn-system/longhorn-backend
│ ├── Service/longhorn-system/longhorn-frontend
│ ├── Service/longhorn-system/longhorn-conversion-webhook
│ ├── Service/longhorn-system/longhorn-admission-webhook
│ ├── Service/longhorn-system/longhorn-recovery-backend
│ ├── DaemonSet/longhorn-system/longhorn-manager
│ ├── Deployment/longhorn-system/longhorn-driver-deployer
│ └── Deployment/longhorn-system/longhorn-ui
└── HelmRepository/flux-system/longhorn
Longhorn UIへのアクセス
Longhornをhelmチャートでインストールするとlonghorn-frontendというserviceと、その接続先であるlonghorn-uiのpodが作られます。
Cilium gatewayの設定変更、HTTPRouteの追加をしてダッシュボードへのアクセスを用意します。
$ kubectl get svc longhorn-frontend -n longhorn-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
longhorn-frontend ClusterIP 10.96.107.178 <none> 80/TCP 23h
Cilium gateway
こちらが更新後のgatewayのマニフェストです。変更がfluxに渡されると対応するTLS証明書がcert-managerによって取得され、gatewayには"longhorn.lab.blink-1x52.net"でアクセスできるlistenerが追加されます。
# ./infrastructure/lab-hlv3/configs/cilium/gateway.yaml
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: cilium-gateway
namespace: gateway
annotations:
cert-manager.io/issuer: issuer
spec:
gatewayClassName: cilium
addresses:
- type: IPAddress
value: 192.0.2.79
listeners:
- name: whoami-kube-http
hostname: whoami-kube.lab.blink-1x52.net
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway: cilium
- name: whoami-kube-https
hostname: whoami-kube.lab.blink-1x52.net
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway: cilium
tls:
mode: Terminate
certificateRefs:
- name: tls-whoami-kube
kind: Secret
namespace: gateway
- name: longhorn-https
hostname: longhorn.lab.blink-1x52.net
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway: cilium
tls:
mode: Terminate
certificateRefs:
- name: tls-longhorn
kind: Secret
namespace: gateway
HTTPRoute
こちらがgatewayとlonghorn-frontendサービスを繋ぐHTTPRouteです。
# ./infrastructure/lab-hlv3/configs/longhorn/httproutes.yaml
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: longhorn-https
namespace: longhorn-system
spec:
parentRefs:
- name: cilium-gateway
sectionName: longhorn-https
namespace: gateway
hostnames:
- "longhorn.lab.blink-1x52.net"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: longhorn-frontend
port: 80
Longhorn UIとディスク
ダッシュボードより各ノードとディスクが確認できます。最初からある程度のディスクスペースは予約済みとして、残りは利用可能な状態となっています。
ルートファイルシステムとは別に追加ディスクを用意し、そちらを利用してデモへと進みます。
lab-worker2とlab-worker3それぞれに80GBディスクを追加します。
追記:追加ディスクはxfsファイルシステムとしてフォーマットします。のちにMinio S3で利用する予定だからです。
lab-worker2へのディスク追加
手順は次の通りです。
- 新しいディスクの作成
- 新しいiscsiコントローラの作成
- ディスクを接続
lab-worker2はHyper-V上で動かしているVMです。Powershellでの作業は以下の通りです。
# create a new vhdx
New-VHD -Path "F:\hyperv\vhd\lab-worker2-disk2.vhdx" -SizeBytes 80GB -Dynamic
# confirm the existing disks connected
Get-VMHardDiskDrive -VMName lab-worker2 -ControllerType SCSI
# confirm the controllers
# there should be a couple for disks and DVD drive
Get-VMScsiController -VMName lab-worker2
# add one controller
# and confirm the controller ID newly created and open for the new disk connection
Add-VMScsiController -VMName lab-worker2
Get-VMScsiController -VMName lab-worker2
# add the newly created vhdx to the VM using the available controller
Add-VMHardDiskDrive -VMName lab-worker2 -ControllerType SCSI -ControllerNumber 2 -Path "F:\hyperv\vhd\lab-worker2-disk2.vhdx"
lab-worker2上での作業は次の通りです。
- パーティション作成
- ext4でフォーマット
- マウント
# identify the device
sudo fdisk -l
# assuming the newly attached disk is on /dev/sda
sudo fdisk /dev/sda
# on fdisk menu,
# "p" to print existing partitions
# "d" to delete if there is any existing one
# "n" to create new partition, create "p" primary, one big partition
# and then "w" to write the change and exit fdisk
# confirm the result and should see /dev/sda1
sudo fdisk -l
# format /dev/sda1
# sudo apt install xfsprogs # if mkfs.xfs command is missing
sudo mkfs.xfs /dev/sda1
# confirm UUID of the formatted disk space
sudo blkid
# prepare directory to mount this new disk
sudo mkdir -p /mnt/disk2
システム起動時に自動的にマウントされるよう、/etc/fstab
ファイルに一行追記します。
UUID=UUID_FOR_DEV_SDA1_CONFIRMED_ABOVE /mnt/disk2 xfs defaults,noatime 0 2
問題がないか確認し、再起動します。
sudo findmnt --verify --verbose
sudo systemctl reboot
lab-worker3へのディスク追加
こちらのVMはProxmox上で稼働しています。Proxmox上での操作は以下の通りです。
# shutdown the target VM
# on this VM) sudo systemctl poweroff, or sudo shutdown -h now
# or on proxmox) qm stop VMID
export VMID=1234 # VM ID
# see the status of each available storage on proxmox ve
pvesm status
# list the disks on specific storage
pvesm list local-lvm
# create and allocate 80GB disk
pvesm alloc local-lvm $VMID vm-$VMID-disk2 80G
# confirm vm config
qm config $VMID
# attach the created disk at scsi1
qm set $VMID --scsi1 local-lvm:vm-$VMID-disk2
# verify and start the VM
pvesm list local-lvm
qm config $VMID
qm start $VMID
ディスクをVMに接続した後は、lab-worker2で実施した同じ作業をこちらのVMでも実施します。
Longhornへのディスク追加
/mnt/disk2
をそれぞれのノードで追加します。
ついでに、デモへ進める前にその他のディスクを全て無効にします。
PVCのテスト
追加ディスク以外すべて無効にした状態です。
- 156 Gi のスケジュール可能なストレージ
- スケジュール可能なストレージを持つノードは2ノード
テストに用いたマニフェストの概要は次の通りです。
- nginxのdeployment
- nginxへアクセスするためのservice
- nginxで使う1GiのPVC
マニフェストをGitOps用レポジトリに上げるとfluxcdへと渡り、PVCに対応したPVが作成されました。Podもボリュームもlab-worker2上に作成されました。
$ kubectl -n longhorn-system get pods -o wide | grep test
my-longhorn-test-676d6b57dc-gzqtc 1/1 Running 0 3m40s 10.0.3.202 lab-worker2 <none> <none>
NginxのdeploymentのnodeSelectorをlab-worker1とすると(そしてdeploymentをリスタートすると)、lab-worker2上のpodは落とされましたがPVCはそのままで、lab-worker1上に新たなpodが作成され、元々のPVCがそのままpodに接続されました。
podがlab-worker2上にある時とlab-worker1上にある時それぞれで、マウントしたボリューム上でファイルを更新しました。以下がcurl
で確認したときの出力です。
# edit /usr/share/nginx/html/index.html on the pod running on lab-worker2
$ kubectl exec deploy/tools -n testbed -- curl http://longhorn-test.longhorn-system.svc.lab.blink-1x52.net
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 50 100 50 0 0 21758 0 --:--:-- --:--:-- --:--:-- 50000
<html>
<body>
<h1>hi, world.</h1>
</body>
</html>
# nodeSelector lab-worker1 added to the deployment, pod gets re-created
# edit /usr/share/nginx/html/index.html on the pod running on lab-worker1
$ kubectl exec deploy/tools -n testbed -- curl http://longhorn-test.longhorn-system.svc.lab.blink-1x52.net
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 76 100 76 0 0 30170 0 --:--:-- --:--:-- --:--:-- 38000
<html>
<body>
<h1>hi, world.</h1>
<h2>hi, world at h2.</h2>
</body>
</html>
ダッシュボード上では以下のように見えていました。data localityに関して警告が出ていますが機能していました。
テスト用マニフェスト
テストに用いたマニフェストはこちらです。"nodeSelector"はあれこれ変更し、deploymentをリスタートすると指定のノードにpodを移すといった細かい操作ができます。
---
apiVersion: v1
kind: Service
metadata:
name: longhorn-test
namespace: longhorn-system
spec:
ports:
- name: http
targetPort: 80
port: 80
selector:
app: longhorn-test
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-longhorn-test
namespace: longhorn-system
spec:
replicas: 1
selector:
matchLabels:
app: longhorn-test
strategy:
type: Recreate
template:
metadata:
labels:
app: longhorn-test
spec:
containers:
- name: nginx
image: nginx:1.27.3-alpine
ports:
- containerPort: 80
volumeMounts:
- name: test-longhorn-volume
mountPath: /usr/share/nginx/html
volumes:
- name: test-longhorn-volume
persistentVolumeClaim:
claimName: test-longhorn-pvc
nodeSelector:
kubernetes.io/hostname: lab-worker1
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-longhorn-pvc
namespace: longhorn-system
spec:
storageClassName: longhorn
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
終わりに
以上です!
次はモニタリングかS3サービスいずれかをセットアップします。
Discussion
right... minio recommends xfs and the directpv I previously used by default sets up xfs drives. The minio s3 did work alright with longhorn provisioning ext4 PVs, but I guess I'll do some re-work on this