Lab_03 - Persisting Data

Lab 03: Persisting Data

In this lab, we will see how we can keep our data, even though our containers are (and should be!) ephemeral.

emptyDir

We will start with a very simple example - the emptyDir volume type. This simply uses a directory on the node the pod is running on.

Connect to the master node with your user credentials. Make sure that there are no pods already running on the system (in the default namespace).

Copy the 02-alpine.yaml file to a new file: 09-emptydir.yaml

Edit the new file to add an emptyDir volume. Name the volume empty-volume, and mount it in /scratch

Create a pod based on this specification.

Solution

kubectl get pod

09-emptydir.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: alpine01
spec:
  containers:
    - image: alpine
      name: alpine
      stdin: true
      tty: true
      volumeMounts:
        - mountPath: /scratch
          name: empty-volume
  volumes:
    - name: empty-volume
      emptyDir: {}

Get a shell inside the pod. Create a file inside the /scratch directory, with a text contents of your choosing.

Hint

you can connect to the existing shell (kubectl attach), or you can open a new one (kubectl exec). Which one you choose is very relevant when you exit the pod!

Solution

Inside the container:

Exit the pod and delete it.

Solution

Inside the container:

Create a new pod based on the same yaml file.

Solution

Get a shell inside the new pod. Is your file still inside?

Solution

Note

While emptyDir volumes wil survive a pod crash/restart, they will be removed when the pod itself is removed.

Exit the pod and delete it.

hostPath

A more relevant (more… persistent) example is the hostPath volume type. This will actually persist across pod deletions, but has another disadvantage - it makes the pod dependent on a specific host (a specific host directory structure). So in order to make sure that the pods will find that directory structure, we will force them to always run on a specific host.

Needless to say, this is not something you would generally want to do in production. However, it is a useful exercise for dealing with labels and selectors.

In order to make testing easier, we want to force our pod to run on one specific node (it is easier this way than chasing the pods across multiple nodes). In order to do this, we will use a label. Label your first worker node (k8s-ID-02) with pathConfiguredID=true (replace ID with your user ID).

Solution

Make sure that the label has been correctly applied.

Solution

Copy the 09-emptydir.yaml file to 10-hostpath.yaml.

Edit the 10-hostpath.yaml file to add the following:

  • A node selector that forces the pod to run only on nodes labeled with pathConfiguredID=true. (under .spec.nodeSelector).

  • A volume named host-volume mapped to the host directory /tmp/hostpath

  • A volumeMount for the container that tells it to mount the volume under /hostvol

Create a pod based on this new specification file.

Solution

10-hostpath.yaml:

Get a shell into the pod, and create a test file in /hostvol. Use a content of your choosing.

Solution

Inside the pod:

Exit the pod. Check the /tmp/hostpath directory. You should see your newly-created file.

Solution

Delete the pod, and create a new one based on the same YAML file. Get a shell into the pod. The file should still be in /hostvol.

Solution

Inside the pod:

Delete the pod.

Optional: NFS Volume

Getting closer to a real-life deployment - we will be using an NFS mount that we connect to over the network. The task is marked as optional because it has a prerequisite that cannot always be satisfied - a server that has been preconfigured to export an NFS mount over the network. The NFS mount has also been prepopulated with an index.html file, so that you can test whether your configuration is correct.

Note

While closer to a real-life example, we are not there yet! We are still using volumes defined at the pod level, which are closely coupled to the pods themselves. A real life scenario would actually be using PVs/PVCs (see the next section).

Copy 10-hostpath.yaml to 11-nfs.yaml.

Edit the 11-nfs.yaml file to change the following:

  • the pod should be running nginx (which also means that stdin and tty are no longer necessary)

  • the nodeSelector is no longer necessary (all nodes have equal access to the NFS datastore)

  • the pod name should be nginx-01

  • the volume type is now nfs, on server 10.10.17.34, path /NFS_STUDENTS (remember that file and directory names are case sensitive!)

  • the volume name is nfs-vol-xx (with xx being your user ID)

  • the volume is mounted inside the container as /usr/share/nginx/html (the default nginx web server root)

Create a pod based on this specification.

Solution

10-hostpath.yaml:

Make sure that the pod is running correctly.

If the pod seems to be stuck in „Pending” or „ContainerCreating”, it is likely that the NFS mount has failed. Use kubectl describe to get more details, and ask your instructor for assistance.

Solution

Get the pod IP address. Connect to the pod IP address using curl. You should get a page confirming that you have successfully completed this task.

Solution

Delete the pod.

Solution

Bonus: PVs

For the most complex scenario, we will use the NFS mount to provision multiple persistent volumes for our various pods. We will work with persistent volumes, persistent volume claims, and pods. To keep things simpler, we will define the components in separate files.

Create a YAML file (12-nfs-pv.yaml) for the NFS persistent volume. The details are below:

  • name: nfs-pv01-ID (replace ID with your assigned ID)

  • .spec.capacity.storage: 2Mi

  • .spec.accessModes: [ ReadWriteOnce ]

  • type: nfs

  • .spec.nfs.server: 10.10.17.34

  • .spec.nfs.path: /NFS_STUDENTS

Note

If you have not seen the „Mi” notation before, that is a „mebibyte”. The kibi/mebi/gibi notation has been introduced to differentiate between regular SI prefixes (powers of 10) and binary prefixes (powers of 2). More details here: https://en.wikipedia.org/wiki/Binary_prefixarrow-up-right

Hint

Solution

12-nfs-pv.yaml:

Apply the file to create a PersistentVolume.

Solution

Check the list of PersistentVolumes to verify that the new volume has been successfully created.

Solution

Create another YAML file ( 13-nfs-pvc.yaml ), that defines a PersistentVolumeClaim. The claim will be named nfs-pvc01, and will request a PV with a size of 2Mi.

Hint

Create a PVC based on this new file.

Solution

13-nfs-pvc.yaml:

Verify that the PVC has been successfully created, and that Kubernetes has bound it to the available NFS PV ( nfs-pv01 ).

Solution

Create a YAML file ( 14-nfs-pod.yaml ) for a pod that mounts the PVC as a volume:

  • The pod should run nginx

  • The name of the pod should be nginx-nfs

  • The pod should mount a volume under /usr/share/nginx/html

  • The volume should be the PVC we created earlier ( nfs-pvc01 )

Hint

Create a pod based on this file. Check that the pod has successfully started.

Solution

14-nfs-pod.yaml:

Get the pod IP address and connect to it using curl. What do you see?

Solution

Note

You should get the exact same congratulatory file you have seen in the previous exercise. And it is normal - after all, we are mounting the exact same volume! The difference is that this time the allocation of the volume is done dynamically, based on the volume size (specified in the PV) and the size requested by the pod (via PVC).

Cleaning Up

Delete all PVs, PVCs, and pods.

Solution

Last updated