[Kubernetes] Pod 볼륨 - 2. emptyDir
Kubernetes in Action 2nd Edition 9장의 학습 내용을 기반으로 합니다.
TL;DR
emptyDir은 Pod와 수명 주기를 같이 하는 임시 볼륨으로, 빈 디렉토리로 시작한다- 컨테이너가 재생성(recreate)되어도 같은 Pod 내에서 emptyDir의 데이터는 유지된다. Pod가 삭제되면 데이터도 사라진다
- init 컨테이너를 사용해 emptyDir 볼륨에 초기 데이터를 채울 수 있다
- 동일한 emptyDir 볼륨을 여러 컨테이너에 마운트하여 파일을 공유할 수 있다
medium: Memory설정으로 tmpfs(메모리 기반) 볼륨을 생성할 수 있다
emptyDir 볼륨 개요
가장 단순한 볼륨 타입인 emptyDir은 Pod와 수명 주기를 같이 하는 임시 볼륨이다.
- 이름에서 알 수 있듯이 빈 디렉토리로 시작한다
medium을Memory로 설정하면 데이터를 디스크 대신 메모리(tmpfs)에 저장할 수 있다- 컨테이너에 마운트되면 볼륨에 작성된 파일은 Pod가 존재하는 동안 보존되나, 다른 Pod와는 공유할 수 없다
이 볼륨 타입은 다음 상황에서 사용된다.
- 단일 컨테이너 Pod에서 컨테이너가 재시작되더라도 데이터를 보존해야 하는 경우
- 컨테이너의 파일시스템이 읽기 전용으로 설정되었지만 임시로 데이터를 쓸 공간이 필요한 경우
- 두 개 이상의 컨테이너를 가진 Pod에서 컨테이너 간 데이터를 공유하는 경우
컨테이너 재시작 간 파일 유지
이전 글에서 만든 quiz Pod에 emptyDir 볼륨을 추가하여, MongoDB 컨테이너가 재시작될 때 데이터가 손실되지 않도록 만든다.
Pod에 emptyDir 볼륨 추가하기

quiz-data라는 이름의 emptyDir 볼륨을 spec.volumes에 정의하고, mongo 컨테이너의 /data/db에 마운트한다.
# pod.quiz.emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
name: quiz
spec:
volumes:
- name: quiz-data
emptyDir: {}
containers:
- name: quiz-api
image: luksa/quiz-api:0.1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
- name: mongo
image: mongo:7
volumeMounts:
- name: quiz-data
mountPath: /data/db
emptyDir 볼륨 설정
emptyDir 볼륨 타입은 두 가지 설정 필드를 지원한다.
| 필드 | 설명 |
|---|---|
medium |
스토리지 매체 타입. 비워두면 호스트 노드의 기본 디스크를 사용한다. Memory로 설정하면 tmpfs(메모리 기반 파일시스템)를 사용한다 |
sizeLimit |
볼륨의 최대 크기 제한. 예: 10Mi |
두 필드 모두 선택 사항이다. emptyDir: {}는 “두 필드 모두 기본값을 사용하겠다”는 의미로, 저장 매체는 노드의 디스크, 크기 제한은 없음이다. YAML에서는 emptyDir:만 쓰고 {}를 생략해도 동일하게 동작한다.
emptyDir 볼륨의 수명
문제를 추가한 후 MongoDB 컨테이너를 종료시키고 데이터가 유지되는지 확인한다.
kubectl apply -f pod.quiz.emptydir.yaml
# 문제 추가
./insert-question.sh
# 컨테이너 강제 종료
kubectl exec -it quiz -c mongo -- mongosh admin --eval "db.shutdownServer()"
# command terminated with exit code 137
# 데이터 확인 → 1건 유지!
kubectl exec -it quiz -c mongo -- mongosh kiada --quiet --eval "db.questions.countDocuments()"
# 1
컨테이너를 재시작해도 더 이상 파일이 사라지지 않는다. 파일이 컨테이너의 파일시스템이 아닌 볼륨에 저장되기 때문이다.
emptyDir 볼륨의 파일 저장 위치

