Docker Architecture History

Docker Architecture History

Overview

이전 포스팅에서 Docker가 기존 컨테이너 기술들에 비해 어떤 점들이 더 좋은지, 어떻게 사실상 컨테이너 기술의 표준이 됐는지를 알 수 있었다. 이번에는 Docker의 architecture가 어떻게 변화했는지에 대해 알아보며 현재의 구조가 탄생한 배경에 대해 기술적으로 이해해볼 것이다.


1. 초기 Docker Architecture (~v0.8)

Docker가 2013년도에 처음 나왔을 당시, docker engine은 2개의 주요 컴포넌트(dockerd, LXC)로 이뤄진 monolithic 아키텍처였다.

// Docker 초기 architecture (~v0.8)
+-------------------------------------+
|        Docker Daemon(dockerd)       |
|-------------------------------------|
| - Docker Client                     |
| - Docker API                        |
| - Container Runtime                 |
| - Image Build                       |
| - etc ...                           |
+-------------------------------------+
                 |
                 v
+-------------------------------------+
|       LXC(Execution Driver)         |
|-------------------------------------|
| - Provide fundamental container     |
|   build-blocks to docker daemon     |
+-------------------------------------+
                 |
                 v
+-------------------------------------+
|     Linux Kernel(Host Kernel)       |
|-------------------------------------|
| - Namespaces (Isolation)            |
| - Cgroups (Resource Management)     |
| - Capability (Process Permission)   |
| - etc ...                           |
+-------------------------------------+

(제가 직접 한땀한땀 그린 것이니.. 막 가져가지 말아주세요…)


1.1) 현 구조의 한계

위 구조가 초기에는 딱히 문제가 없었지만, 발전시켜나가는 과정에서 아래와 같은 애로사항이 존재했다. 특히 LXC 에 대한 내용인데,

  1. 다른 플랫폼(운영체제)으로의 확장에 대한 어려움 (LXC는 리눅스 위에서만 실행됨)
  2. Docker core 기술이 특정 소프트웨어(LXC)에 의존적이라는 점
  3. LXC의 성능 이슈 (Docker를 위해 설계된 소프트웨어가 아닌 점에서 나오는 최적화의 한계)

Docker를 발전시켜감에 있어서 특정 소프트웨어에 의존적인 부분은 매우 부정적이었기에 LXC에서 벗어날 필요가 있었다.


2. libcontainer의 등장 (v0.9)

LXC에 종속되지 않기 위해 2014년 3월, Docker는 libcontainer라는 linux kernel에 접근할 수 있는 라이브러리를 개발했다. 이를 통해서 Docker는 host linux kernel에 libcontainer를 통한 직접 접근이 가능해졌다.

이로써 기존의 LXC를 더 이상 사용할 필요가 없어졌고, 이에 libcontainer가 Docker의 기본 execution driver가 됨에 따라 아래와 같이 아키텍처가 변화하였다.

// Docker v0.9 architecture
+---------------------------------------------------------------------------------+
|                          Docker Daemon(dockerd)                                 |
|---------------------------------------------------------------------------------|
| - Docker Client                                                                 |
| - Docker API                                                                    |
| - Container Runtime                                                             |
| - Image Build                                                                   |
| - etc ...                                                                       |
+---------------------------------------------------------------------------------+
                                        |
                                        v
+---------------------------------------------------------------------------------+
|                       Execution Driver API (interface)                          |
+---------------------------------------------------------------------------------+
                 |                                           |
                 | (default driver)                          | (optional driver)
                 v                                           v
+-------------------------------------+     +-------------------------------------+
|   libcontainer(Execution Driver)    |     |        LXC(Execution Driver)        |
|-------------------------------------|     |-------------------------------------|
| - default execution driver          |     | - Provide fundamental container     |
|   at docker v0.9                    |     |   build-blocks to docker daemon     |
| - access directly to host linux     |     | - Optional execution driver at      |
|   kernel (Go lang library)          |     |   docker v0.9                       |
+-------------------------------------+     +-------------------------------------+
                 |                                           |
                 v                                           v
+---------------------------------------------------------------------------------+
|                          Linux Kernel(Host Kernel)                              |
|---------------------------------------------------------------------------------|
| - Namespaces (Isolation)                                                        |
| - Cgroups (Resource Management)                                                 |
| - Capability (Process Permission)                                               |
| - etc ...                                                                       |
+---------------------------------------------------------------------------------+

(제가 직접 한땀한땀 그린 것이니.. 막 가져가지 말아주세요…)


2.1) libcontainer가 뭔데요..?

2.1.1) 엥 갑자기 무슨 native…?

이유는 알 수 없으나 driver name이 실제로 native가 맞다… moby github repo에 있는 코드 이력을 뒤져서… 0.9 버전 커밋 기준으로 확인해봤다.

docker09_exec_driver_in_code

moby/execdriver/native/driver.go

changelog_v09

moby/CHANGELOG.md

코드를 면밀히 분석하지는 못했고 단순하게 남아있던 흔적… 정도만 확인해봤다.


