containerd의 역할
컨테이너를 실행한다라는 것은 무엇일까 많이 설명이 컨테이너 = 격리된 프로세스에서 멈추는데 이 말은 반만 맞다.
컨테이너 실행에는 다음이 동시에 성립되어야 한다.
- 어떤 프로세스를 실행할 것인가
- 어떤 파일시스템 위에서 실행할 것인가
- 어느 네임스페이스에 속하게할 것인가
- 어느 리소스 한도 cgroup를 적용할 것인가
- 이 상태를 누가 기억하고 관리할 것인가
여기서 핵심 문제가 생긴다.
프로세스를 하나 띄우는 행위와 그 프로세스의 생애 전체를 관리하는것은 전혀 다른 문제다.
runc 한계 #
runc의 한계는 실행은 해도 관리는하지 않는것이다.
runc는 철저히 순간적인 실행 도구이며 OCI spec에 따라 clone + namespace + cgroup 설정을 한 후 execve를 호출 이것이 전부다.
runc의 관점에서 컨테이너는, 만들어진 뒤 어떻게 되는지 관심이 없으며 죽었는지 재시작해야하는지, 이미지가 어디서 왔는지 다른 컨테이너와 무슨 관계인지를 모른다.
runc는 행위만 있고 상태가 없다는 뜻이다. 이 지점에서 containerd의 필연성이 등장한다.
containerd #
containerd는 컨테이너를 실행하는것이 아니라 컨테이너의 상태 전이를 관리한다.
컨테이너에는 항상 상태가 있다.
- 이미지 상태 (pull/unpack)
- RootFS 상태 (snapshot 생성됨)
- 컨테이너 정의 상태 (존재/삭제)
- 테스크 상태 (실행 중/ 종료)
- 리소스 상태 (cgroup 설정)
- 이벤트 상태 (시작, 종료, 실패)
이 모든 상태를 영속적으로 기록하고 재시작 이후에도 복구하며 외부(kubelet)에게 관측 가능하게 만드는 시스템이 필요하다. 그것이 containerd
여기서 오해하면 안되는게 containerd는 runc를 실행해서 컨테이너를 띄운다는 말 자체가 표면적으로 맞지만 개념적으론 틀렸다.
containerd가 하는일
- 컨테이너가 존재한다는 상태를 저장
- 이 컨테이너의 RootFS의 snapshot 정의
- 이 컨테이너를 실행할 런타임으로 runc를 선택하고 실형 결과를 상태로 반영
- 종료되면 이벤트를 발행
위와 같이 containerd는 컨테이너라는 객체의 수명 관리자 인거고 프로세스 관리자가 아니다. runc랑 containerd는 독립적이란 말.
kubelet과의 경계 #
kubelet은 RootFS가 어떻게 만들어졌는지 컨테이너의, 이미지 레이어는 어디에 있는지 동일 이미지의 중복은 어떻게 제거되었는지 노드 재시작후 살아남은 컨테이너는 무엇인지 답하지 않는다.
그저 pod를 이런 state로 실행하라를 유지하기만 한다. desired state를 유지를 위한 파드 관리 에이전트인것이고
containerd는 kubelet이 pod의 desired state를 관리하기 위해 보낸 요청을 받아 불변 이미지 모델로 관리하고 파일시스템 관점으로 풀어내고 커널 자원 모델로 매핑하는 작업을 한다.
그래서 contaierd는 쿠버네티스 확장이 아닌 의존할수밖에 없는 런타임 계층인것.
상태 머신 관점 #
컨테이너느 상태 머신이다.
Image Pulled
→ Snapshot Created
→ Container Created
→ Task Running
→ Task Exited
→ Garbage Collected
containrd는 이 상ㅇ태 전이를 정확하게 보장하는 시스템이다.
불변 객체 모델 (Content Address) #
이미지는 절대 수정되지 않는다 digest 기반으로 참조되기에
동일 레이어 중복 제거, 재현 가능한 실행, 안정적인 캐시를 가능하게 한다.
이는 단순 구현이 아니라 컨테이너의 재현성과 안정성을 위한 철학이다.
책임 분리 #
containerd는 일붤 많은 것을 담당하지 않는데
빌드, 스케줄링, 네트워크 정책은 생각하지 않는다 왜냐하면 상태 관리 시스템은 항상 예측 가능성과 단순성을 최우선해야하기 때문이다.
한줄로 정리해서 containrd는 컨테이너를 실행하는 프로그램이 아니라
컨테이너라는 추상 객체를 커널 자원으로 일관되게 투영하는 상태 관리자인것이다.