Docker & Container

컴퓨터의 성능이 향상되면서 가상화라는 단어는 일반적이되었습니다. 
가상머신을 구현하기 위하여 VMWARE, KVM, Hyper-V 기술들을 사용하였으나, 최근에는 Docker로 대표되는 LXC (Linux Containers) 와 같은 컨테이너형 가상화쪽으로 화제가 옮겨가고 있습니다.
컨테이너형 가상화 기술은 기존의 가상화 기술보다 가벼워 지고, 이식성이 뛰어난 특징을 가지고 있습니다.
Virtulization_vs_Container

LXC ( Linux Container)

LXC ( Linux Container)
Linux 컨테이너를 살펴보자면 OS의 내부는 물리적 자원을 관리하는 ‘커널 공간 “과 사용자 프로세스 (애플리케이션)을 실행하는”사용자 공간 “으로 나뉩니다. 
컨테이너 형 가상화는 사용자 공간을 여러 개로 나누어 각각의 사용자 프로세스에서 보이는 리소스를 제한하는 것입니다. 
이와 같이 여러 사용자 프로세스를 정리하여 분리한 사용자 공간이 바로 ‘컨테이너’입니다.

1. LXC ( Linux Containers) 란?

  • LXC = Linux Containers
Note

LXC (LinuX Containers)는 단일 컨트롤 호스트 상에서 여러개의 고립된 리눅스 시스템 (컨테이너)들을 실행하기 위한 운영 시스템 레벨 가상화 방법이다.  리눅스 커널은 cgroups를 절충하여 가상화 머신을 시작할 필요 없이 자원 할당 (CPU, 메모리, 블록 I/O, 네트워크 등)을 한다. Cgroups는 또한 애플리케이션 입장에서 프로세스 트리, 네트워크, 사용자 ID, 마운트된 파일 시스템 등의 운영 환경을 완전히 고립시키기 위해 namespace isolation을 제공한다.  LXC는 cgroups와 namespace를 결합하여 애플리케이션을 위한 고립된 환경을 제공한다. Docker 또한 실행 드라이버의 하나로 LXC를 사용할 수 있으며 이를 통해 이미지 관리와 개발 서비스를 제공한다.
– 위키페디아

LXC는 Linux 커널에서 컨테이너 관련 기능이 구현되기 시작한 2008 년경부터 커널 기능만을 이용하여 컨테이너 역할을 할 수 있는 소프트웨어로 개발되고 있습니다. 
Linux 커널을 패치 할 필요없이 커널에 구현되어있는 컨테이너에 관련된 기능을 활용하여 컨테이너 관리 작업을 할 수 있습니다.

2. 기존 가상화 기술과 LXC 차이점

널리 사용되고있는 가상화 기술로는 Xen과 KVM이 있으며, 이것을 사용하여 호스트 OS (또는 하이퍼 바이저)에서 가상 머신 환경을 만들고 그 위에 OS를 실행시켜 여러 OS 환경을 구축할 수 있습니다.

KVM과 같은 기존의 가상화 기술에서는 가상머신이 실제 물리적인 하드웨어를 Emulate하기 때문에 OS가 반드시 필요합니다. 즉 왼쪽의 그림처럼 OS 위에서 또하나의 OS가 동작하는 형태입니다.
이 경우 가상머신을 실행하는 호스트 OS와 게스트 OS를 완전히 분리 할 수​​있는 장점은 있지만, 하드웨어에서 시뮬레이트하기 때문에 오버 헤드가 증가하는 단점도있습니다.
 
Linux Container는 오른쪽 그림과 같이 모든 프로세스는 호스트 OS에서 바로 시작합니다. 일반적인 프로세스의 동작과 다른 점은 그 과정의 일부를 그룹화하고 다른 그룹이나 그룹에 속하지 않는 프로세스에서 단절된 공간으로 동작하는 것입니다.
화물 컨테이너처럼 독립된 공간에 프로세스가 들어 있기 때문에 이 공간을 ‘컨테이너’라고 부르는 것입니다. 
컨테이너 간에는 다른 컨테이너의 내부를 볼 수 없습니다.
결론적으로 Linux Container는 Xen과 KVM 등 가상화 기술과는 다르게, 가상 머신을 생성하는 것이 아니라 OS가 사용하는 자원을 분리하여 여러 환경을 만들수 있도록 하는 것입니다.
이러한 방식이기 때문에 하드웨어 시뮬레이션이 필요없기 때문에 가상화 오버 헤드는 거의 존재하지 않으며, 또한 가상 머신 부팅 및 종료라는 개념이 존재하지 않기 때문에 가상 환경의 시작과 종료를 빠르게 실행할 수 있습니다.

