LabHub
배우기 러닝패스 코스

ストレージとマウント

マウント名前空間と伝播の方式

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

한 줄 요약

/proc/self/mountinfo 는 "이 프로세스가 보는 마운트 트리 전체"를 담고 있고, 거기에는 mount 명령이 보여 주지 않는 전파 방식(propagation) 까지 적혀 있다.

概念マップ: 전파 방식(propagation)・마운트 네임스페이스와 전파 방식・원본 안에서의 루트・선택 필드 — 전파 방식

왜 이게 필요했나

컨테이너를 쓰기 시작하면 마운트가 갑자기 어려워진다. 호스트에서 붙인 볼륨이 컨테이너에 안 보이거나, 컨테이너 안에서 붙인 것이 호스트로 새거나, 컨테이너를 지웠는데 마운트가 남아 있다. 이 현상들은 전부 마운트 네임스페이스와 전파 방식으로 설명된다.

어떻게 동작하나

mountinfo 읽기

36 25 0:31 / /sys/fs/cgroup rw,nosuid,nodev,noexec shared:9 - cgroup2 cgroup2 rw
[1][2][3] [4]    [5]              [6]                [7]   [8]  [9]     [10]  [11]
필드 의미
1 마운트 ID
2 부모 마운트 ID
3 major:minor 장치 번호
4 원본 안에서의 루트 — 바인드 마운트면 여기가 / 가 아니다
5 마운트 지점
6 마운트 옵션
7 선택 필드 — 전파 방식 (shared:, master:, propagate_from:, 없으면 private)
8 구분자 -
9~11 파일시스템 타입, 소스, 상위 옵션

4번 필드가 바인드 마운트를 식별하는 열쇠다. 같은 장치의 하위 디렉터리를 붙였다면 거기에 / 대신 그 하위 경로가 적힌다.

전파 방식 네 가지

방식 mountinfo 표시 동작
private (표시 없음) 이 마운트의 변화가 아무 데도 전파되지 않는다
shared shared:N 양방향 전파. 여기서 붙이면 짝에게도 보이고 반대도 마찬가지
slave master:N 단방향. 마스터의 변화는 받지만 내 변화는 안 보낸다
unbindable unbindable 바인드 마운트의 원본이 될 수 없다

컨테이너 런타임이 볼륨을 붙일 때 rslaverprivate 를 쓰는 이유가 여기 있다. 컨테이너 안에서 실수로 붙인 마운트가 호스트로 새면 곤란하고, 반대로 호스트가 붙인 것은 보여야 하는 경우가 많다.

tmpfs

메모리 위의 파일시스템이다. 재부팅하면 사라진다.

tmpfs  /var/cache/app  tmpfs  size=256M,mode=1777,noexec,nosuid,nodev  0  0

systemd 의 .mount 유닛

fstab 대신 유닛 파일로도 마운트를 정의할 수 있다. 유닛 이름은 마운트 지점 경로를 이스케이프한 것이어야 한다.

# /etc/systemd/system/var-cache-app.mount
[Unit]
Description=Application cache (tmpfs)

[Mount]
What=tmpfs
Where=/var/cache/app
Type=tmpfs
Options=size=256M,mode=1777,noexec,nosuid,nodev

[Install]
WantedBy=local-fs.target

/var/cache/appvar-cache-app.mount. 앞의 슬래시는 빼고, 나머지 슬래시는 하이픈으로 바꾼다. 이름이 경로와 안 맞으면 systemd 가 유닛을 거부한다. systemd-escape --path /var/cache/app 로 정확한 이름을 얻을 수 있다.

마운트가 사라지거나 안 보일 때

바인드 마운트와 tmpfs 는 단순해 보이는데, 전파와 이름공간 때문에 예상과 다르게 동작하는 경우가 있다.

컨테이너 안에서 나중에 붙인 마운트가 안 보인다. 호스트에서 /mnt/data 에 새 디스크를 마운트해도, 이미 그 경로를 바인드해 둔 컨테이너에는 안 나타난다. 전파 방식이 private 이면 이후의 마운트가 전달되지 않기 때문이다. 쿠버네티스에서 mountPropagation: HostToContainer 를 쓰는 이유가 이것이다.

findmnt -o TARGET,SOURCE,PROPAGATION /mnt/data

tmpfs 는 메모리를 쓴다. df 에는 파일 시스템으로 보이지만 실제로는 RAM 이고, 컨테이너에서는 그 메모리가 cgroup 한도에 포함된다. /tmp 를 tmpfs 로 두고 큰 파일을 쓰면 OOM 으로 죽는다. 크기를 반드시 정한다.

tmpfs /tmp tmpfs size=512M,mode=1777,nosuid,nodev 0 0

빈 디렉터리에 마운트하지 않으면 원래 내용이 가려진다. 그 파일들은 사라진 것이 아니라 밑에 깔린 채 공간을 차지한다. 되찾으려면 마운트를 걷거나 다른 곳에 바인드해서 본다.

mkdir /mnt/under && mount --bind / /mnt/under
ls /mnt/under/mnt/data       # 가려진 원래 내용

umount 가 안 될 때는 누가 쓰고 있는지 본다.

lsof +f -- /mnt/data
fuser -vm /mnt/data
umount -l /mnt/data          # 마지막 수단: 이름만 떼고 나중에 정리한다

-l(lazy)은 열려 있는 파일이 닫힐 때까지 실제로는 붙어 있으므로, 디스크를 물리적으로 빼는 상황에서는 안전하지 않다.

바인드 마운트에 걸린 옵션은 두 번 걸어야 한다. mount --bind -o ro 는 리눅스에서 읽기 전용이 되지 않는다. 붙인 뒤에 다시 걸어야 한다.

mount --bind /src /dst
mount -o remount,ro,bind /dst

현장에서 만나는 모습

컨테이너를 지웠는데 마운트가 남는다. 전파 방식이 shared 인 상태에서 컨테이너가 마운트를 만들면 호스트 네임스페이스로 새어 나온다. 컨테이너가 죽어도 그 마운트는 호스트에 남아 디스크를 붙잡는다. findmnt 로 찾아 수동으로 정리해야 한다.

tmpfs 크기를 안 정해 OOM 이 난다. size= 없이 만든 tmpfs 에 로그가 쌓여 메모리를 다 먹었다. 디스크가 아니라 메모리라는 사실을 잊기 쉽다.

다음 실습에서 할 것

/proc/self/mountinfo 를 직접 파싱해 마운트 트리와 전파 방식을 표로 만들고, 바인드 마운트와 tmpfs 의 fstab 줄을 작성하고, .mount 유닛 파일을 정확한 이름으로 만든다.