Kubernetes has a simple volume type called emptydir where it asks the node to spare a disks that mounted on runtime. This type of volume really useful to store temporary files, logs, etc. This volume “survive” on container restarts, but removed on pod removal, makes it helpful for persisting data across restart process, without consumimg unnecessary disks.
But things gets more interesting afterward. Imagine a workload that runs as Kubernetes Job, then suddenly failing / misbehaving and we need to check the temporary files that its produces to emptyDir. Sure, mounting PVC could be one way to solve this, but it adds another layer just for debugging purposes.
Based on the https://kubernetes.io/docs/concepts/storage/volumes/#emptydir emptydir contents will persist as long as the pod is available on the node. This mechanism also works for popular tools like fluentd/fluentbit as log collector, etc. So I wonder, is it possible to retrieve emptyDir content when the pod hasn’t been removed, but not in running state, for example on Completed, or Error state. Technically the pod is still there, isn’t it? because we still able to get the pod using kubectl get pod.
Preparation
I start to simply create a k8s cluster using K3D, spin up very minimal cluster to run 2 main pods. 1 pod will be the target, where the pod will mount an emptyDir, write file to it, then exit. Another pod will be the fetch where it mainly used for manual retriving from target pod emptyDir.
Experiments
At first, we need to understand how emptyDir works. Basically when a pod with emptyDir scheduled on a node, it will be mounted as container mount from a path on the host. The host path location for empytDir are constructed in /var/lib/kubelet/pods/{containerID}/volumes/kubernetes.io~empty-dir/{volume name}. Logically, running another pod on the same node with hostPath volume, targeting that path should be enable us to retrieve the data.
Here are simple target pod and fetch pod declaration
apiVersion: v1
kind: Pod
metadata:
name: target
labels:
name: target
spec:
containers:
- name: target
image: busybox
command:
- sh
args:
- -c
- echo "hey! please retrieve me" > /target/output.txt && ls -al /target && sleep 30 && exit 1 # This could simulate the pod states into Error, or Completed. Remove the exit command to make it Completed instead of Error
resources:
limits:
memory: "128Mi"
cpu: "500m"
volumeMounts:
- name: target-output
mountPath: /target
restartPolicy: Never # To ensure that the pod in Error / Completed state, not CrashloopBack
terminationGracePeriodSeconds: 0
nodeName: k3d-local-agent-0
volumes:
- name: target-output
emptyDir: {}
apiVersion: v1
kind: Pod
metadata:
name: fetch
labels:
name: fetch
spec:
containers:
- name: target
image: bash
command:
- tail
args:
- -f
- /dev/null
resources:
limits:
memory: "128Mi"
cpu: "500m"
volumeMounts:
- name: fetch-target
mountPath: /target
# hostPath best practices to configure it as readOnly.
readOnly: true
restartPolicy: Never
terminationGracePeriodSeconds: 0
nodeName: k3d-local-agent-0
volumes:
- name: fetch-target
hostPath:
# mounting the root of pods directory so we could handle the dynamic pod id to explore
path: /var/lib/kubelet/pods
type: Directory
Completed pod
when runs the target, configure it to write files into emptyDir and exit 0, the pod will be in Completed state. Try fetching it via fetch pod, the files is empty :(
Error pod
Very similar story with Completed pod, the directory is empty when mounted on fetch pod.
CrashloopBack pod
Changing the pod restart policy to Always, changes the end state results from Error to CrashloopBack. On this state, the files persist and we could retrieve the emptydir content via kubectl cp for example.