This project demonstrates how to deploy a stateful application on Kubernetes using PersistentVolumeClaims (PVCs) to ensure data durability across pod restarts.
The application used is Linkding, a self-hosted bookmark manager, deployed into its own namespace with persistent SQLite storage.
This lab was built and tested locally using Rancher Desktop (K3s), following production-grade Kubernetes storage patterns.
- Namespace isolation (
linkding) - Deployment for application lifecycle management
- Service for internal access
- PersistentVolumeClaim (PVC) for durable storage
- StorageClass:
local-path(dynamic provisioning)
- Containers are ephemeral by default
- Application data is lost when pods restart unless persisted externally
- Requests storage independently of pod lifecycle
- Automatically provisioned via StorageClass
- Bound to a PersistentVolume (PV)
- PVC mounted into container at
/etc/linkding/data - SQLite database persists across pod restarts
.
├── manifests/
│ ├── linkding/
│ │ ├── linkding.yaml # Deployment + Service (no storage)
│ │ └── linkding-with-storage.yaml # PVC + Deployment + Service
│ └── nginx/ # Earlier learning artifacts
├── screenshots/
│ ├── 01-pods-running.png
│ ├── 02-pvc-bound.png
│ ├── 02-describe-pvc.png
│ ├── 03-container-data-dir.png
│ ├── 03-sqlite-data-persisted.png
│ └── 04-linkding-ui.png
└── README.md
# Create namespace
kubectl create namespace linkding
# Deploy with persistent storage
kubectl apply -f manifests/linkding/linkding-with-storage.yaml -n linkding
# Verify pods and PVC
kubectl get pods -n linkding
kubectl get pvc -n linkding
# Access Linkding UI
kubectl port-forward svc/linkding -n linkding 9090:9090Open http://localhost:9090 in your browser.
- Kubernetes namespace isolation for workload separation
- Stateful application deployment using PVCs
- Dynamic storage provisioning via StorageClass
- Production-grade volume mounting patterns
- Data persistence validation across pod restarts





