도커 컨테이너 까보기(1) – Protocol, Registry

Docker 에 대해서는 정보가 넘쳐난다.
Docker 가 도대체 무엇이고 왜 필요한지… 이런 얘기는 길게 할 필요가 없을 것 같다.
기억을 더듬는 차원에서 먼저 간단히만 정리하고 넘어가자.

도커는 컨테이너인가?
아니다
.

도커는 컨테이너들을 효율적으로 관리하기 위한 관리 도구를 말한다.
컨테이너들을 쉽게 관리할 수 있으니, Application 을 배포하기가 굉장히 쉬워졌다.
그래서, 도커는 Application 배포에 특화된 기술이라고 할 수 있다.

컨테이너 기술은 예전부터 이미 존재해왔다.
자원을 특정 태스크 그룹에 할당하고, 리소스 들을 서로 고립화시키는 기술이 이미 있었다는 것이다.
그런데, 사용하기도 어렵고 대중화하기에는 한계가 있었다.
컨테이너 기술의 역사가 꽤 되었음에도 불구하고 널리 퍼지지 못한 이유가 이것이다.

이러한 기술을 획기적으로 조합해준 것이 도커이다.
스마트폰도 그렇지 않은가.
이미 다 있었던 기술들의 조합… 누군가 말했지. 창조도 별거아니네…;;
이미 존재하던 리소스 할당과 고립화 기술들을 잘 포장한 후 아래와 같이 기능들을 제공했다.
아래 기능들을 잘 보면 하나하나가 이식성과 관리효율성을 위해 꼭 필요한 기능 들이라는 것을 알 수 있다.

  • 호스트 운영체제의 영향을 받지 않는 실행환경 (Docker engine을 이용한 실행환경 표준화)
  • Dockerfile 을 이용한 컨테이너 구성 및 애플리케이션 배포 정의
  • 이미지 버전 관리
  • 레이어 구조를 갖는 이미지 포맷 (차분 빌드가 가능)
  • 도커 레지스트리(이미지 저장 서버 역할을 함)
  • 프로그램 가능한 다양한 기능의 API (Docker API 를 이용하여 관리 App 개발 가능)

오늘 첫번째 까볼 내용은 Docker 가 내부에서 사용하는 Protocol 과 Registry 에 관한 것이다. 
docker pull, docker create, docker run 등을 수행하게 되면, 이러한 operation 은 어떠한 형태로 docker engine 에게 전달되고 수행이 되는지 궁금했었다.

위의 그림을 보면 Client 와 Docker daemon, 그리고 Docker daemon 과 registry 사이에서 사용하는 인터페이스가 HTTP 라는 것을 알 수 있다.
Docker client 에서 Docker engine 쪽으로 명령을 내릴 때 HTTP 프로토콜을 사용한다.
좀 더 정확히 말하면 RESTful API 를 이용하여 Docker engine 에게 컨테이너 및 이미지 관리 등을 요청하는 operation 을 수행한다.
API 이외에도 Go 나 Python SDK 를 이용하여 Docker operation 을 수행하는 Application 을 개발할 수도 있다.
(Docker SDK 에 대해서는 이곳을 참조해보자.)
컨테이너나 이미지처럼 Docker 에서 관리하는 것들이 리소스 들이니, 리소스 다루기 좋게 만든 REST API 를 사용하는 것이 어쩌면 당연하다.
Client 가 Docker daemon 에게 보내는 Request 메시지는 아래처럼 생겼다.
Container 를 생성하라는 요청인 것을 쉽게 파악할 수 있다.
(리소스 관리에서 직관적인 인터페이스를 제공하는 것이 REST API 의 장점이기도 하다.)

POST /v1.24/containers/create HTTP/1.1
Content-Type: application/json
Content-Length: 12345

{
       "Hostname": "",
       "Domainname": "",
       "User": "",
       "AttachStdin": false,
       "AttachStdout": true,
       "AttachStderr": true,
...
}

반면에 Response 메시지는 아래처럼 생겼다.
이는 물론 Docker engine 이 요청 처리를 완료한 후 Client 에게 보내는 것이다.
json body 의 결과를 보면 생성된 Container ID 가 보인다.

HTTP/1.1 201 Created
Content-Type: application/json
{
     "Id":"e90e34656806",
     "Warnings":[]
}

Docker operation 을 위한 API 는 Docker version 별로 약간 차이가 있다.
자신의 Docker version 에 맞는 API reference 를 참조하자.
Docker 관련 API 는 다음의 4 가지 종류가 있다.
Docker API 도 사용되는 영역에 따라 category 별로 나뉘어져 있다.

아래 그림은 Docker 에서 제공하는 Docker engine API 의 종류이다.
우리가 docker 를 통해 수행하는 친숙한 많은 operation 들이 보인다.
이러한 Docker engine API 를 이용하여 우리는
(1) container 를 만들고, 기동하고, 삭제하고…
(2) image 를 만들고 push/pull 하고…
(3) volume 이나 network 구성을 할 수 있고…
(4) docker swarm 구성을 할 수 있고…
등등의 작업을 할 수 있는 것이다.

