LabHub

컨테이너 내부 원리 · cgroup — 얼마나 쓸 수 있는가 · 실습

제한을 걸고 관측값과 대조하기

LabHub 에서 이어서 보기

이 실습은 진짜 VM 에서 돕니다

이 상자는 파드가 아니라 KubeVirt 가 띄운 가상머신입니다. 리눅스 커널이
따로 돌고 systemd 가 실제로 서비스를 관리하며, docker 는 흉내가 아니라
진짜 도커 엔진입니다. docker run 으로 띄운 컨테이너는 실제로 프로세스가
되고 docker execdocker logs 도 그대로 동작합니다.

예전에는 이 실습이 파드 안에서 돌았습니다. 커널 권한을 전부 내려놓은 상자라
컨테이너를 띄우는 단계가 막혀 있었고, 그래서 이미지 아카이브를 직접 풀어
보는 우회로 배웠습니다. 이제 우회가 필요 없습니다.

알아 둘 것이 둘 있습니다.

목표

메모리·CPU·PID 한도를 직접 걸어 보고, 요청한 값(docker inspect 의 HostConfig)과
컨테이너가 실제로 보는 값(/sys/fs/cgroup/*)을 나란히 놓고 비교합니다.
종료코드 137 을 직접 만들어 보고 OOM 킬과 구분하는 법을 정리합니다.

왜 중요한가

운영에서 나오는 질문은 거의 항상 "제한을 걸었는데 왜 안 지켜지죠"이거나
"CPU 는 한가한데 왜 느리죠"입니다. 첫 번째는 요청값과 강제값이 다를 수 있다는
것(rootless 환경에서는 systemd delegation 이 없으면 요청만 기록됩니다)을 몰라서
생기고, 두 번째는 CPU cgroup 이 프로세스를 죽이지 않고 재운다는 것을 몰라서
생깁니다. 그리고 둘 다 docker stats 나 대시보드가 아니라 cgroup 파일을 직접
읽어야 확정됩니다. 그래서 이 실습은 값을 두 군데서 읽어 대조하는 습관을
만드는 것이 목적입니다. 하나만 읽으면 반드시 틀린 결론에 도달합니다.

단계

1. /root/int2 디렉터리를 만들고, stat -fc %T /sys/fs/cgroup 의 출력을 그대로 /root/int2/version.txt 에 저장합니다 (cgroup2fs 면 v2, tmpfs 면 v1).
2. /sys/fs/cgroup/cgroup.controllers 파일 내용을 그대로 /root/int2/controllers.txt 에 저장합니다.
3. alpine:3.20 이미지로 dk-mem 컨테이너를 메모리 한도 64MiB(67108864 바이트) 로 걸어 백그라운드 실행합니다. 채점 시점에 계속 running 상태여야 합니다.
4. dk-mem 안에서 /sys/fs/cgroup/memory.max 를 읽어 그 값을 그대로 /root/int2/memmax.txt 에 저장합니다.
5. alpine:3.20 이미지로 dk-cpu 컨테이너를 CPU 0.5 코어 한도로 걸어 백그라운드 실행합니다.
6. dk-killed 컨테이너를 띄운 뒤 직접 SIGKILL 을 보내 종료코드 137 로 끝냅니다(OOM 이 아니어야 합니다). 그리고 /root/int2/exit137.txt 에 137 이 128 + 9 로 이루어진다는 분해와, OOM 킬도 같은 137 을 낸다는 점을 함께 적습니다.
7. alpine:3.20 이미지로 dk-pids 컨테이너를 PID 한도 64 로 걸어 실행합니다.
8. /root/int2/limits.md 에 세 행을 적습니다. dk-mem 행에는 실제 바이트 값 67108864 를, dk-cpu 행에는 0.5(또는 500m)를, dk-pids 행에는 64 를 포함시킵니다.

참고

단계 8개

  1. cgroup 버전 판별
  2. 사용 가능한 컨트롤러 목록
  3. 메모리 한도 64MiB 요청하기
  4. 컨테이너가 실제로 보는 memory.max
  5. CPU 0.5 코어 한도
  6. 종료코드 137 만들고 해석하기
  7. PID 한도로 포크 폭탄 막기
  8. 제한 요약표 작성