[네떡스터디🔥kans] overlay filesystem
CloudNet@ 가시다님이 진행하는 쿠버네티스 네트워크 스터디 KANS 3기 내용을 정리한 글입니다.
OverlayFS 이해하기
Overlay Filesystem은 여러 디렉토리를 하나의 통합된 뷰로 보여주는 Union Mount를 지원하는 파일 시스템 중 하나입니다.
Union Mount를 지원하는 파일시스템에는 AUFS와 OverlayFS가 있습니다.
컨테이너는 프로세스를 격리시키고, 프로세스 실행에 필요한 파일들을 패키징하여 독립된 환경에서 동작할 수 있게 합니다. 그리고 이러한 컨테이너 환경을 효율적으로 관리하는 데 Overlay Filesystem(OverlayFS)이 중요한 역할을 합니다.
OverlayFS는 여러 개의 디렉토리를 하나의 통합된 디렉토리 구조로 보여주는 파일 시스템입니다. 기본적으로 Lower Layer와 Upper Layer로 구성되어 있으며, 이를 합쳐서 Merged Layer로 나타냅니다.

- Lower Layer: 읽기 전용으로 제공되는 기본 파일 시스템입니다. 기본 파일들은 이 레이어에 위치합니다.
- Upper Layer: 읽기/쓰기 가능하며, 이 레이어에 파일을 변경하거나 추가할 수 있습니다. 새로운 파일이나 변경된 파일은 이 상위 레이어에 저장됩니다.
- Merged Layer: 사용자에게 노출되는 최종 파일 시스템으로, 상위 레이어와 하위 레이어의 파일 시스템을 합쳐서 보여줍니다.
작동 방식은 다음과 같습니다
- 읽기: 사용자가 파일을 읽을 때, 상위(upper) 레이어에서 파일이 존재하는지 확인합니다. 만약 존재하지 않으면 하위(Lower) 레이어에서 파일을 찾습니다.
- 쓰기: 사용자가 파일을 수정하거나 새로운 파일을 생성할 때, 상위 레이어에 변경사항이 기록됩니다. 하위 레이어는 읽기 전용이므로 직접적으로 수정되지 않습니다.
overlay 마운트 명령어 예시
lowerdir에 설정된 디렉토리 중 가장 먼저 설정된 디렉토리가 가장 상위 레이어로 작동합니다.
workdir은 copy-up 작업, whiteout 파일 처리 등과 같은 임시 데이터를 저장하는 데 사용됩니다.
실제 통합된 파일 시스템 뷰는 마지막에 지정된 마운트 지점에 나타납니다.
mount -t overlay overlay \
-o lowerdir=/tmp/lowerdir_1:/tmp/lowerdir_2,\
upperdir=/tmp/upperdir,workdir=/tmp/workdir \
/tmp/merged_layer
OverlayFS 사용해보기
먼저 lower 레이어에 해당할 lower 디렉토리와 upper디렉토리 그리고 merge 디렉토리와 메인 work디렉토리를 만듭니다.
mkdir lowerdir_1 lowerdir_2 upperdir workdir merged_layer
lower 폴더에 텍스트 파일을 하나 만들어봅니다.
echo "Hello ~" > lowerdir_1/text.txt
echo "Hi ~" > lowerdir_2/text.txt
그리고 이 디렉토리를 merged_layer에 마운트 해봅시다.

