컨테이너 런타임 레이어
레이어 정리
우리가 일상에서 컨테이너를 띄우는 것은 아주 고수준의 레이어인 docker 커맨드(cli)를 사용해서 띄우게 된다
하지만 hostOS의 cgroup을 조절하고 namespace를 설정하는 건 마법처럼 뚝딱되는 것이 아니다
컨테이너가 실행되기까지 여러 레이러를 거치는데 각 레이어가 무슨역할을 하는지 정리해본다
bash
사용자 / 오케스트레이터 (docker, nerdctl)
↓
high-level runtime (containerd, CRI-O)
↓
shim (containerd-shim-runc-v2)
↓
OCI runtime (runc, crun)
↓
Linux kernelhigh-level runtime: 이미지 pull, 스토리지, 네트워크 조율을 담당한다. 이미지를 rootfs + config.json으로 구성된 OCI bundle로 변환해서 shim을 통해 OCI runtime(runc)에 넘긴다.
shim은 containerd 같은 하이레벨 런타임이 죽어도 컨테이너가 유지되도록 분리해주는 역할을 한다.
- 컨테이너 프로세스의 부모역할을 맡게 되는데, 만약 containerd 가 컨테이너들을 자식 프로세스로 지니고 있으면 containerd가 죽고나서 관리가 안된다
bash
# shim이 없을 경우
containerd 죽음
→ 컨테이너 프로세스는 살아있음
→ 근데 exit code를 수거할 놈이 없음
→ stdio 연결이 끊김
→ 다시 살아난 containerd가 컨테이너 상태를 모름
# shim이 중간에 있으면?
containerd 죽음
→ shim은 살아있음
→ 컨테이너 프로세스의 부모 = shim
→ exit code, stdio 다 shim이 들고 있음
→ containerd 재시작 후 shim에 다시 연결
→ 컨테이너 상태 복구 가능그 밑에 레이어가 OCI runtime 이다 (편하게 runc라고함)
runc는 OCI Runtime Spec에 정의된 5개의 operation을 구현한다
bash
create → namespace, cgroup 설정. 프로세스는 블로킹 상태
start → exec()으로 실제 프로세스 실행
state → 현재 상태 JSON 출력
kill → 시그널 전송
delete → 리소스 정리- start 후 runc는 종료된다. runc는 컨테이너를 띄우는 역할까지만 하고, 이후 컨테이너 프로세스의 부모는 shim이 맡는다.
bash
runc create → namespace, cgroup 설정. 프로세스 블로킹
runc start → exec()으로 실제 프로세스 실행
runc exits → runc 프로세스 자체는 종료
이후 컨테이너 프로세스의 부모 = shimrunc는 리눅스 커널이 제공하는 기능들을 syscall로 호출하여 격리 환경을 구성한다.
bash
namespaces → 프로세스 격리
cgroups → 리소스 제한
seccomp → syscall 필터링
capabilities → root 권한 세분화