emptyDir 볼륨의 파일은 호스트 노드의 파일시스템에 있는 디렉토리에 저장된다. 일반적으로 다음 위치에 있다.
/var/lib/kubelet/pods/<pod_UID>/volumes/kubernetes.io~empty-dir/<volume_name>
# Pod UID 확인 후 호스트에서 emptyDir 확인
docker exec -it kind-control-plane ls -al \
/var/lib/kubelet/pods/$(kubectl get pod quiz -o jsonpath='{.metadata.uid}')/volumes/kubernetes.io~empty-dir/quiz-data/
출력 결과
total 360
drwxrwxrwx 5 999 root 4096 Mar 31 16:38 .
drwxr-xr-x 3 root root 4096 Mar 31 16:31 ..
drwx------ 3 999 root 4096 Mar 31 16:31 .mongodb
-rw------- 1 999 systemd-journal 50 Mar 31 16:31 WiredTiger
-rw------- 1 999 systemd-journal 21 Mar 31 16:31 WiredTiger.lock
-rw------- 1 999 systemd-journal 1468 Mar 31 16:38 WiredTiger.turtle
-rw------- 1 999 systemd-journal 77824 Mar 31 16:38 WiredTiger.wt
...
-rw------- 1 999 systemd-journal 114 Mar 31 16:31 storage.bson
MongoDB WiredTiger 스토리지 엔진 파일이 확인된다. 이 파일들이 emptyDir 볼륨을 통해 노드의 디스크에 실제로 저장된 것이다. Pod가 삭제되면 이 디렉토리도 함께 지워진다.
kubectl delete po quiz
# Pod 삭제 후 → 디렉토리도 사라짐
docker exec -it kind-control-plane ls -al \
/var/lib/kubelet/pods/$(kubectl get pod quiz -o jsonpath='{.metadata.uid}')/volumes/kubernetes.io~empty-dir/quiz-data/
# Error from server (NotFound): pods "quiz" not found
데이터는 컨테이너 재시작 시에는 유지되지만, Pod가 삭제되면 유지되지 않는다. 데이터를 제대로 영속화하려면 퍼시스턴트 볼륨(persistent volume)을 사용해야 한다.
메모리에 emptyDir 볼륨 생성하기
볼륨의 I/O 성능을 최대한 빠르게 하거나 민감한 데이터를 저장할 때는, tmpfs 파일시스템을 사용하여 파일을 메모리에 저장할 수 있다. medium 필드를 Memory로 설정한다.
volumes:
- name: content
emptyDir:
medium: Memory
데이터가 디스크에 기록되지 않으므로, 데이터가 유출되거나 원하는 것보다 오래 유지될 가능성이 줄어든다. Kubernetes는 Secret 오브젝트의 데이터를 컨테이너에 노출할 때도 동일한 인메모리 방식을 사용한다.
인메모리 볼륨의 크기는 sizeLimit 필드로 제한할 수 있으며, 특히 Pod의 전체 메모리 사용량이 리소스 제한(resource limits)에 의해 제한되는 경우에 중요하다.
emptyDir 볼륨 초기화
emptyDir 볼륨은 항상 비어 있으므로, init 컨테이너를 사용해 Pod 시작 시 자동으로 데이터를 채울 수 있다.
init 컨테이너로 emptyDir 볼륨 초기화하기