3. LXC의 장점과 단점

기존의 가상화 기술들은 하드웨어 환경을 가상화하는데 비해 컨테이너 방식은 OS에서 관리되기 때문에 “OS 레벨의 가상화”라고 불리기도합니다. 

3.1 컨테이너의 장점

빠른 시작과 종료 속도

LXC를 사용하다 보면, KVM과 Xen, VMware와 같은 가상화 기술에 비해 가상 환경 생성과  시작/종료가 빠르다는 것을 알 수 있습니다. 
컨테이너를 생성하는 것은 OS 입장에서 보면 단순하게 프로세스를 시작하는 것이기 때문에 일반적인 프로세스가 시작하는 것과 별반 차이가 없습니다. 즉 매우 빠르게 시작할 수 있는 것입니다.
LXC에서는 가상 환경이 커널에서 공유되기 때문에 새로운 커널을 시작할 필요가 없으며, 또한 하드웨어 초기화 등의 작업도 필요 없습니다. 

높은 집적도

컨테이너는 커널이 직접 프로세스를 조작하여 분리된 공간을 구성하기 때문에 컴퓨터상에서 동작하는 OS는 하나입니다. 
최소 2 개의 OS가 동작해야하는 가상머신 기술에 비하면 소비하는 자원은 줄어 들 수 뿐이 없습니다. 
여러 개의 컨테이너를 만들어서 실행 중이라고 해도 OS는 하나이므로, 가상머신에 비해 고밀도화가 가능합니다.
또한 컨테이너에서는 실행되는 프로세스를 위한 메모리만 필요하기 때문에 낮은 사양의 환경에서 더욱 활용도가 높아집니다. 

낮은 오버헤드

가상화를 위한 하드웨어 에뮬레이트 (emulate) 단계 없이, 분리된 공간을 만들기 때문에 오버 헤드가 줄어 듭니다.

애플리케이션 컨테이너 지원

컨테이너는 가상머신과는 달리 init을 먼저 시작하거나 각종 데몬들을 실행할 필요가 없습니다. 
컨테이너는 목적에 맞는 프로세스만 존재하는 환경을 만들 수 있습니다. 즉 웹서버용 컨테이너라면 Apache Httpd 프로세스만 존재하는 컨테이너를 만들수 있습니다.
이러한 환경을 애플리케이션 컨테이너라고합니다. 물론 init를 처음 시작하여 보통의 OS가 시작하는 것과 같은 환경을 만들 수 있습니다. 이것은 시스템 컨테이너라고합니다.

3.2 컨테이너의 단점

반대로 컨테이너 구조에서 비롯되는 단점도 있습니다.

Host OS 에 종속적

리눅스 컨테이너는 OS에서 Linux Kernel이 관리하는 것이므로, 당연히 Linux 이외의 다른 OS 에서는 동작하지 않으며, 컨테이너 환경에서도 다른 OS를 설치할 수 없습니다.
컨테이너에 Linux의 모든 배포판은 설치할 수 있지만, 실행중인 커널은 하나이기 때문에 엄밀하게는 컨테이너는 Host OS 의 커널을 사용하게 됩니다.
예를 들어 Ubuntu Host OS에서 컨테이너에 CentOS를 설치한다고 해도 실행중인 커널은 Ubuntu 커널입니다.

컨테이너별 커널구성이 불가능

정확하게는 커널에 관련된 작업은 가능합니다. 그러나 컨테이너마다 다른 커널 작업을 수행 할 수는 없습니다. 커널의 기능으로 구성되는 환경이기 때문에 당연히 전체 컨테이너에서 보이는 커널은 동일합니다.
따라서 컨테이너에서 보이는 장치나 로드되는 커널 모듈은 모두 동일합니다.
 
이상과 같이 LXC의 장점과 단점을 살펴보았습니다. 무엇보다도 컨테이너형 가상화가 유리한 유즈케이스에 잘 활용하는 것이 중요하겠습니다.

4. LXC 는 어떻게 구현될까요?

