cd ..
Kubernetes

Configuring emptyDir volumes in Kubernetes Pods


Configuring emptyDir volumes in Kubernetes Pods

Containers are, by nature, ephemeral. This means that files created within a container’s filesystem can be lost when the container is recreated.

In some situations, however, we need to store temporary files during a Pod’s execution or share data between containers that are part of the same Pod.

For these cases, Kubernetes provides the emptyDir volume.

In this article, we will create a Pod using an Nginx image, mount an emptyDir volume in the /giropops directory, and test its functionality.

What is an emptyDir volume?

An emptyDir is a temporary volume created when the Pod starts.

As the name indicates, it starts as an empty directory. The Pod’s containers can mount this volume and use the space to store temporary files.

An important characteristic is that the volume belongs to the Pod, and not directly to the container.

Therefore:

This type of volume should not be used to store information that needs to remain available after the Pod is deleted.

Creating the Pod manifest

Let’s create the pod-emptydir.yaml file with the following content:

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: coringao
  name: coringao

spec:
  containers:
    - image: nginx
      name: webserver

      volumeMounts:
        - mountPath: /giropops
          name: primeiro-emptydir

      resources:
        limits:
          cpu: "1.5"
          memory: "128Mi"
        requests:
          cpu: "0.5"
          memory: "64Mi"

  dnsPolicy: ClusterFirst
  restartPolicy: Always

  volumes:
    - name: primeiro-emptydir
      emptyDir:
        sizeLimit: "256Mi"

In this manifest, we create a Pod named coringao containing a single container named webserver.

The container uses the official Nginx image:

image: nginx
name: webserver

We also define CPU and memory requests and limits:

resources:
  limits:
    cpu: "1.5"
    memory: "128Mi"
  requests:
    cpu: "0.5"
    memory: "64Mi"

The container requests half a CPU core and 64 MiB of memory, being able to use a maximum of 1.5 CPU and 128 MiB of memory.

Declaring the emptyDir volume

The volume is declared within spec.volumes:

volumes:
  - name: primeiro-emptydir
    emptyDir:
      sizeLimit: "256Mi"

The name field identifies the volume within the Pod:

name: primeiro-emptydir

The emptyDir field, on the other hand, tells Kubernetes that we want to create a temporary volume:

emptyDir:

We also define a storage limit of 256 MiB:

sizeLimit: "256Mi"

By default, emptyDir uses the temporary storage available on the node where the Pod is running.

Mounting the volume in the container

Declaring a volume does not mean it will be automatically available inside the container.

We need to mount it using volumeMounts:

volumeMounts:
  - mountPath: /giropops
    name: primeiro-emptydir

The mountPath field indicates which directory in the container the volume will be mounted to:

mountPath: /giropops

The name field, on the other hand, must be exactly the same as the name provided in spec.volumes:

name: primeiro-emptydir

The association happens by name:

volumeMounts:
  - name: primeiro-emptydir
volumes:
  - name: primeiro-emptydir

If the names are different, Kubernetes will not be able to identify which volume should be mounted in the container.

Validating the manifest

Before creating the resource, we can validate the file locally using:

kubectl apply --dry-run=client -f pod-emptydir.yaml

If the manifest is correct, output similar to this will be shown:

pod/coringao created (dry run)

The --dry-run=client validates the manifest structure without creating the Pod in the cluster.

Creating the Pod

After validation, we apply the manifest:

kubectl apply -f pod-emptydir.yaml

The expected output is:

pod/coringao created

We can monitor the Pod’s status with:

kubectl get pods

Example:

NAME       READY   STATUS    RESTARTS   AGE
coringao   1/1     Running   0          10s

When the STATUS field is Running, the container is executing.

Entering the container

To verify if the volume was mounted correctly, we can open a terminal inside the container:

kubectl exec -ti coringao -- sh

Inside the container, we execute:

ls

The /giropops directory will appear among the available directories:

bin
boot
dev
docker-entrypoint.d
docker-entrypoint.sh
etc
giropops
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

This indicates that the volume was mounted at the path defined in the manifest.

Creating files in emptyDir

Now we can create files inside the volume:

touch /giropops/CORINTHIANS
touch /giropops/VAI

Next, we list the content:

ls /giropops

The output will be:

CORINTHIANS  VAI

We can also use one item per line:

ls -1 /giropops

Output:

CORINTHIANS
VAI

The files were written to the emptyDir volume, not directly to the container’s writable layer.