quiz 문제를 JSON 파일에 저장하고, init 컨테이너가 이 파일을 공유 볼륨에 복사하여 MongoDB가 시작할 때 읽을 수 있도록 한다. MongoDB의 /docker-entrypoint-initdb.d/ 메커니즘을 활용한다. 이 디렉토리에 .js 파일을 넣으면 MongoDB가 첫 시작 시 자동으로 실행한다.
# pod.quiz.emptydir.init.yaml
apiVersion: v1
kind: Pod
metadata:
name: quiz
spec:
volumes:
- name: initdb
emptyDir: {}
- name: quiz-data
emptyDir: {}
initContainers:
- name: installer
image: luksa/quiz-initdb-script-installer:0.1
imagePullPolicy: IfNotPresent
volumeMounts:
- name: initdb
mountPath: /initdb.d
containers:
- name: quiz-api
image: luksa/quiz-api:0.1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
- name: mongo
image: mongo:7
volumeMounts:
- name: quiz-data
mountPath: /data/db
- name: initdb
mountPath: /docker-entrypoint-initdb.d/
readOnly: true
Pod가 시작되면 먼저 볼륨이 생성된 후 init 컨테이너가 시작된다. init 컨테이너가 insert-questions.js 파일을 initdb 볼륨에 복사한 후 종료되면, 메인 컨테이너들이 시작된다. initdb 볼륨이 mongo 컨테이너의 /docker-entrypoint-initdb.d/에 마운트되어 있으므로, MongoDB가 .js 파일을 실행하여 데이터베이스에 문제를 삽입한다.
kubectl apply -f pod.quiz.emptydir.init.yaml
kubectl exec -it quiz -c mongo -- mongosh kiada --quiet --eval "db.questions.countDocuments()"
# 6
인라인 방식으로 볼륨 초기화하기
짧은 파일로 emptyDir 볼륨을 초기화하고 싶을 때는 파일 내용을 Pod 매니페스트에 직접 정의할 수 있다.
# pod.demo-emptydir-inline.yaml
apiVersion: v1
kind: Pod
metadata:
name: demo-emptydir-inline
spec:
volumes:
- name: my-volume
emptyDir: {}
initContainers:
- name: my-volume-initializer
image: busybox
command:
- sh
- -c
- |
cat <<EOF > /mnt/my-volume/my-file.txt
line 1: This is a multi-line file
line 2: Written from an init container
line 3: Defined inline in the Pod manifest
EOF
volumeMounts:
- name: my-volume
mountPath: /mnt/my-volume
containers:
- name: main
image: busybox
command: ["sh", "-c", "cat /app/my-file.txt && sleep infinity"]
volumeMounts:
- name: my-volume
mountPath: /app
ConfigMap이나 별도 리소스 없이도 어플리케이션에 짧은 설정 파일을 제공할 수 있는 간편한 방법이다.
컨테이너 간 파일 공유
emptyDir 볼륨을 여러 메인 컨테이너에 동시에 마운트하여 파일을 공유할 수 있다.
quote Pod를 멀티 컨테이너 Pod로 변환
이전 장에서 fortune 커맨드를 실행하기 위해 post-start hook을 사용했던 quote Pod를 변경한다. Nginx는 웹 서버로 유지하되, post-start hook을 매분 새 quote를 생성하는 quote-writer 컨테이너로 대체한다.