LXC와 비슷한 기술로 “chroot”라는 것이 있습니다. 
chroot는 프로세스의 루트 디렉토리를 변경하는 것으로, 이를 통해 프로세스가 액세스 할 수있는 디렉토리를 제한하거나 시스템 라이브러리와 관련 라이브러리를 로드 할 수있다. 
그러나 chroot에서 제어 할 수있는 파일이나 디렉토리에 대한 액세스만으로, 네트워크 및 프로세스 등을 컨트롤 할 수는 없습니다.
또한 FreeBSD 에는 chroot를 발전시킨 툴로서 “jail”라는 기능이 탑재되어있습니다. jail는 파일 시스템에 대한 액세스뿐만 아니라 프로세스 및 장치 등의 자원에 대해서도 제어가 가능합니다. 
LXC가 jail과 유사한 개념으로 구현 되었습니다.
cgroups은 OS가 관리하는 다양한 리소스를 중앙에서 제어하기 위한 도구입니다. 리소스를 그룹화하고 각 그룹에 대해 우선 순위 및 사용 가능한 리소스를 제한하거나 그룹을 분리하고 다른 그룹에서는 보이지하는 등 기능을 제공합니다.
cgroups에서 관리하는 대상은 파일 시스템이나 프로세스뿐만 아니라 CPU 리소스와 메모리, 각종 디바이스, 네트워크 패킷, 네트워크 인터페이스 등 입니다. 
cgroups의 이용 예로는 특정 프로세스에서 사용 가능한 메모리와 CPU 시간 등을 제한하는 것이 있으며, LXC는 프로세스에 대해 chroot 같이 특정 디렉토리를 루트 디렉토리로 인식하도록하며 cgroups의 네임 스페이스 기능을 사용하여 다양한 자원을 격리함으로써 가상 환경을 구현합니다.
 
컨테이너마다 분할되는 자원에는 다음과 같은 것이 있습니다.
  • 프로세스 테이블 :
    컨테이너마다 별도의 프로세스 테이블를 관리하여 컨테이너의 프로세스에서 다른 컨테이너의 프로세스가 보이지 않도록합니다.
  • 파일 시스템 :
    컨테이너마다 특정 디렉토리를 루트 파일 시스템으로 보이게 합니다. “chroot”와 동일한 개념입니다.
  • 네트워크 :
    네트워크 네임 스페이스 (netns)의 기능은 컨테이너마다 별도의 네트워크 설정을 구성합니다. “veth”라는 가상 NIC 장치를 이용하여 veth의 한쪽을 컨테이너 내부 네임 스페이스에 할당합니다.
  • CPU, 메모리 장치 ( “/dev”다음 장치 파일) :
    cgroups의 기능은 컨테이너에서 사용할 수있는 범위를 제한합니다.

5. LXC 와 Linux 컨테이너 기술들

LXC 외에도 Linux에서 컨테이너를 실현하기위한 소프트웨어는 여러가지 있으며, 다음에서 대표적인 몇가지를 설명합니다. 
( OpenVZ, Virtuozzo, libvirt, Docker, systemd, Warden)  

OpenVZ

OpenVZ 는 Linux 커널에 컨테이너 관련 기술이 충분히 구현되지 않은 오래전부터 Linux 커널에 패치 컨테이너를 구현한 것입니다. OpenVZ와 그것을 바탕으로 한 상용 소프트웨어 인 페러럴즈의 Virtuozzo 는 이전부터 전세계의 호스팅 서비스에서 널리 사용되어 왔으며, 현재에도 널리 사용되고 있는 안정적인 상용 소프트웨어입니다. 현재 Linux 커널에 구현되어있는 컨테이너 관련 구현은 OpenVZ 에서 유래한 것이 많이 있고, 현재에도 OpenVZ 개발자가 구현을 추진하고있는 기능이 존재합니다.

libvirt

libvirt 는 가상 머신을 수행 공통 API를 제공하는 라이브러리에서 다양한 가상화를 지원합니다. 그 중에서도 “LXC”을 지원합니다.

Docker

Docker 는 Docker Inc.에 의해 개발 된 Go 언어로 작성된 소프트웨어입니다. 원래는 컨테이너를 실현하기 위해 LXC을 사용하고있었지만, Docker 0.9 버전 부터는 기본으로 직접 만든 자체 컨테이너를 사용하고 있습니다. Docker는 단순한 컨테이너의 구현을 넘어 컨테이너 기반 가상화 에코시스템을 구축하고 있습니다.
 
이 외에도 systemd에 간단한 컨테이너를 제공하는 명령이 포함되어 있고, Cloud Foundry에서 컨테이너 기능을 실현하기위한 Warden 등 일부 컨테이너의 구현이 있습니다, 물론 Linux 이외에도 컨테이너의 구현은 몇 하나 존재합니다.

References