> ## Documentation Index
> Fetch the complete documentation index at: https://www.latitude.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Setting up persistent storage for Kubernetes with Longhorn

> Configure storage to retain application data on your K8s cluster

[Longhorn](https://longhorn.io/docs/1.7.2/what-is-longhorn/) is a free, open-source distributed block storage system for Kubernetes that keeps things lightweight while handling replication and persistence for your workloads.​​​​​​​​​​​​​​​​ If you've got a K8s cluster deployed on Latitude.sh and need reliable container storage, this guide will get you there.

## Prerequisites

* A [Kubernetes cluster](/guides/kubernetes-on-bare-metal) with at least 3 nodes
* [kubectl CLI](https://kubernetes.io/docs/tasks/tools/) installed on your local workstation
* [Helm](https://helm.sh/docs/intro/install/) installed (for installing Longhorn)

## Step 1: Prepare your cluster

<Steps>
  <Step title="Check available disks">
    Run `lsblk` on each node to find available disks and partitions to dedicate to Longhorn.
  </Step>

  <Step title="Label nodes (Optional)">
    Label your nodes to control which ones will be used for Longhorn storage:

    ```shell theme={null}
    kubectl label nodes <node-name> longhorn=true
    ```
  </Step>
</Steps>

## Step 2: Install Longhorn

Longhorn can be installed on a K8s cluster in [several ways](https://longhorn.io/docs/1.7.2/deploy/install/). In this guide, we'll go with [Helm](https://longhorn.io/docs/1.7.2/deploy/install/install-with-helm/).

<Steps>
  <Step title="Add Longhorn repository">
    Add the Longhorn Helm repository:

    ```shell theme={null}
    helm repo add longhorn https://charts.longhorn.io
    helm repo update
    ```
  </Step>

  <Step title="Install Longhorn">
    Run this command to install Longhorn:

    ```shell theme={null}
    helm install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace
    ```
  </Step>

  <Step title="Verify installation">
    Verify the installation:

    ```shell theme={null}
    kubectl -n longhorn-system get pod
    ```

    All pods should be running without errors.
  </Step>
</Steps>

## Step 3: Access the Longhorn UI

<Steps>
  <Step title="Check services">
    Run this command to check if the Longhorn services are up:

    ```shell theme={null}
    kubectl -n longhorn-system get svc
    ```

    The output should be something like this:

    <img src="https://mintcdn.com/latitudesh/ELzsuRnxGwFWx5KO/images/product/longhorn-frontend-ip.png?fit=max&auto=format&n=ELzsuRnxGwFWx5KO&q=85&s=cb8dad123a59d867633fd6dab2a9524f" alt="Longhorn frontend service" width="787" height="94" data-path="images/product/longhorn-frontend-ip.png" />
  </Step>

  <Step title="Set up port forwarding">
    Set up port forwarding to the frontend service:

    ```shell theme={null}
    kubectl port-forward services/longhorn-frontend 8080:http -n longhorn-system
    ```
  </Step>

  <Step title="Access dashboard">
    Navigate to `http://localhost:8080` in your browser to access the Longhorn UI. You'll be taken to this dashboard:

    <img src="https://mintcdn.com/latitudesh/ELzsuRnxGwFWx5KO/images/product/longhorn-ui.png?fit=max&auto=format&n=ELzsuRnxGwFWx5KO&q=85&s=6130d8af630e0952b06f31ecf892c739" alt="Longhorn dashboard UI" width="3534" height="1998" data-path="images/product/longhorn-ui.png" />
  </Step>
</Steps>

## Step 4: Configure storage

<Steps>
  <Step title="Check nodes">
    In the Longhorn UI, navigate to **Node** and check if your disks are detected automatically.

    <img src="https://mintcdn.com/latitudesh/ELzsuRnxGwFWx5KO/images/product/longhorn-node-page.png?fit=max&auto=format&n=ELzsuRnxGwFWx5KO&q=85&s=017846af23a15e98c715db958c32f45a" alt="Longhorn node page" width="2206" height="533" data-path="images/product/longhorn-node-page.png" />
  </Step>

  <Step title="Define disk usage limits">
    Define disk usage limits and scheduling. Make sure your nodes have enough space to handle the intended workload.
  </Step>
</Steps>

## Step 5: Create a StorageClass

<Steps>
  <Step title="Create StorageClass manifest">
    Create a StorageClass manifest named `longhorn-storageclass.yaml`:

    ```yaml theme={null}
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: longhorn
    provisioner: driver.longhorn.io
    allowVolumeExpansion: true
    reclaimPolicy: Delete
    volumeBindingMode: Immediate
    ```
  </Step>

  <Step title="Apply StorageClass">
    Apply the StorageClass:

    ```shell theme={null}
    kubectl apply -f longhorn-storageclass.yaml
    ```
  </Step>

  <Step title="Set as default (Optional)">
    Set the StorageClass as default:

    ```shell theme={null}
    kubectl patch storageclass longhorn -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
    ```
  </Step>
</Steps>

## Step 6: Create a PersistentVolumeClaim (PVC)

<Steps>
  <Step title="Create PVC manifest">
    Create a PersistentVolumeClaim YAML file named `longhorn-pvc.yaml`:

    ```yaml theme={null}
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: longhorn-pvc
    spec:
      accessModes:
        - ReadWriteOnce
      storageClassName: longhorn
      resources:
        requests:
          storage: 5Gi
    ```
  </Step>

  <Step title="Apply PVC">
    Apply the PVC:

    ```shell theme={null}
    kubectl apply -f longhorn-pvc.yaml
    ```
  </Step>

  <Step title="Verify PVC">
    Verify the PVC:

    ```shell theme={null}
    kubectl get pvc
    ```

    Make sure the status shows **Bound** to confirm it worked.
  </Step>
</Steps>

## Step 7: Use the PVC in a Pod

<Steps>
  <Step title="Create Pod manifest">
    Create a Pod that Uses the PVC, save this as `longhorn-pod.yaml`:

    ```yaml theme={null}
    apiVersion: v1
    kind: Pod
    metadata:
      name: longhorn-test-pod
    spec:
      containers:
        - name: longhorn-test
          image: nginx
          volumeMounts:
            - mountPath: "/usr/share/nginx/html"
              name: longhorn-storage
      volumes:
        - name: longhorn-storage
          persistentVolumeClaim:
            claimName: longhorn-pvc
    ```
  </Step>

  <Step title="Deploy Pod">
    Deploy the Pod:

    ```shell theme={null}
    kubectl apply -f longhorn-pod.yaml
    ```
  </Step>

  <Step title="Check Pod status">
    Check Pod status:

    ```shell theme={null}
    kubectl get pods
    ```

    The Pod should be running without issues. You can check if the data persists by inspecting the mounted directory.
  </Step>
</Steps>

## Troubleshooting

* If Longhorn nodes show as unschedulable, check disk space and ensure no taints are blocking pods.
* For performance tuning, you can adjust the number of replicas for each volume in the Longhorn UI under **Settings > Default Settings**.
* If using firewalls, ensure ports 9500-9600 are open for communication between Longhorn components.

## That's it!

You've got Longhorn running and ready to handle your persistent storage needs.
