Docker 소개

Apr 20, 2016



보통 서버 응용 프로그램을 OS에 설치할 때, 프로그램 뿐만이 아니라 라이브러리(RPM, 팩키지 등)나 환경 변수 등을 설치/설정하기 마련이다. 프로그램이 계속 업그레이드되는 상황 속에서도 마찬가지로 그런 라이브러리나 환경 변수들이 조정되기도 한다. 즉, 서비스 운영 환경이 고정되지 않고 계속 변화한다고 말할 수 있다.

사이드킥 모듈

문제는 오토 스케일링 특성을 갖는 클라우드 서비스를 지향할 경우, 이런 서비스 운영 환경을 관리하기가 쉽지 않다는 것이다. 예를들어 서비스 모듈 여러개를 오프라인 상태에 두고 리퀘스트 증가에 따라 점차 온라인 상태로 활성화한다고 하자. 이러한 모듈들의 상태 관리는 사이드킥 모듈로 제어가 가능할 것이다. 하지만 버그가 발생해서 패치를 해야한다면? 이것도 사이드킥 모듈에서 구현해주면 된다. 그런데 또, 이번에는 RPM을 업데이트 할 필요가 생겼다. 만약 지금까지의 사이드킥 모듈이 RPM 패치에 대응하지 못했다면 사이드킥 모듈을 업그레이드하고나서 진행을 해야할 것이다. 그런데 이번에는 또, 이번에는 또.. 끝이 없다.

VM

사이드킥 모듈이 너무 비대해져서, 이번에는 아예 VM 환경을 복사하는 식으로 구축했다고 치자. 이제는 VM만 관리해주면 되기 때문에 한결 수월해졌다. VM이 가상이라한들 어차피 독립적인 머신이므로 각 VM마다 OS를 띄워야한다. 우리는 단지 서비스만 스케일링 되었으면 했는데, 이러한 OS로 인한 추가적인 리소스가 필요해졌다(!) CPU, 메모리, 스토리지는 물론이거니와 VM 이미지를 다른 물리 호스트로 복사함에 있어서도 시간이 걸리게된다. 즉, VM 기반의 스케일링은 헤비하다.

포터블 프로그램

(좀 억지인 이야기일 수도 있지만) 윈도우 사용자라면 간혹 포터블 프로그램을 사용한 적이 있을 것이다. 예를들어 크롬이나 파이어폭스 브라우저는 설치를 한 뒤 실행할 수도 있고 따로 포터블용을 받아서 설치없이 바로 실행할 수 있다. 이는 포터블 exe 파일에 실제 실행할 프로그램과 함께 필요로하는 라이브러리들과 환경 변수들이 하나의 파일로 팩키징 되어 있기 때문이다. 포터블 프로그램은 몇가지 이유로 선호되는데 우선은 설치가 필요없기 때문에 빨리 실행할 수 있고, 레지스트리나 쓰레기 파일들을 남기지 않아서 (그렇지 않은 것도 많지만) 부담없이 삭제할 수 있다. 특히 OS가 더러워지는 것을 싫어하는 유저로부터 후자의 이유로 인해 선호된다. OS가 더러워지는게 싫다는 것은, 결국 OS 환경이 바뀜에 따라 다른 프로그램이나 서비스들에 악영향이 갈 소지가 있기 때문이다. 그렇다고 VM을 쓰기에는 게스트 OS로 인한 추가적인 리소스가 부담된다.

하지만 포터블 프로그램도 결국 응용 프로그램이다. 현재 사용자와 같은 유저 공간을 사용하며 동일한 파일 시스템을 사용한다. 예를들어 탐색기가 바라보는 C:\ 폴더와 각 포터블 프로그램이 바라보는 C:\ 폴더는 모두 동일하다. 포터블 프로그램이라고 해서 OS의 레지스트리를 핸들하지 못하는 것도 아니다. 즉, 포터블은 가상화가 포함되어 있지 않다.

Docker

사이드킥은 배포가 어렵다. VM은 헤비하다. 포터블은 가상화 개념이 없다. Docker는 이러한 단점들을 적절히 상쇄시켜 줄 만한 특성을 가지고 있다. Docker에 대해 이야기를 하기 전에 우선 컨테이너부터 알고 갈 필요가 있다.

오래전부터 리눅스는 chroot 명령을 제공했는데 chroot는 유저의 루트 디렉토리를 지정한 디렉토리로 변경하고 chroot jail이라는 독립적인 환경을 생성해준다. 이 디렉토리와 환경을 벗어날 수 있는 유저는 오로지 root 뿐이므로, 다른 유저들이 시스템 디렉토리에 접근하는 것을 막을 수 있다. 그러나 chroot jail에 들어갈 실행 파일이나 라이브러리들을 직접 준비해야하기 때문에 설정이 복잡하며 그렇다고 완벽한 가상 환경도 아니었다.

이 후 리눅스는 커널단에서 가상화 관련 API를 제공하기 시작했는데 이 API의 목적은 애플리케이션을 위한 가상 공간을 제공함에 있다. 그 중 cgroups(control groups)는 가상 공간에 CPU, 메모리, 블록 I/O, 네트워크 등과 같은 리소스를 제공하고 namespaces는 프로세스 트리, 사용자 ID, 마운트된 파일 시스템 등의 운영 환경을 제공해준다. LXC(LinuX Containner)는 이러한 커널단 API를 절충한 라이브러리로서 서비스 운영 환경만을 담은 독립적인 가상 공간, 즉 컨테이너를 제공한다. Docker 초기에는 LXC를 기반으로 구현되었으며 지금은 libcontainer라는 별도로 작성한 라이브러리를 통해 cgroups와 namespaces를 사용한다.

사실 컨테이너만 필요하다면 LXC만 사용해도 되지만 LXC는 컨테이너의 생성 및 관리, 배포에 대한 부가 기능이 없기 때문에 실제 서비스를 운용하기에는 부족함이 있다. Docker는 이를 보충하여 컨테이너에 대한 부가 기능을 제공하고 컨테이너의 상태를 이미지화하여 배포를 손쉽게 해준다.