2.3 컨테이너 런타임과 표준: 컨테이너를 움직이는 심장

자, 이제 클라우드 네이티브와 쿠버네티스의 여정에서 정말 중요한 부분을 살펴볼 시간입니다. 바로 컨테이너 런타임인데요. 우리가 애플리케이션을 컨테이너라는 상자에 담아 배포한다고 이야기했죠? 이 컨테이너를 실제로 실행하고 생명을 불어넣는 역할을 하는 것이 바로 컨테이너 런타임입니다. 자동차에 비유하자면, 컨테이너가 잘 설계된 차체라면, 컨테이너 런타임은 그 차를 움직이게 하는 강력한 엔진과 같다고 할 수 있습니다. 쿠버네티스는 이러한 컨테이너들을 지휘하는 오케스트라의 지휘자이고, 컨테이너 런타임은 각 악기(컨테이너)를 연주하는 연주자라고 생각하셔도 좋습니다.

이 장에서는 컨테이너 런타임이 무엇인지, 그리고 왜 다양한 종류의 런타임이 존재하며 이들이 어떻게 표준을 통해 협력하는지에 대해 쉽고 명확하게 설명해 드리겠습니다. 이 부분을 이해하시면 쿠버네티스가 내부적으로 컨테이너를 어떻게 관리하고 실행하는지에 대한 그림을 보다 선명하게 그리실 수 있을 겁니다.

2.3.1 OCI (Open Container Initiative) 표준: 컨테이너 세계의 공용어

세상에는 다양한 종류의 컨테이너 기술들이 존재합니다. 만약 각 기술마다 자신만의 방식으로 컨테이너 이미지 형식을 정의하고 실행 방법을 규정한다면 어떻게 될까요? 마치 각기 다른 언어를 사용하는 사람들처럼 서로 호환되지 않아 큰 혼란이 발생할 것입니다. A 기술로 만든 컨테이너 이미지를 B 기술에서는 실행할 수 없고, C 기술의 런타임은 A 기술의 이미지를 이해하지 못하는 상황이 벌어지겠죠.

이러한 파편화를 막고 컨테이너 기술 생태계의 건강한 발전을 위해 등장한 것이 바로 OCI(Open Container Initiative) 표준입니다. OCI는 리눅스 재단 산하의 프로젝트로, 컨테이너 기술의 핵심적인 두 가지 영역에 대한 표준 사양을 정의합니다.

  1. 이미지 사양 (Image Specification): 컨테이너 이미지가 어떤 구조와 형식(포맷)을 가져야 하는지에 대한 표준입니다. 이 표준 덕분에 어떤 도구를 사용하여 컨테이너 이미지를 만들든, OCI 이미지 사양을 준수한다면 다른 OCI 호환 런타임에서 문제없이 해당 이미지를 인식하고 사용할 수 있습니다. 마치 전 세계 어디서나 통용되는 표준 규격의 화물 컨테이너처럼요.
  2. 런타임 사양 (Runtime Specification): 컨테이너를 어떻게 실행해야 하는지에 대한 표준입니다. 컨테이너 파일 시스템 구조는 어떻게 구성하고, 어떤 설정 값들을 넘겨주어야 하며, 컨테이너의 생명주기(생성, 시작, 중지, 삭제 등)는 어떻게 관리해야 하는지에 대한 규약을 정의합니다.

이 OCI 표준이 왜 중요할까요? 바로 호환성과 선택의 자유를 보장하기 때문입니다. OCI 표준 덕분에 개발자들은 특정 벤더의 기술에 종속되지 않고 다양한 컨테이너 도구와 런타임을 자유롭게 선택하여 사용할 수 있습니다. 또한, 새로운 컨테이너 기술이 등장하더라도 OCI 표준을 따른다면 기존 생태계와 자연스럽게 통합될 수 있어 혁신을 촉진하는 기반이 됩니다. 쿠버네티스 역시 이 OCI 표준을 기반으로 다양한 컨테이너 런타임과 유연하게 연동될 수 있습니다.

2.3.2 저수준(Low-level) 컨테이너 런타임: 컨테이너 실행의 최전선

이제 OCI 표준을 기반으로 실제로 컨테이너를 실행하는 역할을 담당하는 저수준(Low-level) 컨테이너 런타임에 대해 알아보겠습니다. 저수준 런타임은 OCI 런타임 사양을 직접 구현하여, 주어진 명세에 따라 단일 컨테이너를 생성하고 실행하는 데 집중하는 핵심 컴포넌트입니다.

