오픈 소스인 도커는 컨테이너형 가상화 기술을 구현하기 위한 상주 애플리케이션(dockered demon이 상주 실행) 이 애플리케이션을 조작하기 위한 명령행 도구(CLI)로 구성되는 기술입니다.
애플리케이션 배포에 특화돼 있기 때문에 애플리케이션 개발 및 운영을 컨테이너 중심으로 수행할 수 있습니다.
도커는 기존 가상화 소프트웨어보다 훨씬 가볍게 동작합니다. 그러므로 테스트 환경뿐만 아니라 운영 환경에서도 컨테이너를 사용할 수 있습니다.
도커는 이식성이 뛰어납니다. 로컬 머신의 도커 환경에서 실행하던 컨테이너를 다른 서버에 있는 도커 환경에 배포하거나 반대로 다른 서버의 도커 환경에서 동작하던 컨테이너를 로컬로 가져올 수 있습니다.
즉, 개발 환경과 운영 환경을 거의 동등하게 재현할 수 있습니습니다.
하지만 도커도 만능은 아닙니다. 리눅스 계열 운영 체제의 동작이 요구되는 가상 환경을 구축하거나 비리눅스 환경(FreeBSD) 이 필효한 경우에도 VMWare나 VirtualBox 같은 기존의 가상화 소프트웨어를 사용하는 것이 낫습니다. 하지만 기존의 가상화 소프트웨어를 컨테이너형 가상화인 도커와 비교하면 구조적으로 오버헤드가 큽니다.
도커는 컨테이너형 가상화 기술을 사용합니다. 도커는 초기에 컨테이너형 가상화를 구현하는 데 LXC(리눅스 컨테이너)를 런타임으로 사용했지만 현재는 runC를 런타임으로 사용합니다.
컨테이너형 가상화를 사용하면 가상화 소프트웨어 없이도 운영 체제의 리소스를 격리해 가상 운영 체제로 만들 수 있습니다.
컨테이너형 가상화 기술을 사용해서 컨테이너를 쉽게 만들고 사용하고 버릴 수 있다는 점이 도커의 주요 특징 중 하나입니다.
LXC는 호스트 운영 체제 가상화보다 성능 면에서 유리합니다.
LXC에서는 복제한 애플리케이션을 다른 LXC 호스트에서 실행했을 때 LXC 설정의 차이로 인해 기대했던 대로 애플리케이션이 동작하지 않는 등의 크리티컬한 문제가 있었습니다. 반면 도커는 컨테이너가 갖는 성능적 이점을 잘 살리면서도 애플리케이션 배포에 초점을 맞췄습니다. 도커와 LXC의 차이점은 다음과 같습니다.
도커는 컨테이너 정보를 Dockerfile 코드로 관리할 수 있습니다.
이 코드를 기반으로 복제 및 배포가 이루어지기 때문에 재현성이 높습니다.
먼저 등장한 LXC를 넘어서서 배포 스타일이 도커 기반으로 확립되고 보급된 것은 이러한 점들 때문입니다.
도커가 어떤 방식으로 배포가 이루어지는지 살펴보겠습니다.
helloworld라는 이름으로 셸 스크립트 파일을 만듭니다. 단순한 스크립트지만 여기서는 이것이 애플리케이션 역할을 합니다.
#!/bin/sh
echo "Hello, World!"
이제 이 스크립트를 도커 컨테이너에 담아 보겠습니다. Dockerfile이나 애플리케이션 실행 파일을 사용해서 도커 컨테이너의 원형이 될 이미지를 만드는 과정을 도커 이미지 빌드라고 합니다.
FROM ubuntu:16.04
COPY helloworld /usr/local/bin
RUN chmod +x /usr/local/bin/helloworldCMD ["helloworld"]
Dockerfile의 FROM 절은 컨테이너 원형 역할을 할 도커 이미지(운영체제)를 정의합니다. 여기서는 우분투 도커 이미지를 지정했습니다.
COPY 절은 조금 전 작성한 셸 스크립트 파일을 도커 컨테이너 안의 /usr/local/bin에 복사하라고 정의한 것 입니다.
RUN 절은 도커 컨테이너 안에서 어떤 명령을 수행하기 위한 것입니다. 여기서는 helloworld 스크립트에 실행 권한을 부여하기 위해 사용했습니다. 여기까지가 도커 빌드 과정에서 실행되며 결과로 새로운 이미지가 생성됩니다.
CMD 절은 완성된 이미지를 도커 컨테이너로 실행하기 전에 먼저 실행할 명령을 정의합니다. 여기서는 사실상 애플리케이션을 실행하는 명령을 지정했습니다.
이 Dockerfile을 사용해 이미지를 빌드하고 실행해 보겠습니다.
Dockerfile이 있는 폴더에서 docker image build 명령을 실행합니다.
$ docker image build -t helloworld:latest .
Sending build context to Docker daemon 97.5MB
빌드가 끝난 다음 docker container run 명령으로 도커 컨테이너를 실행하는 것이 기본 사용법입니다.
$ docker container run helloworld:latest
Hello, World!
이런 방식으로 도커 이미지에 애플리케이션에 필요한 파일을 운영 체제와 함께 담아서 컨테이너 형태로 실행하는 것이 기본 스타일입니다.
지금 본 예제는 셸 스크립트를 우분투 운영 체제와 함께 컨테이너로 실행한 것입니다.
조금 전 예제에서는 echo 명령을 한 번 실행하는 스크립트를 지정해서 도커 컨테이너를 실행하자마자 스크립트가 실행되고 종료됩니다.
하지만 실제 개발에서 도커 컨테이너로 배포되는 대상은 주로 웹 애플리케이션이나 API 애플리케이션처럼 항상 가동되는 것들입니다.
예를 들어 Node.js 웹 애플리케이션을 배포 대상으로 하는 상황을 가정해 보겠습니다. 애플리케이션은 계속 실행된 상태로 남아있을 것이고, 이미지 빌드도 좀 더 복잡할 것입니다. 애플리케이션이 의존하는 Node.js 버전의 기반 이미지를 이용하되, npm으로 모듈을 추가 설치하거나 애플리케이션 빌드를 컨테이너 안에서 수행해 이미지를 만듭니다. 애플리케이션 실행은 echo 같은 간단한 스크립트와 큰 차이가 없습니다. 완성된 이미지는 도커가 실행되는 환경이라면 어떤 환경에서도 실행할 수 있습니다. 호스트 운영 체제에 Node.js나 npm을 설치할 필요가 전혀 없습니다.
이름 | 역할 |
---|---|
Moby | 컨테이너 기술을 이끄는 오픈 소스 프로젝트로, 다양한 컴포넌트를 제공합니다. |
Docker CE | Moby 프로젝트에서 개발된 컨테이너 관련 컴포넌트를 조합한 무료 제품입니다. 지금까지의 도커는 이 버전을 가리킵니다. |
Docker EE | 도커의 상용 버전입니다. |
Moby가 개발 프로젝트고 도커는 Moby에서 개발하는 컴포넌트 및 도구의 집합체인 제품의 관계입니다.
제품으로서의 도커는 CE와 EE로 나뉘어 승계됩니다.
추상적인 컨테이너 계열 컴포넌트 군을 Moby 프로젝트에서 개발하고 제공하기 때문에 컨테이너 기술 개발자는 도커 이외의 선택지를 자신이 직접 개발하거나 이미 도커에서 사용되는 유용한 컴포넌트를 자유롭게 취사 선택할 수 있습니다.
도커사는 Moby 프로젝트와 함께 새로운 리눅스 배포판인 LinuxKit를 오픈 소스로 공개했습니다. 윈도우/맥용 도커는 이 LinuxKit를 경량 서브 시스템으로 사용해 도커를 실행합니다.
윈도우 macOS에서는 도커를 있는 그대로 동작시킬 수가 없습니다. 그 때문에 윈도우 및 macOS 사용자는 VirtualBox를 경유하는 형태로 도커를 사용해왔습니다. 이러한 방법은 번거롭기도 하거니와 성능적으로도 오버헤드가 큽니다. LinuxKit은 이러한 문제를 해결하기 위한 대책입니다. 윈도우용, macOS용 도커에는 LinuxKit이 포함돼 리눅스 서브 시스템을 제공하고 그 위에서 도커가 동작하는 형태로 오버헤드를 감소시킵니다.