Docker API (출처 : Docker Architecture)

우리가 Docker engine 이 설치된 서버에서 docker 명령어를 수행하면 이는 Docker CLI(Command Line Interface) 를 이용하는 것이다.
Docker CLI 는 내부적으로 unix domain socket 을 사용하기 때문에 local 에서만 사용이 가능하다.
(local 서버에 /var/run/docker.sock 가 생성되어 있는 것을 볼 수 있다.)
만약 원격에서 Docker daemon 으로 operation 을 수행하고자 한다면, Docker deamon 으로 하여금 tcp socket 을 사용하도록 옵션을 변경하고 다시 기동해야 한다.
CLI(unix socket 이용)를 사용하건, tcp socket 을 이용한 remote API 를 사용하건 HTTP 와 json 을 사용하는건 같다.
아래 그림 처럼 Docker daemon 내의 HTTP server 가 Docker client 와의 유일한 접점이기 때문이다.

Docker server (출처: Docker source code analysis)

맨 위의 그림을 보면 Client 와 Docker Daemon 사이 뿐 아니라 Docker daemon 과 Registry 사이의 인터페이스도 HTTP 인 것을 볼 수 있다.
다를 이유가 없다.
registry 는 이미지가 저장되어 있는 곳이고, 이러한 이미지를 조회 및 변경 가능하도록 web 인터페이스를 제공한다.
좀 더 정확히 얘기하면 Docker registry API 를 이용하여 Docker daemon 과 registry 가 이미지 관련 소통을 할 수 있다.
이처럼 registry 로부터 이미지를 pull 하거나 push 하는 경우에도 HTTP 를 사용하는 것이 설계의 일관성 측면에서 좋을 것이다.


참고로, Docker 이미지를 관리하는 registry 의 종류는 3 가지가 있다.

  • Docker Hub : public registry
  • Other public registry
  • Private registry

Docker Hub 은 이미 다 알고 있는 공용 regstry 이고, 이외에도 공용으로 제공되는 registry 들이 존재한다.
local 에 private registry 용 container 를 생성하여 아주 쉽게 나만의 registry 를 구성할 수도 있다는 것도 알아두자.
docker pull 을 수행하면 디폴트로 docker hub 에서 이미지를 가져오게 된다.
만약 자체적으로 구축한 private registry 로부터 이미지 pull 을 하려면 아래와 같이 수행하면 된다. (port 번호는 local registry 구축 시에 지정할 수 있다.)
물론 registry server 와 client 양쪽에서 간단한 설정이 좀 필요하다. (나만의 registry 를 구성)

docker pull myregistry.local:5000/testing/test-image

private registry 를 반드시 local 에 구축해야하는 것만은 아니다.
예를 들어, gitlab.com 에서 회원가입을 한 후 아래와 같이 이를 자신의 private registry 로 사용할 수 있다.
회원 가입 후 자신의 project 를 생성할 수 있는데, 아래의 예에서 test_repo1 은 자신이 생성한 project 이름이다.
project repository 에 Docker container 이미지를 push 할 수 있다.
docker login 시에는 회원 가입 시 등록한 id 와 password 를 사용한다.
docker build 를 이용하여 local 에서 이미지를 만들면 local docker area 에 새로운 이미지가 만들어지고, docker push 를 통해 해당 이미지를 gitlab.com registry 에 올릴 수 있다.

docker login registry.gitlab.com

# Dockerfile 을 이용하여 image build
docker build -t registry.gitlab.com/cloudrain21/test_repo1 .

# local 에 생성된 이미지 확인
docker images | grep image_name

# build 한 이미지를 registry.gitlab.com 에 push
docker push registry.gitlab.com/cloudrain21/test_repo1

위의 과정을 수행하고 나면 gitlab.com 의 project 공간에 아래와 같이 image 가 upload 되어 있는 것을 확인할 수 있다.

push 한 이미지를 다시 pull 하고자 할 경우 아래와 같이 수행한다.

docker pull registry.gitlab.com/cloudrain21/test_repo1

# local 에서 image 검색
docker images | grep test_repo1
  registry.gitlab.com/cloudrain21/test_repo1   latest              2c5e00d77a67        3 months ago        188MB

AWS(Amazon Web Service)에서도 ECR(Elastic Container Registry)서비스를 통해 자신만의 Container Registry 를 구축할 수 있다.
구축하는 방법은 다른 registry 를 사용하는 것과 개념이 유사하기 때문에 이해하기 쉬울 것이다.
다만, AWS ECR 은 private registry 이고 public 은 지원하지 않는다고 한다.
각 repository 에 대한 AMI 유저나 role, AWS 계정의 권한을 조정하면서 사용할 수는 있겠다.
(How to make ECS repository public?)
그냥 public registry 는 docker hub 만을 사용하는 것이 맘 편할 듯 하다.


References
Docker Engine Overview
Docker Architecture
Docker Documentation
Docker 이미지 개인 저장소
Docker Private Registry
gitlab.com
AWS ECR 어렵지 않아요
Amazon ECR 의 도커 기본 사항

You may also like...