Aller au contenu

Lab Adv 02: Deploy Longhorn on OKS

By the end of this lab, you will be able to:

  • Deploy Longhorn on an OKS cluster
  • Create persistent volumes using Longhorn
  • Test a ReadWriteMany volume
  • Validate data persistence in a multi-AZ environment

Before starting this lab, make sure you have the following:

Create a nodepool.yaml file:

apiVersion: oks.dev/v1beta2
kind: NodePool
metadata:
name: nodepool-01
spec:
desiredNodes: 1
nodeType: tinav7.c4r8p2
zones:
- eu-west-2a
- eu-west-2b
- eu-west-2c
volumes:
- device: root
size: 100
type: "gp2"
dir: '/'
- device: xvdl
size: 100
type: "gp2"
dir: "/var/lib/longhorn"

Apply the configuration:

Terminal window
kubectl apply -f nodepool.yaml

Create the configuration-iscsi.yaml file:

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: longhorn-iscsi-installation
labels:
app: longhorn-iscsi-installation
annotations:
command: &cmd OS=$(grep -E "^ID_LIKE=" /etc/os-release | cut -d '=' -f 2); if [[ -z "${OS}" ]]; then OS=$(grep -E "^ID=" /etc/os-release | cut -d '=' -f 2); fi; if [[ "${OS}" == *"debian"* ]]; then sudo apt-get update -q -y && sudo apt-get install -q -y open-iscsi nfs-common cryptsetup && sudo systemctl -q enable iscsid && sudo systemctl start iscsid && sudo modprobe iscsi_tcp; elif [[ "${OS}" == *"suse"* ]]; then sudo zypper --gpg-auto-import-keys -q refresh && sudo zypper --gpg-auto-import-keys -q install -y open-iscsi && sudo systemctl -q enable iscsid && sudo systemctl start iscsid && sudo modprobe iscsi_tcp; else sudo yum makecache -q -y && sudo yum --setopt=tsflags=noscripts install -q -y iscsi-initiator-utils && echo "InitiatorName=$(/sbin/iscsi-iname)" > /etc/iscsi/initiatorname.iscsi && sudo systemctl -q enable iscsid && sudo systemctl start iscsid && sudo modprobe iscsi_tcp; fi && if [ $? -eq 0 ]; then echo "iscsi install successfully"; else echo "iscsi install failed error code $?"; fi
spec:
selector:
matchLabels:
app: longhorn-iscsi-installation
template:
metadata:
labels:
app: longhorn-iscsi-installation
spec:
nodeSelector:
node-pool: nodepool-01
hostNetwork: true
hostPID: true
initContainers:
- name: iscsi-installation
command:
- nsenter
- --mount=/proc/1/ns/mnt
- --
- bash
- -c
- *cmd
image: alpine:3.17
securityContext:
privileged: true
containers:
- name: sleep
image: registry.k8s.io/pause:3.1
updateStrategy:
type: RollingUpdate

Apply the DaemonSet:

Terminal window
kubectl apply -f configuration-iscsi.yaml

Create the namespace:

Terminal window
kubectl create ns longhorn-system

Add the Helm repository:

Terminal window
helm repo add longhorn https://charts.longhorn.io
helm repo update

Install Longhorn:

Terminal window
helm install longhorn longhorn/longhorn --namespace longhorn-system

Check the pods:

Terminal window
kubectl get pods -n longhorn-system

Create the longhorn-storageclass.yaml file:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-3repl
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "2880"
replicaAutoBalance: "least-effort"
fsType: "ext4"
nfsOptions: "vers=4.2,noresvport,softerr,timeo=600,retrans=5"

Apply the StorageClass:

Terminal window
kubectl apply -f longhorn-storageclass.yaml

