도커의 대략적인 구조
도커의 구조
흔히 말하는 도커라고 하면 docker engine을 말하지만 이러한 엔진도 내부 부분으로 나뉘며 엔진만 있어서는 구동이 되지 않는다. 다음 그림은 도커를 구동하기 위한 일련의 그림이다.
해당 그림은 docker 공식 홈페이지에서 갖고 왔다.
imgSource : https://docs.docker.com/get-started/images/docker-architecture.webp
크게 Client와 Host로 나뉘며 이미지 등록하고 내려받기 위한 Registry로 나뉜다. 여기서 Client와 Host는 같은 물리 서버에서 구동될 수도 있고 혹은 다른 물리서버에서 따로 구동되어 원격으로 통신 할 수 도 있다.
Docker client
도커 데몬과 상호작용하는 주체로 docker run과 같은 명령어를 Deamon에 보낼 수 있으며 둘 이상의 데몬과 통신할 수 있다. 이 docker 명령은 UNIX 소켓 또는 네트워크 인터페이스를 통해 REST API를 사용하여 통신한다.
Docker Host
Docker deamon이 여기에 위치하며 여기에서는 단순화하느라 빠져있는데 실상 Host의 구조는 아래와 같다.
dockerd
docker deamon이 하는 일은 아래와 같다.
컨테이너 관리
컨테이너의 생성, 실행 및 종료를 감독하는 것이다. Docker 클라이언트로부터 받은 명령에 따라 수행된다.
네트워킹 및 스토리지
Docker 데몬은 컨테이너에 네트워크 포트, 스토리지등 및 기타 중요한 구성 요소에 대한 액세스를 제공한다.
Registry에서 이미지 올리기 및 내려받기
요청된 이미지나 컨테이너가 로컬에 이미 없는 경우, Docker 데몬은 Docker Registry와 상호 작용하여 요청된 리소스를 가져오고 배포한다.
호스트 운영 체제와 통신
Docker 데몬은 호스트 운영 체제 리소스를 활용하여 컨테이너를 관리하게 되는데 이때 호스트 운영 체제의 커널과 통신하여 컨테이너 작업을 실행한다.
확장성과 유연성
Docker 데몬의 아키텍처는 제3자 도구 및 확장 프로그램과의 원활한 통합을 가능하게 한다.
client에서 새로운 컨테이너 생성 명령을 보냈다고 예를 들어보자. 그럴 경우 dockerd에서 이 명령을 수신하게된다. 그리고 새 컨테이너를 시작할 때, dockerd는 로컬 이미지가 있는지 확인하고 없다면 registry repository에서 해당하는 이름의 이미지를 가져오게된다.
logging drivers와 volume이나 volume drivers를 설정하는 등 컨테이너에 필요한 대부분의 설정을 통해 container에 필요한 대부분을 설정을 진행 한 뒤에 containerd를 호출하게되는데 dockerd는 API를 통해 gRPC로 containerd와 통신한다.
containerd
containerd는 Container의 생명주기를 관리하는 역할을 하며 High-Level Runtime이라 불리는데 High-Level Runtime은 보통 이미지 관리, gRPC/Web API와 같이 컨테이너를 관리하는 것 이상의 높은 수준의 기능을 지원하는 런타임을 의미한다. containerd는 원래 작고, 가벼운 Container lifecycle operations으로 설계되었는데, 시간이 지나면서 image pulls, volumes and networks와 같은 기능들이 확장되었다. 이런 것들은 모두 옵션이기 때문에 추가적인 구성을 통해 기능을 넣었다가 뺐다가 할 수 있다.
dockerd에서 gRPC로 명령을 받았다면 Docker 이미지를 가져와서 컨테이너 구성을 적용하여 runc가 실행할 수 있는 OCI 번들로 변경한 뒤 shim 프로세스를 사용하여 컨테이너 실행을 runc에게 위임한다.
runc
runc는 libcontainer용 CLI Wrapper로, 이전에 multi-platform을 지원하기 위해 libcontainer를 만들었다고 했는데 리팩토링 된 것이라고 생각하면 편하다.
이러한 runc를 Low-Level Runtimes이라고 부르며 Low-Level Runtimes는 보통 컨테이너를 운영하는 것에 초점을 맞춘 실제 컨테이너 런타임을 의미한다.
runc는 docker가 container 관련된 기능들을 쉽게 사용할 수 있도록 해주는 가볍고 이식가능한 툴이며 오직 Container 생성을 목적으로 존재한다.
shim
runc가 실행되고 Container를 생성한 뒤 바로 스스로를 종료시켜버리는데 이때 container의 관리를 위해 shim이 만들어진 container의 부모 프로세스가 된다. 그리고 이 프로세스는 containerd에게 컨테이너 file descriptor(e.g. stdin/out)와 종료 상태를 관리하는 데 필요한 최소한의 코드를 메모리에 남겨서 관리 할 수 있게 끔 만든다.
Registry
이미지가 업로드 되고 이미지를 다운로드 받을 수 있는 곳이다. docker-hub와 같이 public한 곳을 쓸 수 도 있고 개인적으로 직접 구축 할 수도 있다. 친절하게도 docker에서는 이러한 private한 docker-hub를 구축할수 있게 docker image를 제공하고 있다(!) 때문에 보안적인 부분이 걸려서 private한 곳에 hub를 두고 싶다면 이러한 이미지를 받아서 구동하여 사용하면 된다.