컨테이너와 컨테이너 런타임, 제대로 이해하기




개발을 하다 보면 “컨테이너”, “도커”, “쿠버네티스” 같은 단어를 매일같이 듣게 됩니다. 그런데 막상 “컨테이너가 뭐예요?”라고 물으면 명확히 답하기는 의외로 어렵습니다. 더 깊이 들어가서 “컨테이너 런타임은 뭐죠?”라고 물으면, 도커와 컨테이너 런타임이 같은 건지 다른 건지부터 헷갈리기 시작합니다.

이 글은 그런 모호함을 정리하는 것이 목적입니다. 컨테이너가 무엇이고, 어떻게 동작하며, 런타임이라는 계층이 왜 존재하는지를 차근차근 짚어보겠습니다. 시리즈의 첫 편이니만큼, 이후의 모든 글에서 전제가 될 개념들을 여기서 단단히 다지고 갑니다.

컨테이너란 무엇인가

컨테이너는 애플리케이션과 그 실행에 필요한 모든 것을 하나의 패키지로 묶어, 격리된 환경에서 실행하는 기술입니다. 여기서 “모든 것”이란 코드뿐 아니라 라이브러리, 시스템 도구, 설정 파일까지 포함합니다. 그래서 한 번 만들어둔 컨테이너는 어디서 실행하든 동일하게 동작합니다.

비유를 들면 이해가 쉽습니다. 이사를 갈 때 가구·옷·식기를 따로 옮기면서 새 집에 맞춰 다시 배치하는 것이 전통적인 배포 방식이라면, 컨테이너는 **”방 하나를 통째로 들어다 옮기는 것”**에 가깝습니다. 방 안의 모든 것이 그대로 유지되니, 어떤 집으로 옮기든 들어가자마자 그대로 살 수 있습니다.

가상머신(VM)과 무엇이 다른가

컨테이너를 처음 접할 때 가장 많이 비교되는 것이 가상머신입니다. 둘 다 “격리된 환경에서 무언가를 실행한다”는 점에서는 비슷해 보이지만, 구조가 근본적으로 다릅니다.

가상머신은 호스트 위에 하이퍼바이저라는 계층을 두고, 그 위에 게스트 OS를 통째로 올립니다. 즉 각 VM마다 자신만의 OS 커널이 있습니다. 그래서 무겁고 시작이 느리지만, 격리 수준은 매우 높습니다.

컨테이너는 호스트의 OS 커널을 공유합니다. 대신 프로세스·파일시스템·네트워크 등을 격리해 마치 독립된 환경처럼 보이게 만듭니다. 별도 OS를 띄우지 않으니 가볍고 빠르지만, 커널을 공유한다는 한계도 있습니다.

구분가상머신컨테이너
격리 단위OS 전체프로세스
커널각 VM마다 별도호스트와 공유
시작 속도수십 초 ~ 수 분수 초 이내
자원 사용무거움가벼움
격리 강도강함상대적으로 약함

쉽게 말해, VM은 집을 한 채씩 짓는 것이고 컨테이너는 한 건물 안에 독립된 방들을 만드는 것입니다. 어느 쪽이 더 좋다기보다, 용도가 다른 도구입니다.

컨테이너는 어떻게 가능한가 — 리눅스 커널의 두 기둥

컨테이너가 마법처럼 동작하는 것 같지만, 사실은 리눅스 커널이 오래전부터 갖고 있던 기능들을 영리하게 조합한 결과입니다. 핵심은 두 가지입니다.

Namespaces — 격리

네임스페이스는 프로세스가 보는 시스템의 “범위”를 제한합니다. 컨테이너 안의 프로세스는 자기만의 프로세스 목록, 자기만의 네트워크 인터페이스, 자기만의 파일시스템 루트를 가진 것처럼 보입니다. 실제로는 호스트 커널이 같은 자원을 공유하지만, 네임스페이스가 그 사실을 가려줍니다.

대표적인 네임스페이스 종류는 다음과 같습니다.

  • PID: 프로세스 ID 격리 (컨테이너 안에서 PID 1은 자기 자신)
  • NET: 네트워크 격리 (별도의 IP, 포트, 라우팅 테이블)
  • MNT: 파일시스템 마운트 격리
  • UTS: 호스트네임 격리
  • IPC: 프로세스 간 통신 격리
  • USER: 사용자/UID 격리

Cgroups — 자원 제한

Cgroups(Control Groups)는 프로세스가 사용할 수 있는 자원의 양을 제한합니다. CPU·메모리·디스크 I/O·네트워크 대역폭을 컨테이너 단위로 통제할 수 있습니다. 한 컨테이너가 폭주해서 호스트 전체를 마비시키는 일을 막아주는 핵심 장치입니다.

Union File System — 이미지 레이어

여기에 더해, OverlayFS 같은 유니온 파일시스템이 컨테이너 이미지의 레이어 구조를 가능하게 합니다. 베이스 이미지(예: Ubuntu) 위에 라이브러리 레이어, 애플리케이션 레이어를 쌓아 올리고, 변경된 부분만 새 레이어로 저장합니다. 그래서 같은 베이스를 쓰는 이미지들은 디스크를 효율적으로 공유할 수 있습니다.

정리: 컨테이너 = Namespaces(격리) + Cgroups(자원 제한) + Union FS(이미지 레이어)