mount -t overlay overlay \
-o lowerdir=/tmp/lowerdir_1:/tmp/lowerdir_2,\
upperdir=/tmp/upperdir,workdir=/tmp/workdir \
/tmp/merged_layer
$ ls -al /tmp/merged_layer/
total 12
drwxr-xr-x 1 root root 4096 Aug 31 21:17 .
drwxrwxrwt 16 root root 4096 Aug 31 21:17 ..
-rw-r--r-- 1 root root 8 Aug 31 21:17 text.txt
merged_layer에 이제 lowerdir_1의 파일이 보입니다.
여기서 text.txt 파일을 읽어봅시다.
$ cat /tmp/merged_layer/text.txt
Hello ~
가장 상위 레이어에 있던 텍스트가 보입니다.
이제 파일을 삭제해봅시다.
$ rm merged_layer/text.txt
$ ls -al merged_layer/
total 8
drwxr-xr-x 1 root root 4096 Aug 31 21:35 .
drwxrwxrwt 16 root root 4096 Aug 31 21:17 ..
다른 폴더들에서 사라졌는지도 확인해보겠습니다.
$ ls -al merged_layer/
total 8
drwxr-xr-x 1 root root 4096 Aug 31 21:35 .
drwxrwxrwt 16 root root 4096 Aug 31 21:17 ..
# merged_layer 안에는 사라졌지만
# lowerdir_1, lowerdir_2에는 계속 남아 있습니다.
$ ls -al lowerdir_1/
total 12
drwxr-xr-x 2 root root 4096 Aug 31 21:17 .
drwxrwxrwt 16 root root 4096 Aug 31 21:17 ..
-rw-r--r-- 1 root root 8 Aug 31 21:17 text.txt
$ ls -al lowerdir_2/
total 12
drwxr-xr-x 2 root root 4096 Aug 31 21:17 .
drwxrwxrwt 16 root root 4096 Aug 31 21:17 ..
-rw-r--r-- 1 root root 5 Aug 31 21:17 text.txt
# workdir에는 work라는 파일이 생겼습니다.
$ ls -al workdir/
total 12
drwxr-xr-x 3 root root 4096 Aug 31 21:25 .
drwxrwxrwt 16 root root 4096 Aug 31 21:17 ..
d--------- 2 root root 4096 Aug 31 21:35 work
# 폴더 구조를 다시 확인해보면 특이한 파일이 하나 생겨있습니다.
# 파일이 삭제된 것을 기록하기 위한 기록입니다.
tree workdir/
workdir/
└── work
└── #d
1 directory, 1 file
중복 된 데이터 없이 도커 이미지 만들기
컨테이너 이미지에서 각각의 레이어는 읽기 레이어에 해당하게 됩니다. 그래서 만약 다음과 같이 이미지를 만들게 된다면 중복된 파일을 갖고있는 컨테이너 이미지를 만들게 됩니다.
FROM ubuntu:20.04
RUN echo "hello ~" > text.txt
RUN echo "hi ~" > text.txt
RUN rm text.txt
위의 내용을 이용하여 컨테이너 이미지를 만들어보도록 합니다.
$ podman build -t overlayfs:test .
STEP 1/4: FROM ubuntu:20.04
Resolved "ubuntu" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
Trying to pull docker.io/library/ubuntu:20.04...
Getting image source signatures
Copying blob 602d8ad51b81 done
Copying config 9df6d6105d done
Writing manifest to image destination
Storing signatures
STEP 2/4: RUN echo "hello ~" > text.txt
--> 5d188bb274e
STEP 3/4: RUN echo "hi ~" > text.txt
--> 76b4059fe08
STEP 4/4: RUN rm text.txt
COMMIT overlayfs:test
--> 7f030571d39
Successfully tagged localhost/overlayfs:test
7f030571d393e60a787a89908b72fd8ab8ca8e5f43b11f891988834cb1822893
이제 이 이미지를 파일로 저장해봅니다.
$ podman save -o overlaytest.tar overlayfs:test
Copying blob 3ec3ded77c0c done
Copying blob 8995c576969f done
Copying blob d0f1723b4570 done
Copying blob 8a17120b9fb8 done
Copying config 7f030571d3 done
Writing manifest to image destination
Storing signatures
이제 이 압축 파일을 해제 해보면 다음과 같이 나옵니다.
RUN을 3번 호출했기 때문에 FROM에서의 1개의 레이어를 더해 총 4개의 레이어 tar파일을 볼 수 있습니다.
$ tree .
.
├── 3ec3ded77c0ce89e931f92aed086b2a2c774a6fbd51617853decc8afa4e1087a.tar
├── 45f6592aca66aa5142e97053226d03ff616cd135f2716666c120c1827365c7f2
│ ├── VERSION
│ ├── json
│ └── layer.tar -> ../3ec3ded77c0ce89e931f92aed086b2a2c774a6fbd51617853decc8afa4e1087a.tar
├── 6ea6dab847c50b86ecac5b4868dd1cbe6333e5ed91c3b6a5bab1fa41e2bffd72
│ ├── VERSION
│ ├── json
│ └── layer.tar -> ../8995c576969fb893c7bb9a0f07e6b8a9feb9479e2835eca0f669093909eb5528.tar
├── 7f030571d393e60a787a89908b72fd8ab8ca8e5f43b11f891988834cb1822893.json
├── 8995c576969fb893c7bb9a0f07e6b8a9feb9479e2835eca0f669093909eb5528.tar
├── 8a17120b9fb86b955af2428345b233e4157ba9cc4a78f72872b7f6baac539112.tar
├── a599a9b2669ea8e1b13a6869a71b33c35fc72943e042fb121d9c776c9d6234af
│ ├── VERSION
│ ├── json
│ └── layer.tar -> ../8a17120b9fb86b955af2428345b233e4157ba9cc4a78f72872b7f6baac539112.tar
├── d0f1723b4570702a13eec88fede4bf2db63a2b7512d09323a5663cf035cb5faa.tar
├── fc736543e77ac932db66ef91cbbbc2ca677fcbba59d858ef3dd34b01abea28d7
│ ├── VERSION
│ ├── json
│ └── layer.tar -> ../d0f1723b4570702a13eec88fede4bf2db63a2b7512d09323a5663cf035cb5faa.tar
├── manifest.json
├── overlaytest.tar
└── repositories
4 directories, 20 files
레이어로 보이는 tar파일을 하나씩 압축을 해제해보면 (ubuntu 레이어는 제외)
$ tree
.
├── 8995c576969fb893c7bb9a0f07e6b8a9feb9479e2835eca0f669093909eb5528
│ ├── etc
│ │ ├── hosts
│ │ └── resolv.conf
│ ├── run
│ └── text.txt
├── 8a17120b9fb86b955af2428345b233e4157ba9cc4a78f72872b7f6baac539112
│ ├── etc
│ │ ├── hosts
│ │ └── resolv.conf
│ └── run
└── d0f1723b4570702a13eec88fede4bf2db63a2b7512d09323a5663cf035cb5faa
├── etc
│ ├── hosts
│ └── resolv.conf
├── run
└── text.txt
실제 이미지를 만들때에는 삭제했던 text.txt 파일로 보이는 파일이 보입니다.
실제로 읽어봐도 만들면서 넣었던 파일이 남아있는것을 볼 수 있습니다.
$ cat 8995c576969fb893c7bb9a0f07e6b8a9feb9479e2835eca0f669093909eb5528/text.txt
hello ~
$ cat d0f1723b4570702a13eec88fede4bf2db63a2b7512d09323a5663cf035cb5faa/text.txt
hi ~
그럼 이젠 남아있지 않도록 변경해보도록 하겠습니다. 이번에는 파일을 만들자마자 삭제 해보도록 하겠습니다.
FROM ubuntu:20.04
RUN echo "hello ~" > text.txt && rm text.txt
RUN echo "hi ~" > text.txt && rm text.txt
다시 이미지를 만들어 봅시다.
$ podman build -t overlayfs:test2 .
STEP 1/3: FROM ubuntu:20.04
STEP 2/3: RUN echo "hello ~" > text.txt && rm text.txt
--> 2c6bbf4b7e9
STEP 3/3: RUN echo "hi ~" > text.txt && rm text.txt
COMMIT overlayfs:test2
--> c9f57746549
Successfully tagged localhost/overlayfs:test2
c9f57746549b3a6ea9375503618787e1aca6a13bafabc80f4454da842e033cae
$ podman save -o overlaytest.tar overlayfs:test2
Copying blob 3ec3ded77c0c done
Copying blob 9eef920632a6 done
Copying blob 9eef920632a6 skipped: already exists
Copying config c9f5774654 done
Writing manifest to image destination
Storing signatures
이번에도 압축을 다시 해제해보면 이전이랑 다르게 RUN이 하나 줄어 레이어로 보이는 폴더가 3개로 보이는 것을 확인할 수 있습니다.
그런데 이번엔 좀 특이한 게 있는데 layer로 보이는 압축파일은 2개밖에 없습니다.
$ tree .
.
├── 317dd9910344baa87719ba7391cfb300fccefa9340823a52c494e613d30b29e0
│ ├── VERSION
│ ├── json
│ └── layer.tar -> ../9eef920632a6adf2db4a8cd3639dfd6ea865ebc2dc3d5f3ff6027bf59d841378.tar
├── 3ec3ded77c0ce89e931f92aed086b2a2c774a6fbd51617853decc8afa4e1087a.tar
├── 45f6592aca66aa5142e97053226d03ff616cd135f2716666c120c1827365c7f2
│ ├── VERSION
│ ├── json
│ └── layer.tar -> ../3ec3ded77c0ce89e931f92aed086b2a2c774a6fbd51617853decc8afa4e1087a.tar
├── 881434b89fc1279dde07d7f9249b08f8813c50bb92f5b608cafa1587e44e2c89
│ ├── VERSION
│ ├── json
│ └── layer.tar -> ../9eef920632a6adf2db4a8cd3639dfd6ea865ebc2dc3d5f3ff6027bf59d841378.tar
├── 9eef920632a6adf2db4a8cd3639dfd6ea865ebc2dc3d5f3ff6027bf59d841378.tar
├── c9f57746549b3a6ea9375503618787e1aca6a13bafabc80f4454da842e033cae.json
├── manifest.json
├── overlaytest.tar
└── repositories
3 directories, 15 files
그리고 그 레이어로 보이는 파일을 한번씩 다시 압축을 해제해서 보면 우선 text.txt 파일이 없는 것을 알 수 있습니다.
9eef920632a6adf2db4a8cd3639dfd6ea865ebc2dc3d5f3ff6027bf59d841378
├── etc
│ ├── hosts
│ └── resolv.conf
└── run
그리고 추가적으로 2개의 레이어가 동일하게 text.txt파일이 없는 최종 결과물(?)이 만들어졌기 때문에
2개의 레이어가 같은 레이어 압축 파일을 참조하고 있는 것을 알 수 있습니다.
효율적으로 컨테이너 이미지를 만들기 위해서는
변경되지 않는 레이어를 하나 만들어 여러 이미지에서 참조할 수 있게 하는 것이 좋습니다. 또한, 불필요한 이미지는 삭제하여 시스템을 깔끔하게 유지하는 것이 중요합니다.