writing-skills
writing-skills
Use when creating new skills, editing existing skills, or verifying skills work before deployment
longhornUse this skill when deploying and managing Longhorn distributed storage on Kubernetes -- installation, volume management, backup, disaster recovery, performance tuning, monitoring. This skill enforces: minimum 3 nodes for production, replica count 3 for all production volumes, S3-compatible backup target, monitoring alerts for volume degraded and disk space…
Independent GitHub snapshot · Automated classification · Original documentation governs
Define and enforce Longhorn distributed storage patterns for installation, volume management, backup, and DR.
User request includes: longhorn, distributed storage, block storage, rancher longhorn, persistent volume, storageclass, backup target, disaster recovery, volume snapshot, longhorn replication.
A markdown document containing:
Produce the artifact directly. No preamble, no postamble, no explanations. No filler, no hedging, no transitions. Strip articles a/an/the where unambiguous. Compress output -- why use many token when few do trick.
4096 tokens
helm repo add longhorn https://charts.longhorn.io
helm repo update
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace \
--set defaultSettings.replicaCount=3 \
--set defaultSettings.defaultDataPath="/var/lib/longhorn" \
--set persistence.defaultClassReplicaCount=3 \
--version 1.6.0
Pre-requisites:
| Requirement | Minimum | Recommended |
|---|---|---|
| Kubernetes | 1.21+ | 1.28+ |
| Nodes | 3 (for HA) | 3+ |
| CPU per node | 1 core | 4 cores |
| RAM per node | 2 GB | 8 GB |
| Disk per node | 40 GB (SSD) | 200 GB (NVMe) |
| Open ports | 9500-9504 (instance manager) | Same |
| iscsiadm | Required | -- |
| open-iscsi | Required | -- |
| nfs-client | Required (for backup) | -- |
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-fast
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "30"
fromBackup: ""
fsType: ext4
dataLocality: best-effort
replicaAutoBalance: best-effort
diskSelector: ""
nodeSelector: ""
recurringJobSelector: ""
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-slow
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
parameters:
numberOfReplicas: "1"
dataLocality: disabled
replicaAutoBalance: disabled
| Replicas | Fault Tolerance | Storage Cost | Use Case |
|---|---|---|---|
| 1 | No tolerance | 1x | Dev/test, non-critical |
| 2 | 1 node failure | 2x | Semi-critical (not recommended) |
| 3 | 1 node failure | 3x | Production (default) |
| 4+ | 2+ node failures | 4x+ | Critical, multi-AZ |
Backup Target Setup
# Settings -> Backup
backupTarget: "s3://my-backup-bucket@us-east-1/"
backupTargetCredentialSecret: longhorn-backup-secret
# Secret for S3 backup target
apiVersion: v1
kind: Secret
metadata:
name: longhorn-backup-secret
namespace: longhorn-system
stringData:
AWS_ACCESS_KEY_ID: "AKIA..."
AWS_SECRET_ACCESS_KEY: "..."
AWS_ENDPOINTS: "https://s3.us-east-1.amazonaws.com"
Recurring Job
# Recurring backup schedule
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: daily-backup
namespace: longhorn-system
spec:
cron: "0 2 * * *"
task: backup
retain: 7
concurrency: 2
labels:
backup-type: daily
DR Volume
apiVersion: longhorn.io/v1beta2
kind: Volume
metadata:
name: dr-volume-orders
namespace: longhorn-system
spec:
fromBackup: "s3://backup-bucket@us-east-1/backup/orders-v1"
numberOfReplicas: 3
staleReplicaTimeout: 30
nodeSelector:
region: dr-region
DR Process:
| Parameter | Setting | Rationale |
|---|---|---|
| Disk type | NVMe > SSD > HDD | IOPS critical for storage performance |
| Replica count | 3 (balance) | More replicas = more IO overhead |
| Data locality | best-effort | Prefer local replica for read performance |
| Enable SFTP | false | Disable if not needed |
| Guaranteed engine CPU | 0.25 | Reserved CPU for engine |
| Storage network | 10GbE+ separate | Storage traffic isolation |
| Replica rebalance | immediate | Rebalance when new node added |
Prometheus Metrics
# ServiceMonitor for Longhorn
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: longhorn
namespace: longhorn-system
spec:
selector:
matchLabels:
app: longhorn-manager
endpoints:
- port: manager
path: /metrics
Key Metrics
| Metric | Alert Threshold | Description |
|---|---|---|
longhorn_volume_state | != healthy | Volume degraded/faulted |
longhorn_disk_storage_available_bytes | < 10% | Disk space low |
longhorn_node_status | != true | Node offline |
longhorn_volume_robustness | != healthy | Volume degraded |
longhorn_backup_state | != Completed | Backup failed |
# 1. Check current version
helm list -n longhorn-system
# 2. Update repo
helm repo update longhorn
# 3. Upgrade (minor version)
helm upgrade longhorn longhorn/longhorn \
--namespace longhorn-system \
--reuse-values \
--version 1.6.1
# 4. Verify
kubectl -n longhorn-system get pods -w
Rules: Always upgrade one minor version at a time. Check release notes for breaking changes. Test upgrade on non-production first.
| Topology | Pros | Cons | Use Case |
|---|---|---|---|
| Collocated (same node as workload) | Low latency, simpler | Single point of failure for replicas on same node | Dev/test, non-critical |
| Dedicated storage nodes | Performance isolation, predictable | Extra infrastructure cost | High-performance workloads |
| All nodes with storage | Flexible, high aggregate IOPS | Resource contention | General production |
| Separate storage network | Storage traffic isolated from app | Complex networking | High-throughput, multi-TB |
| Target | Pros | Cons | Use Case |
|---|---|---|---|
| S3-compatible (AWS, MinIO, Ceph) | Durable, scalable, standard | Egress costs, network dependency | Default |
| NFS | Simple, low overhead | Single point of failure, limited scalability | Small deployments |
| SMB | Windows compatibility | Performance overhead | Windows workloads |
| Internal (Longhorn volumes) | Simple setup | Not off-cluster, not DR | Backup to backup (not recommended) |
| Model | RPO | RTO | Complexity | Cost |
|---|---|---|---|---|
| S3 backup + restore | 24h (daily backup) | 1-4h | Low | Low (S3 storage only) |
| DR volume (continuous) | Minutes | 15-30min | Medium | Medium (DR cluster idle) |
| Active-active (stretch cluster) | Near-zero | < 1min | High | High (synchronous replication) |
Longhorn requires 3 nodes for replica quorum. With 2 nodes and 3 replicas, one node failure loses quorum (need 2/3 replicas, only 1 node left). With 2 replicas on 2 nodes, a single node failure loses all replicas. Minimum 3 nodes for any production use.
Without backup target, all data is local to the cluster. A cluster failure loses all data. Always configure S3-compatible backup target. Test restore procedure. Without backup, Longhorn provides no data durability.
Host volumes are simple bind mounts -- no replication, no snapshots, no backup integration. Always use CSI volumes for stateful workloads. Host volumes only for temporary or non-critical data.
Storage sync traffic is latency-sensitive. Longhorn replica sync requires <1ms latency between nodes. Deploy nodes within same availability zone. Cross-AZ latency (1-2ms) may cause replica out-of-sync issues. Use placement groups for low latency.
Longhorn allocates disk space for replicas. Running out of disk causes volume to become read-only. Set up monitoring alerts for disk usage at 70%, 85%, 95%. Configure storageMinAllocatedPercentage to reserve capacity.
Always upgrade engine image before instance manager image. Check engine compatibility. In-place upgrade: engine upgrade is live, but tests should verify. Rolling back engine requires specific steps.
More replicas = more storage overhead + more sync I/O. 3 replicas = 3x storage cost. For 1TB volume, 3 replicas need 3TB storage. Plan storage capacity including replica overhead. Use thin provisioning carefully.
allowVolumeExpansion: truereplicaAutoBalance: best-effort for even distributiondataLocality: best-effort for read performancestaleReplicaTimeout: 30 for cleanupfsType: ext4 for general workloads, xfs for large filessnapshot recurring jobs alongside backups| Aspect | Longhorn | Rook/Ceph |
|---|---|---|
| Setup complexity | Low (Helm install) | High (multiple operators) |
| Performance | Good for general workloads | Excellent (distributed) |
| Features | Volume, backup, DR, snapshots | Block, file, object, RBD, RGW |
| Resource usage | Lower (per-volume engines) | Higher (OSD daemons) |
| Operations | Simple (single binary) | Complex (Ceph admin) |
| Community | Moderate | Large |
OpenEBS offers Mayastor (NVMe-oF), Jiva, and cStor engines. Longhorn is simpler to operate (single engine type). OpenEBS Mayastor is faster for NVMe workloads. Longhorn has better built-in backup and DR features. Choose Longhorn for simplicity, OpenEBS Mayastor for performance.
Cloud storage: higher cost per GB, no replica management, built-in HA (AWS handles replication). Longhorn: lower cost (use local disks), cross-cloud portability, snapshots and backup to S3. Longhorn best for on-premises, edge, or multi-cloud. Cloud storage best for single-cloud with deep AWS/Azure/GCP integration.
replicaAutoBalance: immediate to distribute replicaskubectl cordon <old-node>fromBackup field in Volume specstorageMinAllocatedPercentage to reserve spaceHand off to devops/monitoring/SKILL.md for monitoring integration. Hand off to devops/helm-patterns/SKILL.md for Helm deployment best practices.
| Decision | Longhorn | Rook/Ceph | Portworx | OpenEBS |
|---|---|---|---|---|
| Complexity | Low (Helm install) | High (multiple operators) | Medium | Low to medium |
| Performance | Good (NVMe-backed) | Great (Ceph tuned) | Excellent | Varies by engine |
| Replication | 1-3 replicas, sync/async | 1-3 replicas, sync | 1-3 replicas, sync | 1-3 replicas, async |
| Built-in backup | Yes (S3, NFS) | Yes (RGW, OSD) | Yes (PX-Backup) | Via Velero |
| License | Open Source (Apache 2.0) | Open Source (Apache 2.0) | Commercial | Open Source (Apache 2.0) |
| Best for | Edge, small-medium K8s | Enterprise, large clusters | Enterprise, compliance | Simple attached storage |
| Replicas | Durability | Storage cost | Write performance |
|---|---|---|---|
| 1 | Low (single disk failure) | 1x | Fastest |
| 2 | Medium (one replica failure) | 2x | Moderate |
| 3 | High (two replica tolerance) | 3x | Slowest |
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-encrypted
provisioner: driver.longhorn.io
allowVolumeExpansion: true
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "2880"
fromBackup: ""
fsType: ext4
encrypted: "true"
unboundMountMode: "global"
backingImage: ""
backingImageURL: ""
diskSelector: "ssd"
nodeSelector: "storage-optimized"
recurringJobSelector: |
[
{"name": "snapshot-daily"},
{"name": "backup-weekly"},
{"name": "filesystem-trim"}
]
reclaimPolicy: Delete
#!/usr/bin/env bash
set -euo pipefail
create_longhorn_backup() {
local volume=$1
local backup_target=${2:-"s3://backups/longhorn"}
kubectl -n longhorn-system create job \
"manual-backup-$(date +%s)" \
--image=longhornio/longhorn-engine:v1.7.0 \
--command -- \
longhorn backup create \
--backup-target "$backup_target" \
--volume "$volume"
}
restore_from_backup() {
local backup_url=$1
local pvc_name=$2
kubectl apply -f - <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: $pvc_name-restored
spec:
storageClassName: longhorn
dataSource:
name: $backup_url
kind: VolumeBackup
apiGroup: longhorn.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
EOF
}
monitor_longhorn_health() {
while true; do
for node in $(kubectl get nodes -o name); do
HEALTH=$(curl -sf "http://${node}:9500/v1/health" || echo "DOWN")
echo "$(date): $node → $HEALTH"
done
sleep 60
done
}
replica-auto-balance: best-effort to automatically redistribute replicas when nodes join/leavereclaimPolicy: Retain for critical datadisableRevisionCounter: true on volumes to reduce write amplification from metadata updates` interface EventObserver { onEvent(event: T): Promise; }
class EventBus { private observers: Set<EventObserver> = new Set(); subscribe(observer: EventObserver): void { this.observers.add(observer); } unsubscribe(observer: EventObserver): void { this.observers.delete(observer); } async emit(event: T): Promise { const results = Array.from(this.observers).map(o => o.onEvent(event)); await Promise.allSettled(results); } } `
config: defaults: timeout: 30s retryCount: 3 overrides: production: timeout: 60s retryCount: 5 development: timeout: 300s retryCount: 1
| Metric | Threshold | Severity | Action |
|---|---|---|---|
| Error rate | > 1% over 5min | Critical | Page on-call |
| p99 latency | > 2s over 5min | Warning | Investigate |
| Throughput drop | > 50% over 1min | Critical | Check upstream |
| Queue depth | > 1000 over 1min | Warning | Scale consumers |
| Disk usage | > 85% | Warning | Clean or expand |
| Memory usage | > 90% heap | Critical | Restart or scale |
| Anti-Pattern | Symptom | Root Cause | Solution |
|---|---|---|---|
| Premature optimization | Complex code for no measured benefit | Guessing instead of profiling | Measure first, optimize based on data |
| Copy-paste reuse | Duplicate code across codebase | Lack of abstraction | Extract shared logic into libraries |
| Gold-plating | Features with no current requirement | Over-engineering | YAGNI — build what's needed now |
| Magical thinking | Assumptions without validation | Skipping error handling | Handle all failure modes explicitly |
Cache hierarchy: L1 (in-memory local) → L2 (distributed Redis/Memcached) → L3 (CDN/Edge). Cache invalidation: TTL-based (simple, stale), event-based (complex, fresh), write-through (consistent, higher write latency), write-behind (fast writes, eventual consistency).