Create the pvc.yaml file:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rwx-test-claim
namespace: longhorn-system
spec:
accessModes:
- ReadWriteMany
storageClassName: longhorn-3repl
resources:
requests:
storage: 3Gi
Terminal window
kubectl apply -f pvc.yaml
Terminal window
kubectl get volumes.longhorn.io -n longhorn-system
## Expected result:
NAME DATA ENGINE STATE ROBUSTNESS SCHEDULED SIZE
pvc-d1359fcd-9267-4b28-903a-1912a1d1af10 v1 detached unknown 3221225472
Terminal window
kubectl get replicas.longhorn.io -n longhorn-system
## Expected result:
NAME DATA ENGINE STATE NODE DISK
pvc-d1359fcd-9267-4b28-903a-1912a1d1af10-r-0baeabda v1 stopped ip-10-50-110-132 202e26f6-0f49-4733-8b13-5787febd0b16
pvc-d1359fcd-9267-4b28-903a-1912a1d1af10-r-0efa26c4 v1 stopped ip-10-50-65-223 b325f185-de59-4a5a-98f3-daa3e83eea72
pvc-d1359fcd-9267-4b28-903a-1912a1d1af10-r-aa17101c v1 stopped ip-10-50-32-166 b7dc5742-2297-46b7-8904-d5a5440c5d8b
Terminal window
kubectl port-forward -n longhorn-system svc/longhorn-frontend 8080:80

Access: 👉 http://localhost:8080

Expected result:

  • Volume rwx-test-claim is Healthy
  • 3 replicas on different nodes
  • Replicas appear in stopped state until a pod mounts the volume

Create the deployment-nginx.yaml file:

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-rwx-demo
namespace: longhorn-system
spec:
replicas: 3
selector:
matchLabels:
app: nginx-rwx-demo
template:
metadata:
labels:
app: nginx-rwx-demo
spec:
nodeSelector:
node-pool: nodepool-01
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
command: ["/bin/sh", "-c"]
args:
- |
echo "Welcome!" > /usr/share/nginx/html/index.html;
while true; do
echo "$(date) — $(hostname)" >> /usr/share/nginx/html/dates.log;
sleep 60;
done
volumes:
- name: shared-data
persistentVolumeClaim:
claimName: rwx-test-claim
Terminal window
kubectl apply -f deployment-nginx.yaml

Replicas should now be in RUNNING state:

Terminal window
kubectl get replicas.longhorn.io
# Expected result:
NAME DATA ENGINE STATE NODE DISK
pvc-f6d331a7-002f-4a26-b4bc-0042ae816836-r-13f4eaf0 v1 running ip-10-50-110-132 202e26f6-0f49-4733-8b13-5787febd0b16
pvc-f6d331a7-002f-4a26-b4bc-0042ae816836-r-bbe908b3 v1 running ip-10-50-32-166 b7dc5742-2297-46b7-8904-d5a5440c5d8b
pvc-f6d331a7-002f-4a26-b4bc-0042ae816836-r-c3fa3af1 v1 running ip-10-50-65-223 b325f185-de59-4a5a-98f3-daa3e83eea72
Terminal window
kubectl exec -it <pod-name> -- tail -f /usr/share/nginx/html/dates.log
## Expected result:
# Pod 1 :
kubectl exec -it nginx-rwx-demo-6b777c9db8-n29n5 -- tail -f /usr/share/nginx/html/dates.log
Mon Jan 26 12:53:23 UTC 2026 nginx-rwx-demo-6b777c9db8-xvrd2
Mon Jan 26 12:53:24 UTC 2026 nginx-rwx-demo-6b777c9db8-w298m
Mon Jan 26 12:53:25 UTC 2026 nginx-rwx-demo-6b777c9db8-n29n5
# Pod 2 :
kubectl exec -it nginx-rwx-demo-6b777c9db8-w298m -- tail -f /usr/share/nginx/html/dates.log
Mon Jan 26 12:53:23 UTC 2026 nginx-rwx-demo-6b777c9db8-xvrd2
Mon Jan 26 12:53:24 UTC 2026 nginx-rwx-demo-6b777c9db8-w298m
Mon Jan 26 12:53:25 UTC 2026 nginx-rwx-demo-6b777c9db8-n29n5
Mon Jan 26 12:54:23 UTC 2026 nginx-rwx-demo-6b777c9db8-xvrd2
Terminal window
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data

The pod is automatically recreated on another node. Verification:

Terminal window
kubectl exec -it <new-pod> -- tail /usr/share/nginx/html/dates.log

Expected result:

—> data is still present