2.2) 그래서 뭐가 좋아졌나요?

  1. Docker에 최적화된 kernel 접근
  2. 특정 소프트웨어에 대한 불필요한 의존성 제거
  3. driver에 대한 인터페이스화로 인한 특정 driver에 종속되지 않는 구조로의 발전

아무래도 LXC는 Docker만을 위해 개발된게 아니다보니, 최적화 측면에서 그다지 좋지 않았을 것이다. 그리고 LXC의 특정 버전 또는 관련된 의존성들에 영향을 받을 수 밖에 없었을 것이기에 0.9버전에서 libcontainer의 도입은 상당히 긍정적이라고 볼 수 있겠다.


2.3) 그래도 존재하는 한계점…

이와 같은 문제를 어떻게 해결하는지 보도록 하자.


3. Client-Server 구조로의 변경 (v1.11~)

docker_v1_11_0_changelog

2016년도 docker 1.11.0 버전의 CHANGELOG.md

2016년도에 Docker에 있어서 큰 변화가 찾아왔다. 바로 docker daemon를 여러 컴포넌트로 쪼개어 monolithic 구조에서 탈출한 것이다. 이로써 Docker daemon에 있던 container execution, container runtime들은 모두 컴포넌트화되어 분리된 구조를 가지게 됐다.

// Docker v1.11.0 architecture
+---------------------------------------------------------------------------------+
|                             Docker Client (CLI)                                 |
|---------------------------------------------------------------------------------|
| - docker build command                                                          |
| - docker image pull command                                                     |
| - etc CLI command ...                                                           |
+---------------------------------------------------------------------------------+
                                        |
                                        v
+---------------------------------------------------------------------------------+
|                          Docker Daemon(dockerd)                                 |
|---------------------------------------------------------------------------------|
| - Docker API                                                                    |
| - etc ...                                                                       |
+---------------------------------------------------------------------------------+
                                        |
                                        v
+---------------------------------------------------------------------------------+
|                                  containerd                                     |
|---------------------------------------------------------------------------------|
| - Manage container lifecycle                                                    |
| - etc ...                                                                       |
+---------------------------------------------------------------------------------+
                       /                 |                \
                     /                   v                  \
+-------------------+          +-------------------+          +-------------------+
|  containerd-shim  |          |  containerd-shim  |          |  containerd-shim  |
+-------------------+          +-------------------+          +-------------------+
          |                              |                              |
          v                              v                              v
+-------------------+          +-------------------+          +-------------------+
|        runc       |          |        runc       |          |        runc       |
+-------------------+          +-------------------+          +-------------------+
          |                              |                              |
          v                              v                              v
+-------------------+          +-------------------+          +-------------------+
|     container     |          |     container     |          |     container     |
+-------------------+          +-------------------+          +-------------------+

한눈에 봐도 많이 바뀐게 보일 정도다. 위 사진의 CHANGELOG.md 에서도 확인할 수 있듯이 기존 docker daemon의 기능을 컴포넌트화하여 나누게 됐고, 이에 위와 같은 아키텍처를 가지게 된 것이다.


3.1) 뭐가 많이 바뀌었는데, 좋아진게 있나요..?

이 어려운 리팩터링 작업을 한 docker 팀이 새삼 대단하다고 느껴진다…


4. 현재의 Docker Architecture

자, 이제 현재 docker 공식 홈페이지에서 제공하는 이미지를 보도록 하자.

docker-architecture

그림의 Docker Host가 바로 위에서 알아본 docker daemon, containerd, runc… 등등을 포함한 요소로 보인다.


마치며… 정리하며 느낀점

대략 Docker공부를 시작할 즈음, 많은 자료들을 찾고 있었는데, 당시

처음 : Docker daemon에서 컨테이너 만들어주는거구나~

조금 더 읽고 : 어? containerd? 아 얘가 해주는거구나~

마저 읽고 : 어..? runc…? 왜 굳이…?

추가 검색을 하며 : OCI..?

이런식으로 내가 모르는 내용이 너무 많았고, 이를 정리하기가 매우 힘들 것이라는 것이 본능적으로 느껴졌다.

개인적으로 기술의 역사를 알아야 지금 왜 이렇게 발전했는지를 알 수 있다고 생각하기에, 시간이 걸리고 좀 더 힘들더라도 성장하는 시간이 되었다고 생각한다. (그리고 그저 그냥 좋아서 블로그글 복붙해서 의미없는 글 싸지르는 블로그 볼 때 마다 화가 나서 열심히 적은 것도 있다.)


Next

뭔가 작별할 것 같은 뉘앙스로 적었으나, 이걸로 컨테이너에 대한 얘기를 끝낸다는 아니고, 역사를 알았으니 가장 중요한 그 기술을 공부해야 한다. 그리고 알아야할게 아직 산더미 같이 남았다는….

containerd와 runc와 같이 인터페이스 느낌의 컴포넌트가 나타난 이유와 OCI에 대해서 다음에 알아보도록 할 것이고, 이게 끝난 후 본격적으로 기술에 대한 공부를 시작할 예정이다.

참고로 References에 남긴 링크들은 한번씩 들어가서 확인하면 좋을 듯 하니 혹시라도 나의 부족한 글이 참조링크들에 의한 것이 아님을 알아주길 바란다. (내가 못 쓴 것이다.)


References