“Dockershim deprecated with the release of Kubernetes 1.24”

위 문장은 더 레지스터(The register)에 실린 기사의 헤드라인이다. 문장을 보고 어떤 생각이 드는가? 나는 컨테이너가 구현하는 기술이 궁금할 뿐이지, 관련 기술로 먹고 사는 것은 아니라서 별 생각은 없었다. 그러나 관련 업계에서는 매우 큰 화두였었구나 하는 것을 최근 알게 되었다. 실제로 쿠버네티스(Kubernetes) 측에서 아래와 같은 글을 기고했을 정도로 말이다.

“Don’t Panic: Kubernetes and Docker”, Kubernetes Blog

쿠버네티스의 창시자인 조 베다(Joe Beda)는 위와 같은 트윗을 했다. 회사를 비롯해서 모든 것들이 “Docker"이기 때문에 혼란이 발생했다고. 실제로 회사 이름과 제품 이름이 “Docker"이고, 관련된 많은 요소들의 호칭에 “Docker"가 들어가니 오죽할까. 후에 설명할 Conainerd의 네이밍(naming)은 데몬(Daemon) 프로세스로 동작한다고 “Container"에 ’d’를 붙인 듯 하다. 이 정도는 systemd, httpd 등 리눅스(Linux)에 존재하는 수많은 데몬들의 네이밍 규칙을 따른 것이겠지만… 또 Containerd를 다루기 위한 2개의 쉘(Shell)중 하나는 ctl이고 다른 하나가 nerdctl이다. “ctl”? 설마 “control"의 약자를 그대로 갖다 쓴 건가? 심지어 “nerdctl"은 “Containerd"의 끝 네 글자인 “nerd"를 그 앞에 붙인 듯 하다. 아… Containerd가 도커(Docker)에서 파생된 프로젝트라더니 네이밍 센스도 함께 파생된 듯 하다.

여하튼, 위 기사에서 언급하는 것은 정확히 말하면 Docker가 아닌 Dockershim이므로 혼란을 겪지말라고 쿠버네티스 측에서 “Don’t panic” 이라며 공지한 것이다. 그럼 Dockershim은 무엇일까? 이를 화두로 컨테이너(Container) 진영의 주요 기술들 간의 관계를 알아보자.

Docker, Containerd, Kubernetes…

컨테이너 진영은 도커의 등장 이래로 매우 폭발적으로 확장되고 있다. 최근에 검색해보면 도커 말고도 Containerd나 쿠버네티스를 중심으로 수 많은 기술들이 존재함을 알 수 있다. 너무 많은 기술이 난립하면서 이들 간의 호환을 보장하기 위해 표준?이라고 볼만 한 것들이 등장했다.

OCI and CRI-O

OCI(Open Container Initiative)

먼저 등장한 것은 OCI. Docker 이후 rkt 등 여러 벤더(Vendor)들이 사용하는 컨테이너의 형식이 달라서 이들 간의 호환을 보장하기 위해 등장한 표준이다. 즉, 특정 OCI-런타임(runtime)에 의해 생성된 컨테이너 및 컨테이너 이미지는 Docker를 포함해 쿠버네티스 등 주요 컨테이너-런타임에서 얼마든지 사용가능하다. 가장 유명한 OCI-런타임으로는 runc가 있다. 아, 설마 실행하다의 “run"에 컨테이너의 “c"를 붙인 네이밍 센스에서 알 수 있듯이 도커社에서 개발한 것이다. 컨테이너 관련 기술들은 Go 언어로 작성된 경우가 많은데 runc의 경우 C 언어로 작성되었기 때문에 “c” 붙였을 수도 있겠다. 여하튼, crun이라는 OCI-런타임도 있는데 이건 반대로 Go로 개발되었다는 특징이 있다. 네이밍 센스는 커뮤니티 전반으로 전염이 되나보다. 또, Kata-runtime과 보안에 특화된 gVisor와 같은 OCI-런타임 등이 있다.

CRI(Container Runtime Interface)

CRI의 등장으로 도커에서 OCI-런타임이 분리되고, 또 하나 Containerd라는 컨테이너 런타임이 분리된다. OCI-런타임이 컨테이너를 실제로 생성하는 역할을 수행한다면 컨테이너 런타임은 그 외의 나머지 것들을 담당한다. 예를 들면 이미지를 원격지에서 가져오거나, AUFS 또는 OverlayFS로 컨테이너에서 사용할 파일시스템을 구성하거나, 네트워크를 구성하는 것 들이다. 즉, 우리가 유용하다고 생각하는 컨테이너의 특징들은 사실 컨테이너 자체가 아니라 그 외적인 부분에 있다.

한편, 쿠버네티스는 많은 사람들이 도커와 유사한 것으로 알고있지만 Containerd와 같은 컨테이너 런타임들을 관리하는 컨테이너 오케스트레이션 도구라고 봐야한다. 예를 들면, 쿠버네티스는 여러 컨테이너를 대상으로 여러 서버에 적절히 분산 배치하거나, 문제가 생긴 컨테이너는 교체하는 등의 작업을 수행하며 여기에 컨테이너 런타임인 Containerd가 필요할 뿐이다. 외에도 다양한 컨테이너 런타임을 사용하기 위하여 CRI(Container Runtime Interface)라는 명세(Spec)를 만들어 이를 지원하면 얼마든지 쿠버네티스에서 사용 가능하다. 그러나, Containerd가 없었을 때에는 쿠버네티스 측에서 어떻게든 도커를 컨테이너 런타임으로 이용하여야 했기에 Dockershim이라는 것을 개발한다. 즉, Dockershim은 도커가 마치 CRI를 지원하는 컨테이너 런타임인 것 처럼 쿠버네티스에 의해 다뤄질 수 있도록 한다.

앞선 기사의 내용을 다시보면 쿠버네티스는 도커가 아닌 Dockershim의 지원을 중단한 것이다. 따라서 Containerd나 CRI-O로 컨테이너 런타임을 교체하여야 한다. 아마도 CRI를 지원하는 Containerd가 도커에서도 사용 중인 만큼 더 이상 Dockershim을 사용할 이유가 사라졌기 때문일 것이다. Containerd로의 전환에 대해서는 네임스페이스(Namespace) 관련하여 주의할 점이 있다고 하니 이 부분은 유의할 필요가 있을 것 같다.

Containerd

Containerd 아키텍처

여기까지 컨테이너 진영의 주요 기술들 간의 관계를 알아보았다. 그 중 Containerd는 도커와 쿠버네티스가 사용하는 컨테이너 런타임이고, 도커와 컨테이너는 수많은 클라우드 플랫폼에서 사용하기 때문에 매우 중요한 위치에 있음을 위 그림에서 알 수 있다. Containerd는 컨테이너라면 당연히 기대하는 기능들을 제공하고자 Content Store, Snapshotter, Runtime과 같은 핵심 모듈을 갖고있다. 또, 누구나 쉽게 사용할 수 있도록 네임스페이스(Namespace)와 메타데이터(Metadata)를 기반으로 한 다양한 서비스들을 제공하고 있다. 나는 Containerd의 구현에 관심이 있으므로 이들 모듈 및 서비스들에 대한 글을 종종 정리하게 될 것 같다.