이 세 가지가 리눅스 커널 안에 이미 있었기 때문에, 도커는 그것을 사용자 친화적으로 묶어 대중화시킨 것입니다. 도커가 컨테이너를 발명한 것이 아니라, 컨테이너를 쉽게 쓸 수 있게 만든 것입니다.

컨테이너 런타임이란

이제 본격적으로 “런타임” 이야기로 들어가겠습니다.

컨테이너 런타임은 컨테이너를 실제로 실행하고 관리하는 소프트웨어입니다. 이미지를 다운로드하고, 컨테이너를 생성·실행·중지·삭제하며, 위에서 설명한 네임스페이스·cgroups를 호출해 격리 환경을 만드는 역할을 담당합니다.

그런데 한 가지 중요한 사실이 있습니다. 컨테이너 런타임은 하나의 통짜 프로그램이 아니라, 두 계층으로 나뉘어 있습니다.

저수준 런타임 (Low-level Runtime)

실제로 리눅스 커널 기능을 호출해 컨테이너를 생성하는 핵심 엔진입니다. OCI(Open Container Initiative) 런타임 명세를 따르며, 단일 컨테이너의 생명주기만 다룹니다. 이미지 관리·네트워크 설정 같은 부가 기능은 없습니다.

대표적인 저수준 런타임:

  • runc: 가장 널리 쓰이는 표준 구현체. Go로 작성되어 있고 사실상 표준
  • crun: C로 작성된 가벼운 대안. 빠르고 메모리 사용량이 적음
  • youki: Rust로 작성된 신생 런타임

고수준 런타임 (High-level Runtime)

사용자가 직접 마주하는 계층입니다. 이미지 풀(pull), 레지스트리 인증, 네트워크 구성, 스토리지 관리 등 운영에 필요한 모든 부가 기능을 제공합니다. 내부적으로는 저수준 런타임을 호출해 실제 컨테이너를 띄웁니다.

대표적인 고수준 런타임:

  • containerd: 원래 Docker 내부에서 사용되다 분리되어 CNCF 프로젝트가 됨. Kubernetes의 기본 런타임
  • CRI-O: Kubernetes 전용으로 설계된 가벼운 런타임
  • Docker Engine: Docker가 사용하는 런타임 (내부적으로 containerd 사용)

계층 구조로 보면

[ 사용자 / 도구 ]
     ↓
[ Docker CLI / Podman / kubectl 등 ]
     ↓
[ 고수준 런타임: containerd / CRI-O / Docker Engine ]
     ↓
[ 저수준 런타임: runc / crun ]
     ↓
[ 리눅스 커널: Namespaces / Cgroups ]

이 계층 구조를 이해하면, “도커와 containerd는 무슨 관계?”, “쿠버네티스가 도커를 버렸다는 게 무슨 뜻?” 같은 질문에 답이 보입니다. 쿠버네티스는 도커 자체를 버린 게 아니라, 도커 엔진이라는 중간 계층을 거치지 않고 바로 containerd를 쓰는 쪽으로 옮겨간 것입니다. 컨테이너 자체는 동일하게 동작합니다.

OCI 표준 — 왜 도구가 이렇게 많아도 호환되는가

여기까지 읽으면서 한 가지 의문이 들 수 있습니다. “도구가 이렇게 많은데, 한 도구로 만든 이미지가 다른 도구에서도 동작하나?”

답은 그렇다입니다. 그 이유가 OCI(Open Container Initiative) 입니다.

OCI는 컨테이너 이미지 포맷과 런타임 동작에 대한 공개 표준을 정의하는 단체입니다. 2015년 도커가 주도해 만들었고, 지금은 사실상 업계 표준입니다. OCI는 두 가지 주요 명세를 관리합니다.

  • OCI Image Spec: 이미지가 어떻게 생겼는지 (레이어, 매니페스트, 메타데이터)
  • OCI Runtime Spec: 런타임이 컨테이너를 어떻게 실행해야 하는지

이 표준 덕분에, Docker로 빌드한 이미지를 Podman으로 실행할 수 있고, containerd로 만든 이미지를 CRI-O가 받아 동작시킬 수 있습니다. 표준이 있기에 다양한 도구가 공존하는 것입니다.

정리

이번 편에서 다룬 내용을 한 줄씩 정리해보면 다음과 같습니다.

  • 컨테이너는 애플리케이션과 의존성을 함께 묶어 격리된 환경에서 실행하는 기술이다
  • VM과 달리 호스트 커널을 공유하므로 가볍고 빠르다
  • 컨테이너는 마법이 아니라 Namespaces(격리) + Cgroups(자원 제한) + Union FS(레이어) 의 조합이다
  • 컨테이너 런타임은 두 계층으로 나뉜다: 저수준(runc, crun)과 고수준(containerd, CRI-O, Docker Engine)
  • OCI 표준 덕분에 다양한 도구가 같은 이미지를 호환되게 다룰 수 있다

다음 편에서는 이 런타임 위에 쌓이는 컨테이너 관리 도구의 전체 생태계를 조망합니다. 단일 호스트 도구부터 오케스트레이션, 보조 도구까지 — 누가 어디에 쓰이는지 큰 지도를 그려보겠습니다.




댓글 남기기