Checking the volume mount

Another way to check if the volume is mounted is to use:

kubectl exec coringao -- mount

We can filter only the mount related to the /giropops directory:

kubectl exec coringao -- mount | grep giropops

We can also check the available space:

kubectl exec coringao -- df -h /giropops

Modifying an existing Pod

During configuration, it can happen that a Pod with the same name already exists.

When trying to add the volume or modify fields such as container name, resources, and mounts, Kubernetes may show the following error:

The Pod "coringao" is invalid: spec: Forbidden:
pod updates may not change fields

This happens because much of a Pod’s specification is immutable after it is created.

For example, we cannot directly add a new volume to a Pod that is already running.

In this case, we need to remove the old Pod:

kubectl delete pod coringao

Then, we recreate the resource using the updated manifest:

kubectl apply -f pod-emptydir.yaml

There is also the command:

kubectl replace --force -f pod-emptydir.yaml

The --force removes the existing resource and creates another based on the new manifest.

In real environments, we typically don’t manage individual Pods this way. We usually use resources like Deployment, which are responsible for creating and replacing Pods automatically.

Common errors when configuring volumeMounts

A common error is to use volumeMount in the singular:

volumeMount:

The correct field is volumeMounts, in the plural:

volumeMounts:

Another possible error is incorrectly writing the sizeLimit field.

Incorrect:

sizeLImit: "256Mi"

Correct:

sizeLimit: "256Mi"

Kubernetes manifest fields are case-sensitive.

It is also important to ensure that the name provided in volumeMounts is the same as the name declared in volumes.

Incorrect:

volumeMounts:
  - name: primeiro-volume
volumes:
  - name: primeiro-emptydir

Correct:

volumeMounts:
  - name: primeiro-emptydir
volumes:
  - name: primeiro-emptydir

Testing emptyDir behavior

The main concept of emptyDir is that the volume follows the Pod’s lifecycle.

If only the container restarts, the files remain in the volume.

However, if the Pod is deleted:

kubectl delete pod coringao

And created again:

kubectl apply -f pod-emptydir.yaml

The new volume will be created empty.

When executing:

kubectl exec coringao -- ls -1 /giropops

The CORINTHIANS and VAI files will no longer be available.

This happens because the new Pod has a new instance of the emptyDir volume.

We can summarize its behavior as follows:

Container restart  → data remains
Pod deletion       → data is removed
New Pod creation   → a new emptyDir is created

When to use emptyDir?

emptyDir can be used for:

For example, one container can generate files within the volume while another container processes them or makes them available via a web server.

Since the volume does not survive Pod deletion, it is not suitable for databases, important uploads, or any information that needs to be stored permanently.

For persistent data, we should use resources like PersistentVolume and PersistentVolumeClaim.

Conclusion

In this article, we created a Pod using the Nginx image and configured a temporary emptyDir volume.

The volume was declared in spec.volumes:

volumes:
  - name: primeiro-emptydir
    emptyDir:
      sizeLimit: "256Mi"

Then, it was mounted in the container via volumeMounts:

volumeMounts:
  - mountPath: /giropops
    name: primeiro-emptydir

We also entered the container, verified the /giropops directory, and created the CORINTHIANS and VAI files to test data writing.

The most important point to remember is that emptyDir follows the Pod’s lifecycle: it survives a container restart, but its data is removed when the Pod ceases to exist.

References

Official documentation

Kubernetes Documentation. Volumes — emptyDir. Available at: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir

Kubernetes Documentation. Configure a Pod to Use a Volume for Storage. Available at: https://kubernetes.io/docs/tasks/configure-pod-container/configure-volume-storage/

Kubernetes Documentation. Ephemeral Volumes. Available at: https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/

Kubernetes Documentation. Local Ephemeral Storage. Available at: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#local-ephemeral-storage

Kubernetes Documentation. Resource Management for Pods and Containers. Available at: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/

Kubernetes Documentation. kubectl apply. Available at: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_apply/

Kubernetes Documentation. kubectl exec. Available at: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_exec/

Kubernetes Documentation. kubectl delete. Available at: https://kubernetes.io/docs/reference/kubectl/generated/kubectl_delete/

Supplemental material

LINUXtips. PICK – Intensive Containers and Kubernetes Program. Available at: https://linuxtips.io/pick/

LINUXtips. Demystifying Kubernetes. Available at: https://linuxtips.io/courses/

What did you think?