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

# PVs

> Manage Kubernetes PVs as cluster-wide storage resources for persistent data

Persistent Volumes (PVs) are cluster-wide storage resources provisioned by administrators or dynamically by StorageClasses. They represent actual storage in the cluster that can be claimed by PVCs.

## Key Concepts

<CardGroup cols={2}>
  <Card title="PV" icon="database">
    A cluster-scoped storage resource that exists independently of any pod lifecycle.
  </Card>

  <Card title="Reclaim Policy" icon="recycle">
    Defines what happens to the PV when its PVC is deleted (Retain, Delete, Recycle).
  </Card>

  <Card title="Volume Source" icon="hard-drive">
    The underlying storage backend (NFS, CSI, Local, Cloud disks, etc.).
  </Card>

  <Card title="Claim Reference" icon="link">
    Reference to the PVC that has bound this volume.
  </Card>
</CardGroup>

<Info>
  PersistentVolumes are **cluster-scoped** resources. They are not bound to any namespace and can be claimed by PVCs from any namespace.
</Info>

## Required Permissions

| Action    | Permission                                     |
| --------- | ---------------------------------------------- |
| View PVs  | `iam:project:infrastructure:kubernetes:read`   |
| Create PV | `iam:project:infrastructure:kubernetes:write`  |
| Edit PV   | `iam:project:infrastructure:kubernetes:write`  |
| Delete PV | `iam:project:infrastructure:kubernetes:delete` |

## PV Status Values

| Status        | Description                                           |
| ------------- | ----------------------------------------------------- |
| **Available** | PV is free and not yet bound to a PVC                 |
| **Bound**     | PV is bound to a PVC                                  |
| **Released**  | PVC was deleted but the resource is not yet reclaimed |
| **Failed**    | Automatic reclamation of the volume failed            |
| **Pending**   | PV is being provisioned                               |

<Warning>
  A "Released" PV cannot be rebound to a new PVC automatically. The data must be manually handled based on the reclaim policy before the PV can be reused.
</Warning>

## Reclaim Policies

| Policy      | Description                                                                                  |
| ----------- | -------------------------------------------------------------------------------------------- |
| **Retain**  | PV is kept after PVC deletion for manual data recovery (default for manually created PVs)    |
| **Delete**  | PV and underlying storage are deleted when PVC is deleted (default for dynamic provisioning) |
| **Recycle** | Basic scrub (`rm -rf /volume/*`) before making available again (deprecated)                  |

<Tip>
  Use **Retain** for production data that needs to be recoverable. Use **Delete** for ephemeral or easily reproducible data.
</Tip>

## How to View PVs

<Steps>
  <Step title="Select Cluster">
    Choose a cluster from the cluster dropdown.
  </Step>

  <Step title="View List">
    The list shows all PersistentVolumes in the cluster (cluster-scoped, no namespace filter).
  </Step>

  <Step title="Filter and Search">
    Use the search box to find PVs by name, status, storage class, or volume source type. Filter by status (Available, Bound, Released, Failed).
  </Step>
</Steps>

## How to View PV Details

<Steps>
  <Step title="Find the PV">
    Locate the PV in the list.
  </Step>

  <Step title="Click PV Name">
    Click on the PV name to open the detail drawer.
  </Step>

  <Step title="Review Details">
    View PV information including:

    * **Overview**: Name, status, storage class, reclaim policy, age
    * **Capacity**: Storage size and volume mode
    * **Access Modes**: How the volume can be accessed
    * **Volume Source**: Backend storage details (NFS path, CSI driver, etc.)
    * **Claim**: Reference to bound PVC (if any)
    * **Node Affinity**: Node constraints for local volumes
    * **Labels & Annotations**: Metadata attached to the PV
    * **Events**: Recent Kubernetes events
  </Step>
</Steps>

## How to Create a PV

<Steps>
  <Step title="Click Create PV">
    Click the **Create PV** button in the page header.
  </Step>

  <Step title="Write YAML">
    Enter the PV manifest in YAML format. Key fields:

    * `spec.capacity.storage` - Storage capacity
    * `spec.accessModes` - How the volume can be accessed
    * `spec.persistentVolumeReclaimPolicy` - What happens when released
    * `spec.storageClassName` - Storage class for dynamic binding
    * Volume source (e.g., `spec.nfs`, `spec.csi`, `spec.local`)
  </Step>

  <Step title="Create">
    Click **Create** to apply the manifest.
  </Step>
</Steps>

## How to Edit a PV

<Steps>
  <Step title="Open Actions Menu">
    Click the actions menu (three dots) on the PV row.
  </Step>

  <Step title="Click Edit YAML">
    Select **Edit YAML** to open the YAML editor.
  </Step>

  <Step title="Modify Spec">
    Edit the PV specification. Note that most fields are immutable after creation.
  </Step>

  <Step title="Save">
    Click **Update** to apply changes.
  </Step>
</Steps>

<Warning>
  Most PV fields are immutable after creation, including capacity, access modes, and volume source. You can modify reclaim policy, labels, and annotations.
</Warning>

## How to Delete a PV

<Steps>
  <Step title="Open Actions Menu">
    Click the actions menu on the PV row.
  </Step>

  <Step title="Click Delete">
    Select **Delete** from the menu.
  </Step>

  <Step title="Confirm">
    Confirm the deletion. This removes the PV from the cluster.
  </Step>
</Steps>

<Warning>
  Deleting a PV that is bound to a PVC will fail. Delete or unbind the PVC first. Deleting a PV does NOT necessarily delete the underlying storage (depends on the storage backend).
</Warning>

## Volume Source Types

PVs support various storage backends:

| Type                     | Description                                               |
| ------------------------ | --------------------------------------------------------- |
| **CSI**                  | Container Storage Interface drivers (modern, recommended) |
| **NFS**                  | Network File System shares                                |
| **Local**                | Local node storage with node affinity                     |
| **HostPath**             | Directory on the node (testing only)                      |
| **iSCSI**                | iSCSI block storage                                       |
| **FC**                   | Fibre Channel storage                                     |
| **RBD**                  | Ceph RADOS Block Device                                   |
| **CephFS**               | Ceph Filesystem                                           |
| **GlusterFS**            | GlusterFS network filesystem                              |
| **AWSElasticBlockStore** | AWS EBS volumes                                           |
| **GCEPersistentDisk**    | Google Cloud persistent disks                             |
| **AzureDisk**            | Azure managed disks                                       |
| **AzureFile**            | Azure File shares                                         |

## Example PVs

### NFS Volume

```yaml theme={null}
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    server: nfs-server.example.com
    path: /exports/data
```

### Local Volume

```yaml theme={null}
apiVersion: v1
kind: PersistentVolume
metadata:
  name: local-pv
spec:
  capacity:
    storage: 500Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: local-storage
  local:
    path: /mnt/disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - worker-node-1
```

### CSI Volume

```yaml theme={null}
apiVersion: v1
kind: PersistentVolume
metadata:
  name: csi-pv
spec:
  capacity:
    storage: 50Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: csi-standard
  csi:
    driver: ebs.csi.aws.com
    volumeHandle: vol-0123456789abcdef0
    fsType: ext4
```

## Volume Modes

| Mode           | Description                                |
| -------------- | ------------------------------------------ |
| **Filesystem** | Volume is mounted as a directory (default) |
| **Block**      | Volume is presented as a raw block device  |

## Access Modes

| Mode                 | Abbreviation | Description                          |
| -------------------- | ------------ | ------------------------------------ |
| **ReadWriteOnce**    | RWO          | Mounted read-write by a single node  |
| **ReadOnlyMany**     | ROX          | Mounted read-only by multiple nodes  |
| **ReadWriteMany**    | RWX          | Mounted read-write by multiple nodes |
| **ReadWriteOncePod** | RWOP         | Mounted read-write by a single pod   |

## Troubleshooting

