Kubernetes

Container Runtime과 CRI, 그리고 Containerd 알아보기

mokpolar 2024. 9. 8. 12:06
반응형

들어가며 

안녕하세요?


Container Runtime과 CRI, Containerd 에 대해서 공부한 내용을 정리해보겠습니다.

이 글은 CloudNeta팀 가시다님의 KANS(Kubernetes Advanced Network Study) 2주차 과제로 작성되었습니다.

 

Container Runtime

Container Runtime이 뭔가요?

 

CRI를 알아보기 전에 Container Runtime 부터 알아보겠습니다.

여기저기 나온 그림들을 합쳐서 어떤 식으로 Kubernetes에서 container를 만들어 내는지에 대해 아래와 같은 구조를 그려봤습니다.
High level runtime, Low level runtime 이라는 단어가 등장합니다.

 

 

Low Level Container Runtime 이 뭔가요?

지난 주에 작성한 글 Container 격리 기술 이해하기 에서 리눅스에서 사용하는 컨테이너 격리 기술에 대해서 알아봤습니다.

cgroup, namespace 등이 있었죠.

 

물론 그 기술들을 사용하면 컨테이너를 저수준에서 격리할 수는 있겠지만 이걸 일일이 사용자가 하고 있을 수는 없겠죠. 그리고 Kernel 버젼도 다르고 시스템도 다 다릅니다.

 

그래서 LXC (Linux Container) 같은걸 사용해서 간접적으로 관리하게 되었다고 합니다.
그러다가 Docker에서는 Kernel 관련 가상화를 위한 interface를 libcontainer란 이름을 붙여서 개발하게 되었고, 이것이 현재의 runC가 되었다고 합니다.

 

runC는 namespace와 cgroup을 직접 사용하여 컨테이너를 생성합니다.
그리고 이 runC와 같은 것들을 low level container runtime 이라고 부릅니다.

 

하지만 실제로 컨테이너 이미지를 가지고 이렇게 컨테이너를 생성을 하려면 이를 위한 기능이나 API도 필요합니다.

이런 일들은 high level container runtime에서 수행합니다.

 

High Level Container Runtime 이 뭔가요?

high level container runtime은 위 그림에서 보듯이 OCI 표준을 준수하며 Open Container Initiative · GitHub관련 API를 제공하는 데몬으로서 기능합니다.

 

컨테이너에 대한 이미지, 라이프사이클, 리소스를 관리하며 runC 같은 저수준 컨테이너 런타임에 명령을 전달합니다.

이런 녀석들에는 containerdcri-o가 있습니다.

 

Container Runtime Interface

그래서 Container Runtime Interface는 뭔가요?

 

low, high level container runtime에 대해서 알아봤으니 이제 CRI, Container Runtime Interface를 알아보겠습니다.

먼저 이 내용을 설명한 쿠버네티스 공식 옛날 문서를 기계번역으로 인용해보겠습니다. 쿠버네티스의 컨테이너 런타임 인터페이스(CRI) 소개

 

하는일 : "표준 인터페이스를 통해서 kubelet 재컴파일 없이 다양한 컨테이너 런타임 사용"

각 컨테이너 런타임에는 고유한 강점이 있으며, 많은 사용자들이 쿠버네티스가 더 많은 런타임을 지원하도록 요청해 왔습니다.

쿠버네티스 1.5 릴리즈에서는, 재컴파일할 필요 없이 다양한 컨테이너 런타임을 사용할 수 있는 플러그인 인터페이스인 컨테이너 런타임 인터페이스(CRI)를 도입하게 된 것을 자랑스럽게 생각합니다.

CRI는 프로토콜 버퍼와 gRPC API, 라이브러리로 구성되며, 

...

Kubelet 내부에 대한 깊은 이해가 필요하며 Kubernetes 커뮤니티에 상당한 유지 관리 오버헤드가 발생합니다.
이러한 요소들은 초기 컨테이너 런타임에 대한 높은 진입 장벽을 형성합니다.

명확하게 정의된 추상화 계층을 제공함으로써 이러한 장벽을 없애고
개발자가 컨테이너 런타임을 구축하는 데 집중할 수 있도록 지원합니다.


이제 다시 이 그림을 갖고 와보겠습니다.

그래서 Container Runtime Interface이란 kubelet이 컨테이너 런타임을 호출할 수 있는 인터페이스를 의미합니다.

