Docker containers running in Kubernetes have an ephemeral file system: Once a container is terminated, all files are gone. In order to store persistent data in Kubernetes, you need to mount a Persistent Volume into your container. Kubernetes has built-in support for network filesystems found in the most common cloud providers, like Amazon’s EBS, Microsoft’s Azure disk, etc. However, some cloud hosting services, like the Hetzner cloud, provide network storage using the CIFS (SMB, Samba, Windows Share) protocol, which is not natively supported in Kubernetes.
Fortunately, Kubernetes provides Flexvolume, which is a plugin mechanism enabling users to write their own drivers. There are a few flexvolume drivers for CIFS out there, but for different reasons none of them seemed to work for me. So I wrote my own, which can be found on github.com/fstab/cifs.
This blog post shows how to use the
fstab/cifs plugin for mounting CIFS volumes in Kubernetes.
The flexvolume plugin is a single shell script named cifs. This shell scripted must be available in
/usr/libexec/kubernetes/kubelet-plugins/volume/exec/fstab~cifs/ on the Kubernetes master and on each of the Kubernetes nodes. The directory name
fstab~cifs will be mapped to the Flexvolume driver name
On the Kubernetes master and on each Kubernetes node run the following commands:
mkdir -p '/usr/libexec/kubernetes/kubelet-plugins/volume/exec/fstab~cifs' cd '/usr/libexec/kubernetes/kubelet-plugins/volume/exec/fstab~cifs' curl -L -O https://raw.githubusercontent.com/fstab/cifs/master/cifs chmod 755 cifs
cifs script requires a few executables to be available on each host system:
mount.cifs, on Ubuntu this is in the cifs-utils package.
jq, on Ubuntu this is in the jq package.
mountpoint, on Ubuntu this is in the util-linux package.
base64, on Ubuntu this is in the coreutils package.
To check if the installation was successful, run the following command:
It should output a JSON string containing
"status": "Success". This command is also run by Kubernetes itself when the cifs plugin is detected on the file system.
The plugin takes the CIFS username and password from a Kubernetes Secret. To create the secret, you first have to convert your username and password to base64 encoding:
echo -n username | base64 echo -n password | base64
Then, create a file
secret.yml and use the ouput of the above commands as username and password:
apiVersion: v1 kind: Secret metadata: name: cifs-secret namespace: default type: fstab/cifs data: username: 'ZXhhbXBsZQ==' password: 'bXktc2VjcmV0LXBhc3N3b3Jk'
Apply the secret:
kubectl apply -f secret.yml
You can check if the secret was installed successfully using
kubectl describe secret cifs-secret.
Next, create a file
pod.yml with a test pod (replace
//server/share with the network path of your CIFS share):
apiVersion: v1 kind: Pod metadata: name: busybox namespace: default spec: containers: - name: busybox image: busybox command: - sleep - "3600" imagePullPolicy: IfNotPresent volumeMounts: - name: test mountPath: /data volumes: - name: test flexVolume: driver: "fstab/cifs" fsType: "cifs" secretRef: name: "cifs-secret" options: networkPath: "//server/share" mountOptions: "dir_mode=0755,file_mode=0644,noperm"
Start the pod:
kubectl apply -f pod.yml
You can verify that the volume was mounted successfully using
kubectl describe pod busybox.
If everything is fine, start a shell inside the container to see if it worked:
kubectl exec -ti busybox /bin/sh
Inside the container, you should see the CIFS share mounted to