Reference: K0s CSI Driver
First, CSI stands for Container Storage Interface. It is an API for storage drivers to interact with kubernetes ( k0s ). Storage drivers are software that facilitate data storage. However, different types of storage require different drivers to work. Some drivers are generic while others are specific to their vendor's features.
Note: This document assumes you already have an NFS server with at least 1 share. If you don't, see Red Hat's blog - Learning NFS through server and client configuration
The best way to install components and applications ( apps ) is with the helm app.
wget https://get.helm.sh/helm-v4.2.0-linux-amd64.tar.gz
sha256sum helm-v4.2.0-linux-amd64.tar.gz | grep 97dbeb971be4ac4b27e3839976d9564c0fb35c6f3b1da89dd1e292d236af4096
tar zxf helm-v4.2.0-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/local/bin/helm
rm -rf linux-amd64
helm version
# Add the official Kubernetes CSI Helm repository helm repo add csi-driver-nfs https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts helm repo update
# Install the driver with the customized k0s path sudo helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs \ --namespace kube-system \ --set kubeletDir=/var/lib/k0s/kubelet \ --kubeconfig /var/lib/k0s/pki/admin.conf
watch -n1 'k0s kubectl --namespace=kube-system get pods --selector="app.kubernetes.io/instance=csi-driver-nfs"'
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-csi provisioner: nfs.csi.k8s.io parameters: server: 192.168.1.50 # Replace with your NFS Server IP share: /volume1/k8s # Replace with your exported NFS path reclaimPolicy: Delete volumeBindingMode: Immediate mountOptions: - nfsvers=3 - hard # Pods wait if the NFS server goes offline - nolock # Use '-o nolock' to keep locks local
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-nfs-pvc spec: accessModes: - ReadWriteMany storageClassName: nfs-csi resources: requests: storage: 5Gi
sudo k0s kubctl apply -f manifest-nfs-pvc.yaml
sudo k0s kubectl get pvc
apiVersion: v1 kind: PersistentVolume metadata: name: existing-nfs-pv spec: capacity: storage: 100Gi # Match or exceed what your pods need volumeMode: Filesystem accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain # Retain ensures data isn't deleted if the PVC drops storageClassName: "" # Must be blank or use a custom name to skip automatic provisioning csi: driver: nfs.csi.k8s.io volumeHandle: existing-nfs-shared-volume # Must be a unique string in the cluster volumeAttributes: server: 192.168.1.50 # Replace with your NFS Server IP share: /volume1/existing-data # Replace with your exact existing path mountOptions: - nfsvers=4.1 - hard - nolock # Kept to prevent the rpc.statd error
sudo k0s kubectl aply -f manifest-existing-nfs-pv.yaml
sudo k0s kubectl get pv
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: existing-nfs-pvc spec: accessModes: - ReadWriteMany storageClassName: "" # Must remain blank to match the PV's blank storageClassName volumeName: existing-nfs-pv # Forces binding to your specific PV above resources: requests: storage: 100Gi # Must be less than or equal to the PV size
sudo k0s kubectl get pvc
apiVersion: v1 kind: Pod metadata: name: nfs-app-pod labels: # <--- ADD THIS BLOCK SO THE SERVICE CAN FIND IT name: nfs-app-pod spec: containers: - name: web-server image: nginx:latest volumeMounts: - name: nfs-storage mountPath: /usr/share/nginx/html # Path inside the container where data appears volumes: - name: nfs-storage persistentVolumeClaim: claimName: existing-nfs-pvc # Must exactly match your PVC name
sudo k0s kubectl apply -f manifest-app-nfs-test.yaml
sudo k0s kubectl exec -it nfs-app-pod -- bash ls -lh /usr/share/nginx/html
helm repo add metallb https://metallb.github.io/metallb helm repo update helm install metallb metallb/metallb \ --namespace metallb-system \ --create-namespace \ --kubeconfig /var/lib/k0s/pki/admin.conf
apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: local-pool namespace: metallb-system spec: addresses: - 192.168.1.200-192.168.1.210 # <--- Change to your free network IP range --- apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: local-advertisement namespace: metallb-system spec: ipAddressPools: - local-pool
apiVersion: v1 kind: Service metadata: name: nfs-web-service spec: type: LoadBalancer selector: name: nfs-app-pod # MUST match the label on your Pod ports: - protocol: TCP port: 80 # The port open to your network targetPort: 80 # The port Nginx is listening on inside the container
sudo k0s kubctl apply -f manifest-app-nfs-web-service-lb.yaml