Skip to content

Persistent Volumes

Volumes and Dynamic Storage Provisioning

On-disk files in a container are the simplest place for an application to write data, but this approach has drawbacks. The files are lost when the container crashes or stops for any other reason. Furthermore, files within a container are inaccessible to other containers running in the same Pod. The Kubernetes Volume abstraction addresses both of these issues.

Volumes differ in their storage implementation and their initial contents. You can choose the volume source that best fits your use case. For a complete list of volume types, refer to the Kubernetes Volumes documentation

PersistentVolume resources are used to manage durable storage in a cluster. In GKE, a PersistentVolume is typically backed by a persistent disk. You can also use other storage solutions like NFS. Filestore is an NFS solution on Google Cloud

PersistentVolumeClaims

A PersistentVolumeClaim is a request for and claim to a PersistentVolume resource. PersistentVolumeClaim objects request a specific size, access mode, and StorageClass for the PersistentVolume. If a PersistentVolume that satisfies the request exists or can be provisioned, the PersistentVolumeClaim is bound to that PersistentVolume.

Most of the time, you don't need to directly configure PersistentVolume objects or create Compute Engine persistent disks. Instead, you can create a PersistentVolumeClaim and Kubernetes automatically provisions a persistent disk for you.

The following manifest describes a request for a 30 gigabyte (GiB) disk whose access mode allows it to be mounted as read-write by a single node. Meanwhile, it creates a Pod that consumes the PersistentVolumeClaim as a volume.

# pvc-pod-demo.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-demo
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 30Gi
  storageClassName: standard-rwo
---
kind: Pod
apiVersion: v1
metadata:
  name: pod-demo
spec:
  volumes:
    - name: pvc-demo-vol
      persistentVolumeClaim:
       claimName: pvc-demo
  containers:
    - name: pod-demo
      image: nginx
      resources:
        limits:
          cpu: 10m
          memory: 80Mi
        requests:
          cpu: 10m
          memory: 80Mi
      ports:
        - containerPort: 80
          name: "http-server"
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: pvc-demo-vol

When you create this PersistentVolumeClaim object with kubectl apply -f pvc-pod-demo.yaml, Kubernetes dynamically creates a corresponding PersistentVolume object.

Because the storage class standard-rwo uses volume binding mode WaitForFirstConsumer, the PersistentVolume will not be created until a Pod is scheduled to consume the volume.

Access modes of Persistent Volumes

PersistentVolume resources support the following access modes:

ReadWriteOnce: The volume can be mounted as read-write by a single node. ReadOnlyMany: The volume can be mounted read-only by many nodes. ReadWriteMany: The volume can be mounted as read-write by many nodes. PersistentVolume resources that are backed by Compute Engine persistent disks don't support this access mode.

Other Alternatives to consider before choosing PVs

Persistent Volumes may not always be the best option for you. Some reasons could be:

  • You don't need the data after the pod is removed from a node
  • You don't want to manage the life cycle of the volumes
  • You would like to store your objects/files in GCS S3 buckets

Ephemeral Volume type: emptyDir

An emptyDir volume is first created when a Pod is assigned to a node and exists as long as that Pod is running on that node and the volume is initially empty. All containers in the Pod can read and write the same files in the emptyDir volume, When a Pod is removed from a node for any reason, the data in the emptyDir is deleted permanently.

if you set the emptyDir.medium field to "Memory", Kubernetes mounts a tmpfs (RAM-backed filesystem) for you instead. While tmpfs is very fast, be aware that unlike disks, tmpfs is cleared on node reboot and any files you write count against your container's memory limit.

Some uses for an emptyDir are:

  • scratch space, such as for a disk-based merge sort
  • checkpointing a long computation for recovery from crashes
  • holding files that a content-manager container fetches while a webserver container serves the data

Note: A container crashing does not remove a Pod from a node. The data in an emptyDir volume is safe across container crashes.

emptyDir configuration example

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 500Mi

configMap

A ConfigMap provides a way to inject configuration data into pods. The data stored in a ConfigMap can be referenced in a volume of type configMap and then consumed by containerized applications running in a pod.

When referencing a ConfigMap, you provide the name of the ConfigMap in the volume. You can customize the path to use for a specific entry in the ConfigMap.

ConfigMap configuration example

apiVersion: v1
kind: Pod
metadata:
  name: configmap-pod
spec:
  containers:
    - name: test
      image: busybox:1.28
      volumeMounts:
        - name: config-vol
          mountPath: /etc/config
  volumes:
    - name: config-vol
      configMap:
        name: log-config
        items:
          - key: log_level
            path: log_level

secret

A secret volume is used to pass sensitive information, such as passwords, to Pods. You can store secrets in the Kubernetes API and mount them as files for use by pods without coupling to Kubernetes directly. secret volumes are backed by tmpfs (a RAM-backed filesystem) so they are never written to non-volatile storage.

Note: You must create a Secret in the Kubernetes API before you can use it. Note: A container using a Secret as a subPath volume mount will not receive Secret updates.

secret configuration example:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm