用于生产 k3s 集群的 Longhorn 存储:动态 PVC 扩展、复制和灾难恢复
k3s 和 Rancher 上使用 Longhorn 的生产级分布式存储
存储是Kubernetes中最难的问题。计算是无状态且可替换的——杀死一个 Pod,安排另一个 Pod。 Networking 拥有成熟的 CNI 插件和服务网格。 But storage?存储是状态所在,数据在重新启动后仍然存在,单个错误配置可能意味着永久数据丢失。对于运行生产工作负载(数据库、消息队列、应用程序状态)的 k3s 集群,您需要一个分布式、弹性、可扩展且可操作的存储解决方案。 Longhorn 就是这样的解决方案。
Longhorn 是适用于 Kubernetes 的轻量级、可靠且易于使用的分布式块存储系统。它最初由 Rancher Labs(现为 SUSE 的一部分)开发,是一个 CNCF 孵化项目,专为简单性很重要但生产可靠性不容妥协的集群而构建。与需要专用存储节点和深厚专业知识的 Ceph 或提供零冗余的本地路径配置程序不同,Longhorn 实现了 k3s 集群所需的精确平衡:跨节点的分布式复制、动态卷扩展、云对象存储的集成备份、快照和灾难恢复 - 所有这些都通过干净的 UI 和 Kubernetes 原生 CRD 进行管理。
本指南涵盖了在 k3s 上部署 Longhorn 进行生产所需的一切:架构内部结构、安装方法、StorageClass 配置、动态 PVC 扩展、复制策略、备份和灾难恢复、卷加密、数据库性能调整、监控和故障排除。每项建议都附带经过生产测试的配置,您可以适应您的环境。
Longhorn 架构
了解 Longhorn 的架构对于做出有关复制、性能和故障处理的明智决策至关重要。 Longhorn 由三个核心组件组成,它们协同工作,在连接到 Kubernetes 节点的本地磁盘上提供分布式块存储。
Longhorn Manager作为 DaemonSet 在集群中的每个节点上运行。它是 Longhorn 的控制平面 — 它处理 API 调用、编排卷创建、管理复制、协调快照和备份,并与 Kubernetes API 服务器通信以管理 PersistentVolume 和 PersistentVolumeClaim 生命周期。当您创建引用 Longhorn StorageClass 的 PVC 时,Longhorn Manager 通过 CSI 驱动程序接收请求、配置卷并在可用节点上安排其副本。
Longhorn 引擎是一个按卷存储控制器,作为 Linux 用户空间进程实现(基于 Rancher Longhorn 引擎的分支)。每个卷都有自己的专用引擎进程,在该卷所附加的节点上运行。该引擎处理该卷的所有读取和写入 I/O,在确认对应用程序的写入之前将写入同步复制到所有配置的副本。这种按卷的架构意味着一个卷的引擎崩溃或挂起不会影响任何其他卷——这是生产的关键隔离属性。
副本是实际的数据存储过程。每个副本在其运行的节点的本地磁盘上存储卷数据的完整副本。默认情况下,Longhorn 为每个卷创建三个副本,分布在不同的节点(也可以选择不同的区域)。副本对快照使用写时复制机制,无论卷大小如何,都可以即时创建快照。
该架构为生产使用提供了几个关键属性。容错能力:在三个节点上具有三个副本,该卷可以承受两个同时出现的节点故障。隔离:每个卷都有自己的引擎进程,因此一个卷中的错误或挂起无法级联。简单性:没有专用存储节点,没有单独的 Ceph 或 GlusterFS 集群 — Longhorn 使用本地磁盘在与应用程序 Pod 相同的工作节点上运行。Kubernetes-native:的所有内容均通过 CRD、kubectl 和 Kubernetes CSI 接口进行管理。
在 k3s
上安装 LonghornLonghorn 可以通过三种方法安装在 k3s 上:Helm 图表(建议用于生产)、Rancher App Marketplace(如果您有 Rancher 管理集群)或直接 kubectl apply。安装之前,请确保您的节点满足先决条件。
先决条件
# Verify prerequisites on each node
# Required: open-iscsi (for iSCSI support)
sudo apt-get install -y open-iscsi
sudo systemctl enable iscsid
sudo systemctl start iscsid
# Required: NFSv4 client (for backup/restore to NFS targets)
sudo apt-get install -y nfs-common
# Recommended: check all prerequisites with Longhorn's environment check script
curl -sSfL https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/scripts/environment_check.sh | bash
# Verify kernel modules
lsmod | grep -E "iscsi_tcp|dm_crypt|nfs"
# On k3s specifically, local-path-provisioner is the default.
# We will make Longhorn the default StorageClass after installation.通过 Helm 安装(推荐)
# Add the Longhorn Helm repository
helm repo add longhorn https://charts.longhorn.io
helm repo update
# Create the namespace
kubectl create namespace longhorn-system
# Install with production values
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--version 1.7.2 \
--values longhorn-values.yaml这是具有调整默认值的生产级values.yaml:
# longhorn-values.yaml — Production configuration
persistence:
defaultClass: true
defaultFsType: ext4
defaultClassReplicaCount: 3
defaultDataLocality: best-effort
reclaimPolicy: Retain
defaultSettings:
backupTarget: s3://longhorn-backups@eu-west-1/
backupTargetCredentialSecret: longhorn-backup-s3-secret
createDefaultDiskLabeledNodes: true
defaultDataPath: /var/lib/longhorn/
defaultReplicaCount: 3
defaultDataLocality: best-effort
replicaSoftAntiAffinity: false
replicaAutoBalance: best-effort
storageOverProvisioningPercentage: 150
storageMinimalAvailablePercentage: 15
guaranteedInstanceManagerCPU: 12
upgradeChecker: false
autoSalvage: true
autoDeletePodWhenVolumeDetachedUnexpectedly: true
disableSchedulingOnCordonedNode: true
replicaZoneSoftAntiAffinity: true
volumeAttachmentRecoveryPolicy: wait
snapshotDataIntegrity: fast-check
snapshotDataIntegrityCronjob: "0 7 * * *"
concurrentAutomaticEngineUpgradePerNodeLimit: 1
longhornManager:
priorityClass: system-cluster-critical
tolerations:
- key: "node-role.kubernetes.io/storage"
operator: "Exists"
effect: "NoSchedule"
longhornDriver:
priorityClass: system-cluster-critical
tolerations:
- key: "node-role.kubernetes.io/storage"
operator: "Exists"
effect: "NoSchedule"
longhornUI:
replicas: 2
ingress:
enabled: true
ingressClassName: nginx
host: longhorn.internal.example.com
tls: true
tlsSecret: longhorn-tls
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: longhorn-basic-auth
nginx.ingress.kubernetes.io/auth-realm: "Longhorn UI"
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi通过 Rancher 应用市场安装如果 Rancher 管理您的 k3s 集群,请导航至应用程序和 应用程序。市场 → 图表 → Rancher UI 中的 Longhorn。选择您的目标命名空间 (longhorn-system),通过表单界面配置值,然后单击安装。 Rancher 自动处理 Helm 生命周期管理和升级跟踪。
通过 kubectl 安装
# Direct manifest installation
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/v1.7.2/deploy/longhorn.yaml
# Verify all pods are running
kubectl -n longhorn-system get pods -w安装后:将 Longhorn 设置为默认 StorageClass
# Remove default annotation from k3s local-path
kubectl patch storageclass local-path -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
# Verify Longhorn is now default
kubectl get storageclass
# NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
# longhorn (default) driver.longhorn.io Retain Immediate true 5m
# local-path rancher.io/local-path Delete WaitForFirstConsumer false 30d用于生产的StorageClass 配置
默认的 Longhorn StorageClass 适用于开发,但生产工作负载需要针对不同用例的特定配置 - 数据库需要高复制和特定数据局部性,临时处理需要快速单副本卷,共享卷需要 RWX 支持。
# StorageClass for database workloads — maximum durability
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-db
annotations:
storageclass.kubernetes.io/is-default-class: "false"
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Retain
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "2880"
fromBackup: ""
fsType: ext4
dataLocality: best-effort
recurringJobSelector: '[{"name":"db-snapshot","isGroup":true},{"name":"db-backup","isGroup":true}]'
---
# StorageClass for general workloads — balanced
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-standard
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "2"
staleReplicaTimeout: "2880"
fsType: ext4
dataLocality: best-effort
---
# StorageClass for temporary/cache workloads — performance
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-fast
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "1"
staleReplicaTimeout: "2880"
fsType: ext4
dataLocality: strict-local
---
# StorageClass for RWX (ReadWriteMany) shared volumes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-rwx
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Retain
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "3"
nfsOptions: "vers=4.1,hard,timeo=50,retrans=3"
staleReplicaTimeout: "2880"
fsType: ext4动态 PVC 扩展
Longhorn 最重要的生产功能之一是动态 PVC 扩展 — 能够在不停机、不丢失数据的情况下增加持久卷的大小,并且除了单个 kubectl 命令或清单更改之外无需手动干预。这对于数据增长不可预测并且磁盘空间不足意味着中断的数据库至关重要。
Longhorn 支持在线扩展(卷在增长时保持连接和安装)和离线扩展(首先分离卷)。在线扩展是默认且推荐的生产方法,因为它可以避免应用程序停机。
在 StorageClass
中启用卷扩展动态PVC扩展的关键要求是StorageClass必须具有allowVolumeExpansion: true。 Longhorn 默认 StorageClass 已包含此字段,但如果您有自定义 StorageClass,请验证此字段是否已设置。
# Verify your StorageClass supports expansion
kubectl get storageclass longhorn -o yaml | grep allowVolumeExpansion
# allowVolumeExpansion: true
# If not set, patch it
kubectl patch storageclass longhorn -p '{"allowVolumeExpansion": true}'分步:动态扩展 PVC
# 1. Check current PVC size
kubectl get pvc pg-data-postgresql-0 -n database
# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
# pg-data-postgresql-0 Bound pvc-abc123 50Gi RWO longhorn-db 30d
# 2. Check current usage inside the pod
kubectl exec -n database postgresql-0 -- df -h /var/lib/postgresql/data
# Filesystem Size Used Avail Use% Mounted on
# /dev/longhorn 49G 42G 7.0G 86% /var/lib/postgresql/data
# 3. Expand the PVC (online — no downtime)
kubectl patch pvc pg-data-postgresql-0 -n database --type merge -p '{
"spec": {
"resources": {
"requests": {
"storage": "100Gi"
}
}
}
}'
# 4. Watch the expansion progress
kubectl get pvc pg-data-postgresql-0 -n database -w
# Wait for CAPACITY to update from 50Gi to 100Gi
# 5. Verify the filesystem expanded inside the pod
kubectl exec -n database postgresql-0 -- df -h /var/lib/postgresql/data
# Filesystem Size Used Avail Use% Mounted on
# /dev/longhorn 99G 42G 57G 43% /var/lib/postgresql/data
# 6. Verify via Longhorn volume status
kubectl -n longhorn-system get volumes.longhorn.io -o wide通过警报自动执行 PVC 扩展
在生产中,您不应等到磁盘已满 86% 时才手动对其进行扩展。使用 Prometheus 警报自动触发扩展或在容量变得至关重要之前提醒待命工程师。
# PrometheusRule for PVC capacity alerts
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: pvc-capacity-alerts
namespace: monitoring
spec:
groups:
- name: pvc-capacity
rules:
- alert: PVCCapacityWarning
expr: |
(kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes) > 0.80
for: 10m
labels:
severity: warning
annotations:
summary: "PVC {{ $labels.persistentvolumeclaim }} at {{ $value | humanizePercentage }} capacity"
runbook: "Expand the PVC using: kubectl patch pvc {{ $labels.persistentvolumeclaim }} -n {{ $labels.namespace }} --type merge -p '{\"spec\":{\"resources\":{\"requests\":{\"storage\":\"NEW_SIZE\"}}}}'"
- alert: PVCCapacityCritical
expr: |
(kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes) > 0.90
for: 5m
labels:
severity: critical
annotations:
summary: "CRITICAL: PVC {{ $labels.persistentvolumeclaim }} at {{ $value | humanizePercentage }}"
description: "Immediate expansion required to prevent application failure"卷复制和数据局部性
Longhorn 跨多个节点复制卷数据以防止硬件故障。复制因子和数据局部性设置控制持久性、性能和存储效率之间的权衡。
复制因子决定存在多少数据副本。默认值为 3,这意味着每次写入都存储在三个不同的节点上。对于生产数据库,3 是最小推荐值。对于不太重要的工作负载,您可以将其设置为 2 以节省存储空间,或者对于可以接受数据丢失的临时/缓存卷,将其设置为 1。
数据局部性控制 Longhorn 是否尝试将副本保留在与使用卷的 Pod 相同的节点上。共有三种模式:
- 禁用— 副本纯粹根据可用空间和反关联性进行调度。 Pod 可能会从远程节点上的副本读取数据,从而给每个 I/O 操作增加网络延迟。
- 尽力而为— Longhorn 尝试将一个副本放置在与消费 Pod 相同的节点上。如果本地节点空间不足或 Pod 迁移,卷仍然可以工作,但延迟可能会稍高。这是大多数工作负载的推荐设置。
- 严格本地— 该卷只能在具有本地副本的节点上使用。如果 pod 被调度到没有本地副本的节点,则卷附加会失败。仅将其用于延迟敏感的单副本工作负载(您接受持久性权衡)。
# Change replication factor on an existing volume
kubectl -n longhorn-system patch volumes.longhorn.io pvc-abc123 \
--type merge -p '{"spec":{"numberOfReplicas":3}}'
# Set data locality on existing volume
kubectl -n longhorn-system patch volumes.longhorn.io pvc-abc123 \
--type merge -p '{"spec":{"dataLocality":"best-effort"}}'
# Replica auto-balancing (spreads replicas evenly across nodes)
# Set via Longhorn settings
kubectl -n longhorn-system edit settings.longhorn.io replica-auto-balance
# Set value to: best-effort快照和备份
Longhorn 提供两种不同的数据保护机制:快照(本地、即时、用于快速回滚)和备份(远程、到对象存储、用于灾难恢复)。了解何时使用每种方法至关重要。
快照与卷副本本地存储在同一磁盘上。它们是使用写时复制即时创建的——在快照时不复制任何数据,只有在快照分配额外空间后进行新的写入。快照非常适合在有风险的迁移或部署之前快速回滚,但它们不能防止节点或磁盘故障,因为它们与卷位于同一存储上。
备份将卷数据复制到外部备份目标 — S3、GCS、Azure Blob 或任何 S3 兼容存储(MinIO、Wasabi)。备份在块级别是增量的:仅传输自上次备份以来更改的块。这使得定期备份变得快速且存储高效。备份可以防止整个集群丢失,因为它们是独立存在的。
配置备份目标
# Create the S3 credentials secret
kubectl create secret generic longhorn-backup-s3-secret \
-n longhorn-system \
--from-literal=AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE \
--from-literal=AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY \
--from-literal=AWS_ENDPOINTS=https://s3.eu-west-1.amazonaws.com
# Set the backup target in Longhorn settings
kubectl -n longhorn-system edit settings.longhorn.io backup-target
# Set value to: s3://longhorn-backups@eu-west-1/
kubectl -n longhorn-system edit settings.longhorn.io backup-target-credential-secret
# Set value to: longhorn-backup-s3-secret
# For GCS backup target
# value: s3://longhorn-backups@us/ (GCS is S3-compatible via interop)
# Or use the GCS JSON key:
kubectl create secret generic longhorn-backup-gcs-secret \
-n longhorn-system \
--from-literal=GOOGLE_APPLICATION_CREDENTIALS=/var/longhorn-backup/gcs-key.json \
--from-file=gcs-key.json=./service-account-key.json
# For Azure Blob backup target
kubectl create secret generic longhorn-backup-azure-secret \
-n longhorn-system \
--from-literal=AZBLOB_ACCOUNT_NAME=prodbackupstorage \
--from-literal=AZBLOB_ACCOUNT_KEY=base64encodedkeyhereVolumeSnapshot 类和快照 YAML
# VolumeSnapshotClass for Longhorn
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: longhorn-snapshot-vsc
driver: driver.longhorn.io
deletionPolicy: Delete
parameters:
type: snap
---
# Create a VolumeSnapshot
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: pg-data-snap-before-migration
namespace: database
spec:
volumeSnapshotClassName: longhorn-snapshot-vsc
source:
persistentVolumeClaimName: pg-data-postgresql-0
---
# Restore a PVC from a snapshot
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pg-data-restored
namespace: database
spec:
storageClassName: longhorn-db
dataSource:
name: pg-data-snap-before-migration
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi定期备份计划
# Recurring snapshot job — every 4 hours, retain 6
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: db-snapshot-4h
namespace: longhorn-system
spec:
cron: "0 */4 * * *"
task: snapshot
retain: 6
concurrency: 2
groups:
- db-volumes
labels:
tier: database
---
# Recurring backup job — daily at 02:00, retain 14 days
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: db-backup-daily
namespace: longhorn-system
spec:
cron: "0 2 * * *"
task: backup
retain: 14
concurrency: 2
groups:
- db-volumes
labels:
tier: database
---
# Recurring backup job — weekly full, retain 8 weeks
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: db-backup-weekly
namespace: longhorn-system
spec:
cron: "0 3 * * 0"
task: backup
retain: 8
concurrency: 1
groups:
- db-volumes
labels:
tier: database
---
# Assign recurring jobs to a volume via labels
# Label the PVC or volume with: recurring-job-group.longhorn.io/db-volumes: enabled
kubectl label pvc pg-data-postgresql-0 -n database \
recurring-job-group.longhorn.io/db-volumes=enabled灾难恢复
Longhorn 通过DR 卷提供内置灾难恢复机制。是辅助集群中的备用卷,持续从主集群的备份目标中提取增量备份。当灾难发生时,您激活灾难恢复卷,它会变成常规读写卷,让辅助集群接管。
设置 DR 卷
# On the DR cluster: create a DR volume from the primary's backup
# This is done via the Longhorn UI or API
# 1. Configure the DR cluster's backup target to point to the same S3 bucket
kubectl -n longhorn-system edit settings.longhorn.io backup-target
# value: s3://longhorn-backups@eu-west-1/
# 2. Create a DR volume from the latest backup
# Via Longhorn UI: Backup → Select volume → Create DR Volume
# Via kubectl:
apiVersion: longhorn.io/v1beta2
kind: Volume
metadata:
name: pg-data-dr
namespace: longhorn-system
spec:
size: "107374182400" # 100Gi in bytes
numberOfReplicas: 3
fromBackup: "s3://longhorn-backups@eu-west-1/?backup=backup-abc123&volume=pg-data"
standby: true
frontend: ""
# 3. The DR volume auto-syncs incremental backups from S3
# Monitor sync status:
kubectl -n longhorn-system get volumes.longhorn.io pg-data-dr -o jsonpath='{.status.lastBackup}'
# 4. During failover — activate the DR volume:
kubectl -n longhorn-system patch volumes.longhorn.io pg-data-dr \
--type merge -p '{"spec":{"standby":false,"frontend":"blockdev"}}'
# 5. Create a PVC bound to the activated DR volume
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pg-data-postgresql-0
namespace: database
spec:
storageClassName: longhorn-db
volumeName: pg-data-dr
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi卷加密
Longhorn 支持使用 Linux LUKS2 的卷级加密。加密卷保护底层磁盘上的静态数据 - 即使有人获得对服务器存储的物理访问权限,如果没有加密密钥,他们也无法读取卷数据。
# Create a Kubernetes secret with the encryption passphrase
kubectl create secret generic longhorn-crypto \
-n longhorn-system \
--from-literal=CRYPTO_KEY_VALUE="a-very-long-and-random-passphrase-here" \
--from-literal=CRYPTO_KEY_PROVIDER=secret \
--from-literal=CRYPTO_KEY_CIPHER=aes-xts-plain64 \
--from-literal=CRYPTO_KEY_HASH=sha256 \
--from-literal=CRYPTO_KEY_SIZE=256 \
--from-literal=CRYPTO_PBKDF=argon2i
# StorageClass with encryption enabled
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-encrypted
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Retain
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "2880"
fromBackup: ""
encrypted: "true"
csi.storage.k8s.io/provisioner-secret-name: longhorn-crypto
csi.storage.k8s.io/provisioner-secret-namespace: longhorn-system
csi.storage.k8s.io/node-publish-secret-name: longhorn-crypto
csi.storage.k8s.io/node-publish-secret-namespace: longhorn-system
csi.storage.k8s.io/node-stage-secret-name: longhorn-crypto
csi.storage.k8s.io/node-stage-secret-namespace: longhorn-systemReadWriteMany (RWX) 支持
默认情况下,Longhorn 卷是 ReadWriteOnce (RWO) — 它们可以由单个节点上的单个 Pod 挂载。对于需要跨多个 Pod 共享存储的工作负载(例如,共享媒体上传、配置文件、ML 模型工件),Longhorn 通过集成 NFS 服务器支持 ReadWriteMany (RWX)。
当 PVC 请求 RWX 访问模式时,Longhorn 会自动部署一个共享管理器 Pod,该 Pod 运行由 Longhorn 卷支持的 NFS 服务器。然后,多个 Pod 可以通过 NFS 同时挂载该卷。这比部署单独的 NFS 服务器更简单,但与直接块访问相比增加了一层网络开销。
# PVC with ReadWriteMany access mode
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-media
namespace: application
spec:
storageClassName: longhorn-rwx
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50GiLonghorn上的数据库工作负载
在 Longhorn 上运行数据库需要仔细注意 StorageClass 参数、pod 关联性和备份集成。 Longhorn 的每卷引擎和同步复制使其非常适合数据库工作负载,但您需要正确配置它才能获得生产级的性能和可靠性。
PostgreSQL StatefulSet 与 Longhorn
# PostgreSQL StatefulSet using Longhorn PVC
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgresql
namespace: database
spec:
serviceName: postgresql
replicas: 3
selector:
matchLabels:
app: postgresql
template:
metadata:
labels:
app: postgresql
spec:
terminationGracePeriodSeconds: 120
securityContext:
fsGroup: 999
runAsUser: 999
containers:
- name: postgresql
image: postgres:16-alpine
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: production
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: pg-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: pg-credentials
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
resources:
requests:
cpu: "1"
memory: 2Gi
limits:
cpu: "4"
memory: 8Gi
volumeMounts:
- name: pg-data
mountPath: /var/lib/postgresql/data
livenessProbe:
exec:
command: ["pg_isready", "-U", "$(POSTGRES_USER)"]
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command: ["pg_isready", "-U", "$(POSTGRES_USER)"]
initialDelaySeconds: 5
periodSeconds: 5
volumeClaimTemplates:
- metadata:
name: pg-data
labels:
recurring-job-group.longhorn.io/db-volumes: enabled
spec:
storageClassName: longhorn-db
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100GiMySQL StatefulSet 与 Longhorn
# MySQL StatefulSet using Longhorn PVC
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: database
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
terminationGracePeriodSeconds: 60
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-credentials
key: root-password
- name: MYSQL_DATABASE
value: production
args:
- "--default-authentication-plugin=mysql_native_password"
- "--innodb-buffer-pool-size=4G"
- "--innodb-log-file-size=1G"
- "--innodb-flush-log-at-trx-commit=1"
- "--sync-binlog=1"
resources:
requests:
cpu: "1"
memory: 4Gi
limits:
cpu: "4"
memory: 8Gi
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
labels:
recurring-job-group.longhorn.io/db-volumes: enabled
spec:
storageClassName: longhorn-db
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi针对数据库工作负载的性能调整
Longhorn 在应用程序和物理磁盘之间添加了一个存储复制层,与直接本地磁盘访问相比,这会引入一些延迟。对于大多数工作负载来说,这种开销可以忽略不计,但具有大量写入模式的数据库工作负载需要进行调整才能实现最佳性能。
使用数据局部性:尽力而为。这可确保一个副本与数据库 Pod 位于同一节点上,这意味着读取会以 NVMe/SSD 速度命中本地磁盘。写入仍会复制到远程节点,但本地副本消除了读取的网络往返。
专用于 Longhorn 的磁盘。不要与 Longhorn 数据共享操作系统磁盘。 添加专用 NVMe 或 SSD 驱动器并将其配置为 Longhorn 磁盘。这可以防止操作系统和数据库卷之间的 I/O 争用。
# Configure dedicated disks on a node
# Via kubectl (Longhorn node CRD)
kubectl -n longhorn-system edit nodes.longhorn.io worker-01
# Add the dedicated disk under spec.disks:
spec:
disks:
default-disk:
allowScheduling: false # disable OS disk for Longhorn
path: /var/lib/longhorn/
storageReserved: 0
nvme-data:
allowScheduling: true
path: /mnt/nvme-longhorn/
storageReserved: 10737418240 # 10Gi reserved
tags:
- nvme
- database设置有保证的引擎管理器 CPU。Longhorn 的引擎进程使用 CPU 进行 I/O 处理和复制。guaranteedInstanceManagerCPU设置为 Longhorn 实例管理器保留一定比例的节点 CPU,以防止 CPU 在负载下饥饿。
调整副本计数。对于已经具有应用程序级复制(PostgreSQL 流复制、MySQL 组复制、MongoDB 副本集)的数据库,您可以将 Longhorn 副本数量减少到 2 个,而不是 3 个。数据库自身的复制提供了额外的数据保护层,更少的 Longhorn 副本意味着更少的写入放大和更好的写入吞吐量。
使用 ext4 而非 xfs 来实现小型随机 I/O。虽然 xfs 在大型顺序写入方面表现出色,但 ext4 通常在数据库工作负载典型的小型随机 I/O 模式方面表现更好。在您的 StorageClass 中设置fsType: ext4。
节点调度和磁盘管理
Longhorn 提供对用于卷调度的节点和磁盘的细粒度控制。这在异构集群中至关重要,其中一些节点具有快速 NVMe 存储,而其他节点具有较慢的 SATA 驱动器。
# Tag nodes for storage scheduling
kubectl label node worker-01 node.longhorn.io/storage=nvme
kubectl label node worker-02 node.longhorn.io/storage=nvme
kubectl label node worker-03 node.longhorn.io/storage=nvme
kubectl label node worker-04 node.longhorn.io/storage=sata
# Use node selector in StorageClass to target NVMe nodes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-nvme
provisioner: driver.longhorn.io
allowVolumeExpansion: true
parameters:
numberOfReplicas: "3"
nodeSelector: "node.longhorn.io/storage=nvme"
diskSelector: "nvme,database"
dataLocality: best-effort使用 Prometheus 和 Grafana 进行监控
Longhorn 通过内置指标端点公开 Prometheus 指标。监控这些指标对于容量规划、性能分析和主动警报至关重要。
# ServiceMonitor for Longhorn metrics
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: longhorn-prometheus
namespace: monitoring
labels:
release: prometheus
spec:
selector:
matchLabels:
app: longhorn-manager
namespaceSelector:
matchNames:
- longhorn-system
endpoints:
- port: manager
path: /metrics
interval: 30s
---
# PrometheusRule for Longhorn alerts
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: longhorn-alerts
namespace: monitoring
spec:
groups:
- name: longhorn-storage
rules:
- alert: LonghornVolumeStatusCritical
expr: longhorn_volume_robustness == 3
for: 5m
labels:
severity: critical
annotations:
summary: "Longhorn volume {{ $labels.volume }} is Faulted"
- alert: LonghornVolumeStatusDegraded
expr: longhorn_volume_robustness == 2
for: 10m
labels:
severity: warning
annotations:
summary: "Longhorn volume {{ $labels.volume }} is Degraded"
- alert: LonghornNodeStorageWarning
expr: |
(longhorn_node_storage_usage_bytes / longhorn_node_storage_capacity_bytes) > 0.80
for: 15m
labels:
severity: warning
annotations:
summary: "Longhorn node {{ $labels.node }} storage at {{ $value | humanizePercentage }}"
- alert: LonghornBackupFailed
expr: longhorn_backup_state == 3
for: 5m
labels:
severity: critical
annotations:
summary: "Longhorn backup failed for volume {{ $labels.volume }}"为 Longhorn 监控创建的关键 Grafana 仪表板面板包括:卷 IOPS(读/写)、卷吞吐量 (MB/s)、卷延迟 (p50/p95/p99)、副本重建进度、节点存储容量和使用情况、备份状态和期限以及每个卷的快照计数。
k3s 集群,具有完整的 Longhorn 存储堆栈
下图显示了 Longhorn 如何融入完整的 k3s 生产堆栈(从裸机服务器到应用程序 Pod),并具有 Rancher 管理和 Prometheus/Grafana 可观察性。
与其他 Kubernetes 存储解决方案的比较
Longhorn 并不是 Kubernetes 的唯一存储选项。了解它与替代方案的比较有助于您根据您的具体要求做出正确的选择。
| 功能 | Longhorn | Rook-Ceph | OpenEBS (Mayastor) | 本地路径 |
|---|---|---|---|---|
| 复杂性 | 低 | 高 | 中 | 最小 |
| 复制 | 内置(2–3 个副本) | CRUSH 算法 | NVMe-oF 副本 | 无 |
| 动态 PVC 扩展 | 有(在线) | 有 | 有 | 无 |
| 快照 | COW 快照 | RBD 快照 | 是 | 否 |
| 备份到云端 | 内置 (S3/GCS/Azure) | 通过 rbd 导出 | 通过 Velero | 无 |
| DR 卷 | 本机备用卷 | RBD 镜像 | 无 | 无 |
| RWX 支持 | 是(基于 NFS) | 是(CephFS) | 否 | 否 |
| 卷加密 | LUKS2 | dmcrypt | 无 | 无 |
| UI | 内置 Web UI | Ceph 仪表板 | 最小 | 无 |
| 最小节点 | 1(3 个用于 HA) | 3(专用 OSD 节点) | 3 | 1 |
| 资源开销 | 低-中 | 高 | 中 | 无 |
| 最适合 | k3s/RKE2 生产 | 大型企业 | 高性能 NVMe | 开发/单节点 |
Longhorn 与 Rook-Ceph:Ceph 是更强大的系统 - 它通过复杂的 CRUSH 放置算法支持对象存储、文件存储和块存储。然而,Ceph 需要至少 3 个专用 OSD 节点、大量 RAM(每个 OSD 守护进程至少 4GB)以及深厚的操作专业知识。对于具有 3-10 个节点的 k3s 集群,Longhorn 以 10% 的运营成本提供 90% 的价值。
Longhorn 与 OpenEBS Mayastor:Mayastor 使用 NVMe-over-Fabrics 进行高性能复制,实现比 Longhorn 基于 TCP 的复制更低的延迟。如果原始 IOPS 和亚毫秒延迟是您最关心的问题,并且您拥有带 RDMA 网络的 NVMe 基础设施,那么 Mayastor 可能是更好的选择。对于大多数 k3s 部署,Longhorn 的集成备份、灾难恢复和操作简单性超过了 Mayastor 的性能优势。
Longhorn 与本地路径:本地路径配置程序是 k3s 的默认存储 — 它只是在节点的本地文件系统上创建目录。零复制、零快照、零备份集成。这对于开发来说很好,但对于生产数据来说是不可接受的。
生产最佳实践
这些建议是从运行数据库工作负载的数十个生产 k3s 集群中运行 Longhorn 中提炼出来的。
1. 设置实例管理器的资源预留。Longhorn 实例管理器(引擎和副本管理器)需要有保证的 CPU 以避免节点压力期间 I/O 停顿。在 Longhorn 设置中将guaranteedInstanceManagerCPU设置为至少 12%。
2. 对数据库卷使用 Retain 回收策略。切勿将Delete用于数据库 PVC。即使 PVC 被删除,Retain策略也会保留 PV 及其数据,为您提供防止意外删除的安全网。
3. 禁用生产副本软反关联性。设置replicaSoftAntiAffinity: false以确保副本始终分布在不同节点上。通过软反亲和力,当空间紧张时,Longhorn 可能会在同一节点上安排多个副本,这违背了复制的目的。
4. 在每个节点上预留存储空间。将storageMinimalAvailablePercentage设置为至少 15%。这可以防止 Longhorn 消耗所有磁盘空间,从而导致影响所有 Pod 的节点级问题。
5. 启用自动抢救。当至少一个副本仍然正常时,autoSalvage设置会自动恢复进入故障状态的卷。这减少了节点故障期间的人工干预。
6. 将优先级设置为系统集群关键。Longhorn 的管理器和驱动程序组件在节点压力期间不应被驱逐。将它们的priorityClass 设置为system-cluster-critical以确保它们能够在 Pod 驱逐中幸存下来。
7. 为所有生产量配置重复作业。每个生产卷都应具有快照和备份重复作业。每 4 小时创建一次快照以实现快速回滚,每天进行一次备份以实现灾难恢复。
8. 定期测试 DR 卷激活。创建每月计划来激活备用集群中的 DR 卷、验证数据完整性并练习故障转移过程。从未经过测试的灾难恢复计划只是文档。
9. 主动监控卷运行状况。针对降级和故障卷、节点存储容量、备份期限和副本重建状态设置 Prometheus 警报。当用户报告数据库速度缓慢时,存储问题已经持续了几个小时。
10. 使用专用存储磁盘。将 Longhorn 数据与操作系统磁盘分开。这可以防止 I/O 争用,为您提供更清晰的容量管理,并避免使用 Longhorn 数据填充操作系统磁盘的风险。
特定于云的部署指南
AWS — 具有 NVMe 实例存储的 EC2
对于 AWS 部署,请使用附带 NVMe 实例存储的i3.xlarge或i3en.xlarge实例。这些以预配置 EBS IOPS 成本的一小部分提供原始 NVMe 性能。格式化实例存储并将其配置为 Longhorn 磁盘。
# On each EC2 i3.xlarge instance
sudo mkfs.ext4 /dev/nvme0n1
sudo mkdir -p /mnt/longhorn-nvme
sudo mount /dev/nvme0n1 /mnt/longhorn-nvme
echo '/dev/nvme0n1 /mnt/longhorn-nvme ext4 defaults,nofail 0 2' | sudo tee -a /etc/fstab
# Configure as Longhorn disk (via node CRD or UI)
# Path: /mnt/longhorn-nvme/Azure — 具有超级磁盘
的虚拟机在 Azure 上,使用具有本地 NVMe 存储的Standard_L8s_v3或Standard_L16s_v3VM。或者,连接超级磁盘以获得一致的亚毫秒级延迟。超级磁盘允许您独立配置 IOPS 和吞吐量。
# Attach Ultra Disk to Azure VM (Azure CLI)
az vm disk attach \
--vm-name k3s-worker-01 \
--resource-group k3s-cluster \
--name longhorn-ultra-01 \
--size-gb 512 \
--sku UltraSSD_LRS \
--disk-iops-read-write 10000 \
--disk-mbps-read-write 300 \
--newGCP — 具有本地 SSD
的虚拟机GCP 提供连接到n2-standard或c3-standardVM 的本地 SSD。本地 SSD 每盘提供 375 GB 容量,读取 IOPS 高达 680,000。连接多个本地 SSD 并对它们进行 RAID 以获得更大的卷。
# Create VM with local SSDs (gcloud)
gcloud compute instances create k3s-worker-01 \
--machine-type=n2-standard-8 \
--local-ssd=interface=NVME \
--local-ssd=interface=NVME \
--zone=europe-west1-b
# RAID two local SSDs for 750GB Longhorn disk
sudo mdadm --create /dev/md0 --level=0 --raid-devices=2 /dev/nvme0n1 /dev/nvme0n2
sudo mkfs.ext4 /dev/md0
sudo mkdir -p /mnt/longhorn-nvme
sudo mount /dev/md0 /mnt/longhorn-nvme本地数据中心
对于本地部署,请使用配备 Longhorn 专用 NVMe 或 SAS SSD 驱动器的服务器。将操作系统磁盘与存储磁盘分开。 在节点之间使用 10GbE 或 25GbE 网络可确保复制流量不会成为瓶颈 — Longhorn 同步复制生成的网络流量与写入吞吐量乘以副本数量成正比。
# Typical on-premises server spec for Longhorn k3s node
# CPU: 8+ cores (Xeon or EPYC)
# RAM: 32+ GB
# OS Disk: 256GB SATA SSD (mirrored)
# Longhorn Disk: 2x 1TB NVMe (RAID-1 or individual Longhorn disks)
# Network: 2x 25GbE (bonded, one for application, one for storage)
# Configure dedicated storage network (optional but recommended)
# In Longhorn settings:
# storage-network: kube-system/storage-network-attachmentLonghorn UI 演练
Longhorn 附带内置 Web UI,提供用于管理卷、快照、备份、节点和设置的可视化界面。通过安装期间配置的 Ingress 或通过 kubectl port-forward 访问它。
# Quick access via port-forward
kubectl -n longhorn-system port-forward svc/longhorn-frontend 8080:80
# Open http://localhost:8080 in your browserUI 提供了多个关键视图:仪表板显示集群范围的存储运行状况,包括总容量、已用空间和卷状态。卷列出所有卷及其状态(正常/降级/故障)、大小、副本计数和连接的节点。您可以直接从此视图扩展、快照、备份和还原卷。节点显示每个节点的存储配置、磁盘分配和调度状态。备份列出备份目标中存储的所有备份及其卷、大小和创建时间。设置公开所有 Longhorn 配置参数及其说明。
常见问题故障排除
降级卷
当一个或多个副本运行状况不佳但卷仍可运行时,卷将进入降级状态。常见原因包括节点故障、磁盘已满或网络分区。
# Check volume status
kubectl -n longhorn-system get volumes.longhorn.io -o wide
# Describe the volume for detailed status
kubectl -n longhorn-system describe volumes.longhorn.io pvc-abc123
# Check replica status
kubectl -n longhorn-system get replicas.longhorn.io -l longhornvolume=pvc-abc123
# If a replica is stuck in error state, delete it to trigger rebuild
kubectl -n longhorn-system delete replicas.longhorn.io pvc-abc123-r-12345
# Monitor rebuild progress
kubectl -n longhorn-system get volumes.longhorn.io pvc-abc123 \
-o jsonpath='{.status.conditions}' | jq卷卡在连接/拆卸
中# Check engine status
kubectl -n longhorn-system get engines.longhorn.io -l longhornvolume=pvc-abc123
# Check for stuck VolumeAttachment objects
kubectl get volumeattachments | grep pvc-abc123
# Force detach a stuck volume (use cautiously)
kubectl -n longhorn-system patch volumes.longhorn.io pvc-abc123 \
--type merge -p '{"spec":{"nodeID":""}}'
# If attachment is truly stuck, delete the VolumeAttachment
kubectl delete volumeattachment csi-abc123def456空间压力
# Check node storage usage
kubectl -n longhorn-system get nodes.longhorn.io -o wide
# Identify large snapshots consuming space
kubectl -n longhorn-system get snapshots.longhorn.io -l longhornvolume=pvc-abc123
# Purge old snapshots to reclaim space
# Via Longhorn UI: Volume → Snapshots → Delete unneeded snapshots
# Old snapshots consume space because COW data cannot be freed until the snapshot is deleted
# Check for snapshot data integrity issues
kubectl -n longhorn-system get settings.longhorn.io snapshot-data-integrity升级程序
Longhorn 升级应谨慎执行,因为存储系统支撑着所有有状态工作负载。升级前务必备份所有关键卷。
# 1. Back up all volumes before upgrade
for vol in $(kubectl -n longhorn-system get volumes.longhorn.io -o jsonpath='{.items[*].metadata.name}'); do
echo "Backing up $vol"
kubectl -n longhorn-system patch volumes.longhorn.io $vol \
--type merge -p '{"spec":{"lastBackupAt":"'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"}}'
done
# 2. Check current version
kubectl -n longhorn-system get daemonset longhorn-manager -o jsonpath='{.spec.template.spec.containers[0].image}'
# 3. Upgrade via Helm
helm repo update
helm upgrade longhorn longhorn/longhorn \
--namespace longhorn-system \
--version 1.7.2 \
--values longhorn-values.yaml
# 4. Monitor the rolling upgrade
kubectl -n longhorn-system rollout status daemonset/longhorn-manager
kubectl -n longhorn-system rollout status deployment/longhorn-driver-deployer
# 5. Verify all volumes are healthy after upgrade
kubectl -n longhorn-system get volumes.longhorn.io -o custom-columns=NAME:.metadata.name,STATE:.status.state,ROBUSTNESS:.status.robustness
# 6. Longhorn automatically upgrades engines — monitor progress
kubectl -n longhorn-system get engines.longhorn.io -o wide与数据库操作员集成
现代 Kubernetes 数据库运算符(CloudNativePG、Percona Operator、Zalando Postgres Operator)与 Longhorn 无缝协作。 Operator 管理数据库生命周期,而 Longhorn 为底层存储提供复制、快照和备份。
# CloudNativePG cluster using Longhorn storage
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: production-pg
namespace: database
spec:
instances: 3
storage:
size: 100Gi
storageClass: longhorn-db
pvcTemplate:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
walStorage:
size: 20Gi
storageClass: longhorn-fast
postgresql:
parameters:
shared_buffers: "2GB"
effective_cache_size: "6GB"
maintenance_work_mem: "512MB"
wal_buffers: "64MB"
max_connections: "200"
backup:
barmanObjectStore:
destinationPath: s3://pg-backups/cnpg/
endpointURL: https://s3.eu-west-1.amazonaws.com
s3Credentials:
accessKeyId:
name: aws-creds
key: ACCESS_KEY_ID
secretAccessKey:
name: aws-creds
key: SECRET_ACCESS_KEY
wal:
compression: gzip
retentionPolicy: "30d"
resources:
requests:
cpu: "2"
memory: 4Gi
limits:
cpu: "4"
memory: 8Gi# Percona XtraDB Cluster with Longhorn storage
apiVersion: pxc.percona.com/v1
kind: PerconaXtraDBCluster
metadata:
name: production-mysql
namespace: database
spec:
crVersion: "1.14.0"
pxc:
size: 3
image: percona/percona-xtradb-cluster:8.0
resources:
requests:
cpu: "2"
memory: 4Gi
volumeSpec:
persistentVolumeClaim:
storageClassName: longhorn-db
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 200Gi
backup:
image: percona/percona-xtradb-cluster-operator:1.14.0-pxc8.0-backup-pxb8.0.35
storages:
s3-backup:
type: s3
s3:
bucket: mysql-backups
region: eu-west-1
credentialsSecret: aws-creds
schedule:
- name: daily-full
schedule: "0 2 * * *"
keep: 14
storageName: s3-backup结论
Longhorn 将 k3s 从仅适用于边缘和开发的轻量级 Kubernetes 发行版转变为能够运行任务关键型有状态工作负载的生产就绪平台。其架构 — 每卷引擎、同步多节点复制、集成快照和备份到云对象存储、灾难恢复卷、卷加密和在线 PVC 扩展 — 提供企业级存储,但没有企业级复杂性。
Longhorn 在生产中取得成功的关键有三个。首先,从一开始就正确配置:使用专用存储磁盘,设置适当的复制因子和数据局部性,并为不同的工作负载类型创建专用的存储类。其次,从第一天起就将备份集成到您的架构中:用于快速回滚的定期快照、用于灾难恢复的每日备份到 S3/GCS/Azure 以及用于最坏情况的备用集群中的 DR 卷。第三,监控一切:卷健康状况、节点存储容量、备份期限和副本重建状态——存储问题在变得灾难性之前是不可见的。
动态 PVC 扩展消除了最常见的生产事故来源之一——磁盘空间不足。借助 Longhorn,只需一条 kubectl 命令即可将数据库卷从 50Gi 扩展到 500Gi,且停机时间为零。 结合容量阈值的 Prometheus 警报,您可以在卷变得关键之前主动扩展卷,或者完全自动化扩展。
无论您是在 k3s 上运行 PostgreSQL、MySQL、MongoDB 还是 Redis(在裸机服务器、AWS EC2、Azure 虚拟机、GCP 实例还是本地数据中心硬件上),Longhorn 都能提供存储基础,让您能够专注于应用程序,而不必担心数据持久性。安装它、配置它、监控它,并用您的生产数据信任它。