<AccordionGroup>
  <Accordion title="PV stuck in Released status">
    * The PVC was deleted but reclaim policy is Retain
    * Manually delete the `spec.claimRef` to make it Available again
    * Or delete and recreate the PV after backing up data
    * Consider changing reclaim policy for future PVs
  </Accordion>

  <Accordion title="PV shows Failed status">
    * Automatic reclamation failed (usually with Recycle policy)
    * Check events for error details
    * Manually handle the volume and recreate if needed
    * Recycle policy is deprecated; use Delete or Retain instead
  </Accordion>

  <Accordion title="PVC cannot bind to PV">
    * Check access modes match between PVC and PV
    * Verify capacity: PV capacity must be >= PVC request
    * Ensure storage class matches (or both are empty for no class)
    * Check if PV is already bound to another PVC
    * For local volumes, verify node affinity allows scheduling
  </Accordion>

  <Accordion title="Cannot delete PV">
    * PV may still be bound to a PVC
    * Delete the PVC first, then delete the PV
    * Check for finalizers blocking deletion
    * Verify you have delete permissions
  </Accordion>

  <Accordion title="Local PV not accessible">
    * Verify the path exists on the specified node
    * Check node affinity configuration
    * Ensure pod is scheduled to the correct node
    * Verify directory permissions on the node
  </Accordion>

  <Accordion title="NFS PV mount issues">
    * Verify NFS server is accessible from cluster nodes
    * Check NFS export permissions
    * Ensure NFS client packages are installed on nodes
    * Verify firewall allows NFS traffic
  </Accordion>
</AccordionGroup>

## FAQ

<AccordionGroup>
  <Accordion title="What is the difference between PV and PVC?">
    **PV (Persistent Volume)** is the actual storage resource provisioned by an admin or dynamically. **PVC (Persistent Volume Claim)** is a request for storage by a user. PVCs bind to PVs to use the storage.
  </Accordion>

  <Accordion title="When should I create PVs manually?">
    Create PVs manually when:

    * Using storage that doesn't support dynamic provisioning
    * Pre-provisioning storage for specific workloads
    * Using local storage with node affinity
    * Migrating from existing storage systems

    Use dynamic provisioning (StorageClass) for cloud environments and CSI drivers.
  </Accordion>

  <Accordion title="Can I resize a PV?">
    Not directly. PV capacity is immutable after creation. To resize:

    1. Back up your data
    2. Create a new larger PV
    3. Migrate data to the new volume
    4. Update workloads to use the new PVC
  </Accordion>

  <Accordion title="What happens when I delete a PVC with Retain policy?">
    The PV enters "Released" state and keeps its data. It cannot be automatically bound to a new PVC. You must manually clear the claimRef or delete/recreate the PV to reuse it.
  </Accordion>

  <Accordion title="Can multiple PVCs use the same PV?">
    No. A PV can only be bound to one PVC at a time. For shared storage, use a volume type that supports ReadWriteMany (like NFS) and create separate PVs or use a CSI driver with volume sharing capabilities.
  </Accordion>

  <Accordion title="Why use CSI over in-tree volume plugins?">
    CSI (Container Storage Interface) is the modern standard:

    * Maintained by storage vendors, not Kubernetes core
    * Features don't require Kubernetes upgrades
    * Supports snapshots, cloning, and expansion
    * In-tree plugins (awsElasticBlockStore, gcePersistentDisk) are deprecated
  </Accordion>

  <Accordion title="How do local volumes differ from hostPath?">
    **Local volumes** are for production use with:

    * Node affinity (binds to specific node)
    * Proper lifecycle management
    * Support for dynamic provisioning

    **HostPath** is for testing only and should not be used in production.
  </Accordion>

  <Accordion title="How do I migrate data between PVs?">
    1. Create a new PV with desired configuration
    2. Create a new PVC bound to the new PV
    3. Run a migration pod with both volumes mounted
    4. Copy data from old to new volume
    5. Update workloads to use the new PVC
    6. Delete old PVC/PV after verification
  </Accordion>
</AccordionGroup>
