ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 도커(docker) 내부구조(internal)
    SE General 2023. 11. 19. 23:24
    반응형

     

    함께 읽으면 좋은 글

     

     

     

    도커 엔진(Docker Enginer)은 컨테이너를 실행하고 관리하는 핵심 소프트웨어입니다. 도커 엔진은 주로 도커 그 자체로 부르기도 하는데요. 

     

    이번 글에서는 우리가 'docker' 커맨드로 컨테이너를 실행하는 CLU를 입력했을 때 무엇을 통해 어떻게 동작하는지 알기 위해, 도커 엔진의 내부구조를 살펴보겠습니다.

     

    Docker Engine - Image from Author inspired by [1]

     


     

    도커의 실행 구조

    우리가 도커로 컨테이너를 실행할 때에 흐름과 구조는 아래와 같습니다:

    Docker running structure - Image from Author inspired by [1]

     

    runc

    먼저, 가장 아래의 실행되고 있는 컨테이너는 그 위의 runc에 의해 실행됩니다. runc는 OCI(Open Container Initiaive) 컨테이너 런타임 스펙 구현체로 , Docker, Inc가 스펙을 정의하고 개발하는데에 깊은 관여를 하였습니다.

     

    부수적인 것들은 제외하면 runc는 작고, 가벼운 libcontainer [2]wrapper입니다.  libcontainer는 네임스페이스, cgroup, capabilites 그리고 파일시스템 접근 제어와 같이 컨테이너를 생성하는 데에 사용됩니다. runc의 단 한가지 목적은 컨테이너를 실행하는 것입니다. 그리고 runc는 그러한 libcontainer를 감싸고 있는 CLI이기 때문에, 다른 라이브러리 없이 runc만으로도 (복잡하지만) 컨테이너를 실행할 수 있습니다. 

     

    containerd

    기존 버젼의 도커를 리팩토링하며 모듈화하면서, 모든 컨테이너 실행 로직은 새로운 모듈인 containerd로 옮겨졌습니다. 이 containerd의 목적은 컨테이너 라이프사이클을 관리하는 것입니다(start | stop | pause | rm ...). 

     

    containerd는 Linux와 Windows에서 daemon으로 제공됩니다. 그리고 도커 엔진 기준으로, 위의 이미지와 같이 runc와 Docker daemon의 중간에 존재하게 됩니다. 

     

    초기에 containerd는 작게, 한정된 목적을 위해 개발되었으나 다양한 기능들(image pulling, volume, network 등)이 추가되면서 점점 복잡해져 왔습니다. 

     

    containerd는 원래 Docker, Inc에서 개발되었으나 CNCF(Cloud Native Computing Foundation)에 기증되어 관리되고 있습니다. 

     

     

    docker 컨테이너 생성 시의 흐름

    docker CLI를 통한 컨테이너 생성의 흐름은 아래와 같습니다:

     

    1. 'docker container run' CLI 실행 시, 클라이언트는 해당되는 Docker daemon의 (주로) socket API를 호출

    2. Docker daemon은 API 호출을 받아 containerd에 grpc를 호출하여 OCI 번들과 제공된 id를 기반해 새로운 컨테이너를 생성하도록 호출

    3. containerd는 Docker daemon의 호출을 받아 runc에 컨테이너를 생성하도록 호출

    4. 컨테이너를 빌드하고 시작한 후 컨테이너가 시작하면, runc는 종료됨(exit), shim이 컨테이너의 부모 프로세스가 됨

     

     

    shim은 무엇을 하는 것인가?

    위 구조에서 shim은 기능을 위해 고안된 컴포넌트입니다. 위에서 컨테이너들은 daemonless 컨테이너가 되게 되는데, 그 이유는 runc가 exit하고 shim이 컨테이너가 부모 프로세스가 되면서, 컨테이너와 daemon의 연결관계를 끊어주기 때문입니다. 이 특징은 실행되고 있는 컨테이너를 종료하지 않고도, daemon을 업그레이드하는 것을 가능하게 합니다. 

     

    shim은 그와 동시에 컨테이너의 부모 프로세스로써 아래와 같은 역할을 수행합니다:

     

    • STDIN, STDOUT 스트림을 열어두어 daemon을 재시작할 때, 컨테이너가 pipe이 close되는 등의 이유로 종료되지 않도록 함
    • daemon에 컨테이너의 exit 상태를 보고함

     

     

    Reference

    [1] Docker Deep Dive, Nigel Poulton

    [2] https://pkg.go.dev/github.com/opencontainers/runc/libcontainer

    반응형
Kaden Sungbin Cho