K8S/🔥 network study🔥

[네떡스터디🔥kans] overlay filesystem

아야는 못말려 2024. 8. 31. 02:33
CloudNet@ 가시다님이 진행하는 쿠버네티스 네트워크 스터디 KANS 3기 내용을 정리한 글입니다.

 

OverlayFS 이해하기

Overlay Filesystem은 여러 디렉토리를 하나의 통합된 뷰로 보여주는 Union Mount를 지원하는 파일 시스템 중 하나입니다.
Union Mount를 지원하는 파일시스템에는 AUFS와 OverlayFS가 있습니다. 

 

 

컨테이너는 프로세스를 격리시키고, 프로세스 실행에 필요한 파일들을 패키징하여 독립된 환경에서 동작할 수 있게 합니다. 그리고 이러한 컨테이너 환경을 효율적으로 관리하는 데 Overlay Filesystem(OverlayFS)이 중요한 역할을 합니다.

 

https://jvns.ca/blog/2019/11/18/how-containers-work--overlayfs/

 

OverlayFS는 여러 개의 디렉토리를 하나의 통합된 디렉토리 구조로 보여주는 파일 시스템입니다. 기본적으로 Lower LayerUpper Layer로 구성되어 있으며, 이를 합쳐서 Merged Layer로 나타냅니다.

 

 

  • Lower Layer: 읽기 전용으로 제공되는 기본 파일 시스템입니다. 기본 파일들은 이 레이어에 위치합니다.
  • Upper Layer: 읽기/쓰기 가능하며, 이 레이어에 파일을 변경하거나 추가할 수 있습니다. 새로운 파일이나 변경된 파일은 이 상위 레이어에 저장됩니다.
  • Merged Layer: 사용자에게 노출되는 최종 파일 시스템으로, 상위 레이어와 하위 레이어의 파일 시스템을 합쳐서 보여줍니다.

작동 방식은 다음과 같습니다

  1. 읽기: 사용자가 파일을 읽을 때, 상위(upper) 레이어에서 파일이 존재하는지 확인합니다. 만약 존재하지 않으면 하위(Lower) 레이어에서 파일을 찾습니다.
  2. 쓰기: 사용자가 파일을 수정하거나 새로운 파일을 생성할 때, 상위 레이어에 변경사항이 기록됩니다. 하위 레이어는 읽기 전용이므로 직접적으로 수정되지 않습니다.

 

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개의 레이어가 같은 레이어 압축 파일을 참조하고 있는 것을 알 수 있습니다.

 

효율적으로 컨테이너 이미지를 만들기 위해서는

변경되지 않는 레이어를 하나 만들어 여러 이미지에서 참조할 수 있게 하는 것이 좋습니다. 또한, 불필요한 이미지는 삭제하여 시스템을 깔끔하게 유지하는 것이 중요합니다.