# pod.quote.yaml
apiVersion: v1
kind: Pod
metadata:
name: quote
spec:
volumes:
- name: shared
emptyDir: {}
containers:
- name: quote-writer
image: luksa/quote-writer:0.1
imagePullPolicy: IfNotPresent
volumeMounts:
- name: shared
mountPath: /var/local/output
- name: nginx
image: nginx:alpine
volumeMounts:
- name: shared
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- name: http
containerPort: 80
quote-writer컨테이너:/var/local/output에 quote 파일을 쓴다nginx컨테이너:/usr/share/nginx/html에서 파일을 제공한다. 읽기 전용으로 마운트되어 있다
동일한 볼륨이 각 컨테이너에 서로 다른 경로로 마운트된다. 보안상 nginx가 볼륨에 쓰기를 하지 못하도록 readOnly: true로 설정하는 것이 좋다.
kubectl apply -f pod.quote.yaml
kubectl port-forward pod/quote 1080:80
curl localhost:1080/quote
Note: 두 컨테이너는 동시에 시작되므로, nginx는 이미 실행 중인데 quote가 아직 생성되지 않은 짧은 기간이 발생할 수 있다. 이를 방지하려면 init 컨테이너(또는 네이티브 사이드카의
restartPolicy: Always)를 사용해 초기 quote를 미리 생성하면 된다.
emptyDir 사용 사례
사이드카 간 파일 공유 (CKA 빈출)
apiVersion: apps/v1
kind: Deployment
metadata:
name: logging-deployment
spec:
replicas: 1
selector:
matchLabels:
app: logger
template:
metadata:
labels:
app: logger
spec:
volumes:
- name: log-volume
emptyDir: {}
initContainers:
- name: log-agent
image: busybox
command: ["sh", "-c", "touch /var/log/app/app.log; tail -f /var/log/app/app.log"]
volumeMounts:
- name: log-volume
mountPath: /var/log/app
restartPolicy: Always
containers:
- name: app-container
image: busybox
command: ["sh", "-c", "while true; do echo 'Log entry' >> /var/log/app/app.log; sleep 5; done"]
volumeMounts:
- name: log-volume
mountPath: /var/log/app
ML 워크로드: /dev/shm 확장
PyTorch DataLoader의 num_workers > 0 설정 시 shared memory가 부족하면 에러가 발생한다. emptyDir 타입 볼륨으로 /dev/shm을 확장하여 해결한다.
containers:
- name: model-trainer
image: sirzzang/mlops:model-trainer-0.0.1
volumeMounts:
- mountPath: /dev/shm
name: shm-empty-dir
volumes:
- emptyDir:
medium: Memory
sizeLimit: 2Gi
name: shm-empty-dir
ML 모델 서빙: init 컨테이너 + emptyDir
init 컨테이너가 MinIO에서 모델 파일을 다운로드하여 emptyDir에 저장하고, 메인 컨테이너가 이를 읽기 전용으로 마운트하여 서빙하는 패턴이다.
initContainers:
- name: model-downloader
image: minio/mc:latest
command: ["/bin/sh", "-c"]
args:
- |
mc alias set myminio $MINIO_ENDPOINT $MINIO_ACCESS_KEY $MINIO_SECRET_KEY
mc cp myminio/${MINIO_BUCKET}/${MINIO_OBJECT_PATH} /models/model.pth
volumeMounts:
- name: model-storage
mountPath: /models
containers:
- name: inference-server
image: my-inference:latest
env:
- name: MODEL_PATH
value: "/models/model.pth"
volumeMounts:
- name: model-storage
mountPath: /models
readOnly: true
resources:
limits:
nvidia.com/gpu: 1
volumes:
- name: model-storage
emptyDir: {}
정리
emptyDir은 가장 단순한 볼륨 타입으로, 빈 디렉토리로 시작하여 Pod의 수명 동안 데이터를 저장한다- 컨테이너 재생성(recreate) 시에도 emptyDir의 데이터는 유지되지만, Pod가 삭제되면 함께 사라진다
medium: Memory로 tmpfs 볼륨을 생성하면 I/O 성능이 향상되고, 민감한 데이터 저장에도 적합하다- init 컨테이너를 사용해 emptyDir 볼륨에 초기 데이터를 채울 수 있다. MongoDB의
/docker-entrypoint-initdb.d/같은 메커니즘과 잘 어울린다 - 동일한 emptyDir 볼륨을 여러 컨테이너에 마운트하면 사이드카 패턴, 로그 공유, ML 워크로드 등 다양한 시나리오에서 활용할 수 있다
이전 포스트: Pod 볼륨 - 1. 볼륨 소개
다음 포스트: Pod 볼륨 - 3. image 볼륨과 hostPath
댓글남기기