가장 대표적인 저수준 런타임으로는 runc가 있습니다. runc는 OCI에서 제공하는 참조 구현체(reference implementation)이기도 하며, 사실상 업계 표준처럼 널리 사용되고 있습니다. runc의 주된 역할은 리눅스 커널의 기능들, 예를 들어 네임스페이스(Namespaces)와 컨트롤 그룹(cgroups) 등을 활용하여 컨테이너를 위한 격리된 환경을 설정하고, 그 안에서 지정된 애플리케이션 프로세스를 실행하는 것입니다.

저수준 런타임은 오직 “컨테이너 하나를 명세대로 실행한다”는 본연의 임무에 충실합니다. 컨테이너 이미지를 내려받거나, 여러 컨테이너를 관리하거나, 네트워킹이나 스토리지 볼륨을 설정하는 등의 복잡한 작업은 저수준 런타임의 책임 범위가 아닙니다. 이러한 작업들은 다음에 설명할 고수준 런타임의 역할이죠.

요약하자면, 저수준 런타임은 OCI 표준에 따라 컨테이너라는 독립적인 실행 환경을 실제로 만들어내고 프로세스를 시작시키는, 작지만 매우 중요한 실행 엔진이라고 이해하시면 됩니다.

2.3.3 고수준(High-level) 컨테이너 런타임: 컨테이너 관리의 조력자

저수준 런타임이 단일 컨테이너 실행에 집중한다면, 고수준(High-level) 컨테이너 런타임은 컨테이너의 전체 생명주기를 관리하고 더 넓은 범위의 기능을 제공하는 역할을 수행합니다. 쿠버네티스와 같은 컨테이너 오케스트레이션 시스템이 실제로 상호작용하는 대상은 바로 이 고수준 런타임입니다.

고수준 런타임은 다음과 같은 다양한 작업들을 처리합니다.

  • 이미지 관리: 원격 레지스트리에서 컨테이너 이미지를 가져오고(pull), 로컬에 저장하며, 이미지 레이어를 관리합니다.
  • 컨테이너 생명주기 관리: 저수준 런타임을 호출하여 OCI 명세에 따라 컨테이너를 생성하고 실행합니다. 또한, 컨테이너의 시작, 중지, 삭제 등을 관리합니다.
  • API 제공: 쿠버네티스의 Kubelet과 같은 클라이언트가 컨테이너와 이미지를 관리할 수 있도록 API(Application Programming Interface)를 제공합니다. (특히, 쿠버네티스는 CRI(Container Runtime Interface)라는 표준 인터페이스를 통해 고수준 런타임과 통신합니다.)
  • 네트워킹 및 스토리지 연동: 컨테이너에 필요한 네트워크 인터페이스를 설정하거나 스토리지 볼륨을 연결하는 등의 작업을 지원합니다.

대표적인 고수준 컨테이너 런타임으로는 containerdCRI-O가 있습니다. 두 런타임 모두 OCI 표준을 준수하며, 내부적으로 runc와 같은 저수준 런타임을 사용하여 컨테이너를 실행합니다.

  • containerd: 처음에는 도커 엔진의 일부였으나, 이후 독립적인 오픈소스 프로젝트로 분리되어 CNCF(Cloud Native Computing Foundation)의 Graduated 프로젝트가 되었습니다. 산업계에서 매우 널리 사용되며 안정성과 성능을 인정받고 있습니다.
  • CRI-O: 쿠버네티스만을 위한 경량 컨테이너 런타임을 목표로 개발되었습니다. 이름에서 알 수 있듯이 쿠버네티스 CRI(Container Runtime Interface)를 구현하는 데 중점을 둡니다.

결국, 클라우드 네이티브 환경에서 컨테이너가 성공적으로 실행되고 관리되기 위해서는 OCI 표준을 기반으로 저수준 런타임과 고수준 런타임이 각자의 역할을 충실히 수행하며 긴밀하게 협력해야 합니다. 고수준 런타임은 이미지 관리와 API 제공 등 포괄적인 관리 기능을 수행하고, 실제 컨테이너 실행은 OCI 런타임 사양에 따라 저수준 런타임에게 위임하는 구조인 것이죠.

쿠버네티스를 사용하면서 우리가 직접 저수준 런타임을 다룰 일은 거의 없겠지만, 이러한 내부 구조와 표준의 역할을 이해하는 것은 쿠버네티스가 어떻게 컨테이너를 생명력 있게 만들고 관리하는지에 대한 깊이 있는 통찰력을 제공할 것입니다. 이는 앞으로 마주하게 될 다양한 문제들을 해결하고 시스템을 더 효과적으로 운영하는 데 든든한 밑거름이 되어줄 것입니다.