Kubernetes Volumes

Internal container storage is ephemeral, which means that it exits only for the lifetime of the container. When the container is stopped any data written inside the container is lost. Volumes provide a means of storing data beyond the life of the container.

The Pod definition below contains an emptyDir Volume  An emptyDir is an empty directory that is created when a Pod is assigned to a Node. All containers in a Pod can read and write in the emptyDir Volume which makes useful for multi container Pod use cases.

apiVersion: v1
kind: Pod
metadata:
  name: pod-volume-1
spec:
  containers:
    - name: volume-container-1
      image: busybox
      command: ['sh', '-c', 'while true; do sleep 3600; done']
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - name: demo-volume # matches volume[x].name
          mountPath: /tmp/storage # location inside container where storage is mounted
    - name: volume-container-2
      image: busybox
      command: ['sh', '-c', 'while true; do sleep 3600; done']
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - name: demo-volume
          mountPath: /tmp/storage
  volumes:
    - name: demo-volume
      emptyDir: {} # creates an empty directory on node when Pod is created

The name attribute in volumeMounts must match name in the volumes definition.

The screenshot above shows that we can exec into volume-container-1 and create a file in the VolumeMount. We can then exit volume-container-1 and exec into volume-container-2 and read the same file. This proves that the file exists on the volumeMount and is accessible to all containers in the Pod.

State Persistence

There may be circumstances where you want to retain state beyond the life of a container or Pod. To do this you’ll need to store data in some kind of long term persistence storage outside of the container. Kubernetes allows you to do this using PersistentVolumes and PersistentVolumeClaims.

  • PersistentVolume or PV is a storage resource
  • PersistentVolumeClaim or PVC is a an abstraction between the storage resource and the Pod. PersistentVolumeClaims will automatically bind themselves to a PeristentVolume that has a compatible StorageClass and AccessMode.

Defining a PersistentVolume

A sample PersistentVolume is defined below.

apiVersion: v1
kind: PeristeneVolume
metadata:
  name: demo-pv
spec:
  storageClassName: local-storage
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

storageClassName defines which PersistentVolumeClaim will be able to bind to this PersistentVolume.

capacity defines the amount of storage made available

accessMode specifies what read/write modes can be used to access the volume. ReadWriteOnce means this PersistentVolume can be read from and written to by one Pod at a time.

hostPath – is a PersistentVolume type specifically for development and testing on a single node. It uses a file or directory on the Node to emulate network attached storage.

You wouldn’t use hostPath in production. Instead you’d hook into some kind of cloud based storage, like an Amazon EBS Volume.

Defining a PersistentVolumeClaim

The sample PersistentVolumeClaim below references the PersistnetVolume defined above.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: demo-pvc
spec:
  storageClassName: local-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 512Mi

storageClassName is used to bind to the PersistentVolume we created above, which has a matching storageClass local-storage.

accessModes specifies what read/write modes will be used to access the volume.

resource.requests.storage – defines how much storage the PersistentVolumeClaim needs, in this instance 512Mi is half the total amount available in the PersistentVolume we defined earlier.

After creating the PersistentVolume and PersistentVolumeClaim we can see that the Status of both is  Bound.

Using a PersistentVolumeClaim

The Pod definition below uses a PersistentVolumeClaim to reference the PersistentVolume we created above.

apiVersion: v1
kind: Pod
metadata:
  name: demo-pvc-pod
spec:
  containers:
    - name: pvc-container
      image: busybox
      imagePullPolicy: IfNotPresent
      command: ['/bin/sh', '-c', 'while true; do sleep 3600; done']
      volumeMounts:
        - name: demo-pvc
          mountPath: 'tmp/pvc-data'
  volumes:
    - name: demo-pvc
      persistentVolumeClaim:
        claimName: demo-pvc

We define a Volume and specify persistentVolumeClaim.claimName to reference the PersistentVolumeClaim created earlier. The Volume is mounted to the container the same way any other Volume is mounted, by specifying the Volume name and a mount path inside the container.

To prove that the PersistentVolume persists data beyond the life of a Pod, we can do the following.

  1. Create demo-pvc-pod defined above
  2. Exec into the Pods container and create a file call hello.txt in /tmp/pvc-data
  3. Exit the container and delete the Pod
  4. Create a new demo-pvc-pod and exec into its container.
  5. The hello.txt file you created for the first Pod should still be visible.

The sample code for these notes is available on Github.