LabHub
배우기 러닝패스 코스

コンテナの内部原理

コンテナを証明する四つのファイル

LabHub 에서 이어서 보기

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

한 줄 요약

커널에 "컨테이너" 라는 자료구조는 없습니다. 대신 프로세스마다 /proc/<pid>/ 아래에 네임스페이스·cgroup·마운트·권한이 적혀 있고, 그 네 파일을 읽으면 그 프로세스가 어떤 격리 안에 있는지 전부 드러납니다.

階層図: 네임스페이스·cgroup·마운트·권한・아이노드 번호・컨테이너 ID 가 들어 있습니다.・이미지 레이어

왜 이게 필요했나

"이 프로세스가 컨테이너 안에 있나요?" 라는 질문에 도커 명령으로 답하려면 도커가 있어야 합니다. 그런데 장애 조사에서 마주치는 상황은 대개 반대입니다 — 호스트에서 ps 를 쳤더니 낯선 프로세스가 CPU 를 먹고 있고, 이게 어느 컨테이너의 것인지, 무엇이 제한돼 있는지 알아야 합니다.

/proc 은 도커·containerd·podman 무엇을 쓰든 똑같이 답해 줍니다. 런타임이 아니라 커널에게 직접 묻는 것이기 때문입니다.

파일 1 — /proc/PID/ns/ : 무엇을 볼 수 있는가

$ ls -l /proc/1/ns/
mnt -> 'mnt:[4026532187]'
net -> 'net:[4026532190]'
pid -> 'pid:[4026532188]'

대괄호 안 숫자가 아이노드 번호이고, 이게 같으면 같은 네임스페이스입니다. 호스트의 /proc/1/ns/net 과 비교해서 다르면 네트워크가 분리된 것이고, 같으면 --network host 로 띄운 것입니다. 컨테이너 두 개를 비교하면 어떤 네임스페이스를 공유하는지도 알 수 있습니다.

파일 2 — /proc/PID/cgroup : 얼마나 쓸 수 있는가

0::/kubepods.slice/kubepods-burstable.slice/.../cri-containerd-9f3c1a....scope

cgroup v2 에서는 한 줄입니다. 이 경로에 컨테이너 ID 가 들어 있습니다. 호스트에서 낯선 프로세스의 정체를 밝힐 때 가장 빠른 길입니다. 그리고 이 경로를 /sys/fs/cgroup/ 아래에서 따라가면 실제 제한값을 읽을 수 있습니다.

/sys/fs/cgroup/<경로>/memory.max      # 메모리 상한
/sys/fs/cgroup/<경로>/memory.current  # 현재 사용량
/sys/fs/cgroup/<경로>/cpu.max         # "200000 100000" = 2 코어

파일 3 — /proc/PID/mountinfo : 파일이 어디서 오는가

컨테이너의 루트 파일시스템은 대개 overlay 입니다.

... / overlay rw,lowerdir=/var/lib/.../l/ABC:/var/lib/.../l/DEF,upperdir=...

lowerdir 에 콜론으로 이어진 목록이 이미지 레이어이고, upperdir 이 컨테이너의 쓰기 레이어입니다. 여기서 볼륨 마운트도 함께 보입니다 — 어떤 호스트 경로가 어디에 붙어 있는지 확인할 때 씁니다.

파일 4 — /proc/PID/status : 무엇을 할 수 있는가

CapEff:	00000000a80425fb
NoNewPrivs:	1
Seccomp:	2

CapEff실효 capability 비트마스크입니다. 0 이면 아무 특권도 없다는 뜻이고, 0000003fffffffff 면 사실상 전부 가진 것 — --privileged 의 흔적 입니다. NoNewPrivs: 1allowPrivilegeEscalation: false 의 결과이고, Seccomp: 2 는 seccomp 필터가 걸려 있다는 뜻입니다.

capsh --decode=00000000a80425fb 로 사람이 읽을 수 있게 풀 수 있습니다.

정리 — 네 파일이 답하는 질문

파일 답하는 질문
ns/ 무엇을 볼 수 있나 (PID·네트워크·마운트 격리)
cgroup 무엇을 얼마나 쓸 수 있나 + 어느 컨테이너인가
mountinfo 파일이 어디서 오나 (레이어·볼륨)
status 무엇을 할 수 있나 (capability·seccomp)

같은 파일들로 답할 수 있는 실제 질문들

/proc 을 읽는 법을 배우면, 도구가 없는 환경에서도 답할 수 있는 질문이 늘어난다. 자주 쓰는 것 넷을 모아 둔다.

"이 두 컨테이너가 네트워크를 공유하나?" — 이름공간의 inode 번호를 비교한다. 같으면 같은 이름공간이다.

readlink /proc/$A/ns/net /proc/$B/ns/net
# net:[4026532567] 이 같으면 같은 네트워크

사이드카가 본체의 네트워크를 못 보는 문제, 임시 컨테이너가 프로세스를 못 보는 문제가 전부 이 한 줄로 확인된다.

"메모리 한도가 정말 걸려 있나?" — cgroup v2 에서는 경로를 따라가 파일을 읽는다.

cat /proc/$PID/cgroup                       # 0::/kubepods/.../<id>
cat /sys/fs/cgroup/kubepods/.../memory.max  # 한도
cat /sys/fs/cgroup/kubepods/.../memory.current
cat /sys/fs/cgroup/kubepods/.../memory.events  # oom_kill 횟수가 여기 있다

memory.eventsoom_kill 이 0이 아니면 그 컨테이너는 이미 한 번 죽었다. 파드가 재시작한 이유를 찾을 때 가장 먼저 볼 자리다.

"이 파일이 어디서 왔나?"mountinfo 를 보면 볼륨이 실제로 어디에 붙었고 읽기 전용인지가 나온다. ConfigMap 이 갱신되지 않는 문제(심볼릭 링크로 마운트되는 구조)가 여기서 드러난다.

grep -E ' /etc/config | /data ' /proc/$PID/mountinfo

"이 프로세스가 무엇을 할 수 있나?"statusCapEff 를 사람이 읽을 수 있게 푼다.

grep CapEff /proc/$PID/status
capsh --decode=00000000a80425fb

CapEff0000000000000000 이면 권한을 전부 버린 것이고, 그것이 우리가 원하는 상태다. 반대로 0000003fffffffff 가 보이면 그 컨테이너는 사실상 특권 모드로 돌고 있다.

호스트에서 컨테이너를 찾는 반대 방향도 자주 쓴다. 호스트에서 CPU 를 많이 쓰는 프로세스를 발견했을 때, 그것이 어느 파드인지는 cgroup 경로에 적혀 있다.

현장에서 만나는 모습

다음 확인에서 볼 것

이어지는 퀴즈에서는 /proc의 네임스페이스 아이노드, cgroup 경로·제한, capability 비트마스크가 각각 무엇을 증명하는지 확인합니다. 앞 실습에서 읽은 커널 값과 문서상의 컨테이너 설정을 구분해 답해 보세요.