High Level Container Runtime과 Kubernetes가 연계되기 위해선 반드시 CRI를 구현해야 하고 이를 통해서 컨테이너 이미지 관리 및 Pod 생성이 가능해야 합니다.

 

그리고 이 CRI를 지원하는 container runtime에 containerd, cri-o 등이 있는 것입니다.

  • Kubelet은 gRPC 프레임워크를 사용하여 Unix 소켓을 통해 Container Runtime 과 통신합니다.
  • 여기서 kubelet클라이언트 역할을 하고 containerd는 서버 역할을 합니다.
  • Protobuf API에는 두 가지 gRPC 서비스인 ImageServiceRuntimeService가 포함되어 있습니다. ImageService는 리포지토리에서 이미지를 가져오고, 이미지를 검사하고, 제거하는 RPC를 제공합니다.

위 링크에서 CRI Spec을 갖고 와보면 이런 형태로 되어있습니다.

service RuntimeService {
    // Version returns the runtime name, runtime version, and runtime API version.
    rpc Version(VersionRequest) returns (VersionResponse) {}
    ...
    rpc RemovePodSandbox(RemovePodSandboxRequest) returns (RemovePodSandboxResponse) {}
    // PodSandboxStatus returns the status of the PodSandbox.
    rpc PodSandboxStatus(PodSandboxStatusRequest) returns (PodSandboxStatusResponse) {}
    // ListPodSandbox returns a list of PodSandboxes.
    rpc ListPodSandbox(ListPodSandboxRequest) returns (ListPodSandboxResponse) {}
    ...

그럼 Containerd에 대해서 좀 더 알아보겠습니다.

 

Conatinerd

containerd의 동작방식과 발전사

Containerd에 대한 설명과 이것이 발전한 과정은 이 문서에 나옵니다.

Kubernetes Containerd Integration Goes GA | Kubernetes
Containerd Brings More Container Runtime Options for Kubernetes | Kubernetes

 

 

처음에 containerd 1.0 버젼에는 cri-containerd라는 데몬이 따로 존재했습니다.

cri-containerd는 Kubelet의 컨테이너 런타임 인터페이스(CRI) 서비스 요청을 처리하고 containerd를 사용하여 컨테이너와 컨테이너 이미지를 관리했습니다.

 

동작하는 방식은 아래와 같았습니다.

  1. Kubelet은 CRI 런타임 서비스 API를 통해 cri-container를 호출하여 파드를 생성하고,
  2. cri-container는 컨테이너를 사용하여 특수 일시 중지 컨테이너(샌드박스 컨테이너)를 생성 및 시작하고 해당 컨테이너를 파드의 cgroups 및 네임스페이스 내에 배치하며(간결성을 위해 단계 생략),
  3. cri-containerd는 CNI를 사용하여 파드의 네트워크 네임스페이스를 구성하고,
  4. 이후 Kubelet이 CRI 이미지 서비스 API를 통해 cri-container를 호출하여 애플리케이션 컨테이너 이미지를 가져온다
  5. cri-containerd는 이미지가 노드에 없는 경우, 컨테이너를 추가로 사용하여 이미지를 가져온다;
  6. 그런 다음 Kubelet은 CRI 런타임 서비스 API를 통해 cri-container를 호출하여 가져온 컨테이너 이미지를 사용하여 파드 내에서 애플리케이션 컨테이너를 생성하고 시작한다
  7. 마지막으로 cri-container가 컨테이너를 호출하여 애플리케이션 컨테이너를 생성하고 파드의 cgroups 및 네임스페이스 내에 넣은 다음 파드의 새 애플리케이션 컨테이너를 시작한다. 이 단계가 끝나면 파드와 해당 애플리케이션 컨테이너가 생성되고 실행된다.

 

그러나 cri-containerd와 containerd grpc를 통해 상호 작용하는 2개의 다른 데몬이기 때문에
CRI plugin으로 리팩토링 되어 containerd에 내장하는 형태로 변화하였습니다.

 

Reference

https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/
Kubernetes Containerd Integration Goes GA | Kubernetes
Dockershim: The Historical Context | Kubernetes
Containerd Brings More Container Runtime Options for Kubernetes | Kubernetes
a-discussion-on-container-runtime---starting-with-dockershim-being-deleted-by-kubernetes_600118
kubernetes/pkg/kubelet/api/v1alpha1/runtime/api.proto at release-1.5 · kubernetes/kubernetes · GitHub

반응형