Post

Deploy ReadWriteMany volume on local K8s for testing

There are several use cases where you may need to share folders between applications. In the cloud hosted kubernetes this requirement can be achieved with cloud native shared disks such as AWS EFS. However we may want to deploy something locally to help test containers.

This solution creates a mock nfs storage class using the smb protocol, in order to dynamically provision ReadWriteMany volumes on local kubernetes clusters, such as rancher and minikube, for local testing and development.

create namespace

1
kubectl create ns mock-nfs

Create credentials

1
2
3
4
5
6
7
8
9
10
kubectl apply -n mock-nfs -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: smbcreds
type: Opaque
stringData:
  username: testuser
  password: testpass
EOF

Create Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
kubectl apply -n mock-nfs -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: samba-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: samba
  template:
    metadata:
      labels:
        app: samba
    spec:
      containers:
        - name: samba
          image: dperson/samba:latest
          env:
            - name: USERID
              value: "0"
            - name: GROUPID
              value: "0"
            - name: TZ
              value: "Europe/London"
            - name: USER
              value: "testuser;testpass"
            - name: SHARE
              value:  "share;/share;yes;no;no;testuser;;;"
          ports:
            - containerPort: 445
          volumeMounts:
            - name: share-pvc
              mountPath: /share
      volumes:
        - name: share-pvc
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: samba
spec:
  selector:
    app: samba
  ports:
    - protocol: TCP
      port: 445
      targetPort: 445
      name: samba-tcp
  type: ClusterIP
EOF

Deploy provisioner on kubernetes

1
2
3
helm repo add csi-driver-smb https://raw.githubusercontent.com/kubernetes-csi/csi-driver-smb/master/charts

helm install csi-driver-smb csi-driver-smb/csi-driver-smb  --version v1.11.0 -n mock-nfs

Create the storage class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
kubectl apply -n mock-nfs -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs
provisioner: smb.csi.k8s.io
parameters:
  # name-inside-cluser/share
  source: "//samba.mock-nfs.svc.cluster.local/share"

  # if csi.storage.k8s.io/provisioner-secret is provided, will create a sub directory
  # with PV name under source
  csi.storage.k8s.io/provisioner-secret-name: "smbcreds"
  csi.storage.k8s.io/provisioner-secret-namespace: "mock-nfs"
  csi.storage.k8s.io/node-stage-secret-name: "smbcreds"
  csi.storage.k8s.io/node-stage-secret-namespace: "mock-nfs"
reclaimPolicy: Delete  # available values: Delete, Retain
volumeBindingMode: Immediate
mountOptions:
  - dir_mode=0777
  - file_mode=0777
  - uid=0
  - gid=0
EOF

To test this you can create a shared volume like this. The pvc does not need to be in the same namespace, it will be be created by the csi-smb driver

1
2
3
4
5
6
7
8
9
10
11
12
13
kubectl apply -f - <<EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: shared-vol
spec:
  storageClassName: nfs
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Mi
EOF

Then mount it 2 pods.

Pod 1 Mounts the shared-pvc to /opt this pod sleeps write hello to /opt/hello

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
kubectl apply -f - <<EOF
kind: Pod
apiVersion: v1
metadata:
  name: test-pod1
spec:
  containers:
    - name: test-pod1
      image: busybox:stable
      resources:
        requests:
          cpu: 100m
          memory: 50Mi
        limits:
          cpu: 100m
          memory: 50Mi
      command:
        - "/bin/sh"
      args:
        - "-c"
        - "echo hello > /opt/hello && sleep 3600"
      volumeMounts:
        - name: shared-pvc
          mountPath: "/opt"
  restartPolicy: "Never"
  volumes:
    - name: shared-pvc
      persistentVolumeClaim:
        claimName: shared-vol
EOF

Pod 2 Mounts the shared-pvc to /opt this pod sleeps for 10 seconds prints contents of /opt/hello

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
kubectl apply -f - <<EOF
kind: Pod
apiVersion: v1
metadata:
  name: test-pod2
spec:
  containers:
    - name: test-pod2
      image: busybox:stable
      resources:
        requests:
          cpu: 100m
          memory: 50Mi
        limits:
          cpu: 100m
          memory: 50Mi
      command:
        - "/bin/sh"
      args:
        - "-c"
        - " sleep 10 && echo $(cat /opt/hello) && sleep 3600"
      volumeMounts:
        - name: shared-pvc
          mountPath: "/opt"
  restartPolicy: "Never"
  volumes:
    - name: shared-pvc
      persistentVolumeClaim:
        claimName: shared-vol
EOF
This post is licensed under CC BY 4.0 by the author.