서버를 배포 할때 내 로컬 컴퓨터를 서버로 사용할 수 없기 때문에 우리는 다른 환경을 빌려 사용 한다. 하지만 내가 개발한 환경이 세계에서 유일한 환경이 아니고 너무나 많은 환경과 개발 생태계가 있기 때문에 우리는 배포할 때 새로운 환경에서 내 코드를 실행하기 위해 꽤나 많은 삽질을 하곤 한다. 이러한 점을 해결하기 위해, 그리고 비효율적으로 한 대의 서버를 하나의 용도로만 사용하지 않기 위해 이전부터 개발자들은 가상화 기술을 연구하고 사용했다.
그리고 이러한 가상화 기술을 가진 도커는 가상화의 한 종류인 컨테이너를 이용해서 프로세스를 격리시켜주는 소프트웨어이다. 이 도커 컨테이너 안에는 규격화된 라이브러리, 시스템 도구, 코드, 런타임 등이 포함되어 내가 만든 서버를 환경에 구애받지 않고 AWS든 Azure든 Google Cloud든 빠르게 구축, 테스트, 배포를 할 수 있다. DevOps 업계의 동향이 모놀리틱 배포에서 마이크로서비스 배포로, VM(Virtual Machine)에서 Container 쪽이 선호되면서 개발자들 사이에서 도커가 많이 사용 되고 있다. 오늘은 도커의 기술 기반에 대해 알아보자.
앞서 개발자들은 다른 환경에서 오는 문제점을 해결하기 위해 가상화 기술을 연구했다고 했는데 도커가 선택한 컨테이너 이전에는 하이퍼 바이저 기반의 가상화, 즉 VM (Virtual Machine)을 사용하였다. 하이퍼 바이저는 호스트 시스템에서 다수의 게스트 OS를 설치 및 가동할 수 있게 하는 소프트웨어이고, 하드웨어를 가상화하고 하드웨어와 각각의 VM을 모니터링하는 중간 관리자라 할 수 있다.
또한 하이퍼 바이저는 "네이티브형"과 "호스트형"으로 나뉜다.
"네이티브형"은 하이퍼 바이저가 하드웨어를 직접 제어하기 때문에 자원을 효율적으로 사용 가능하며, 별도의 OS가 없으므로 오버헤드가 적다. 하지만 여러 하드웨어 드라이버를 세팅해야하므로 설치와 사용이 어렵다는 단점이 있다.
"호스트형"은 일반적인 소프트웨어 처럼 호스트 OS 위에서 실행되며, 하드웨어 자원을 VM 내부의 게스트 OS에 에뮬레이트하는 방식으로 오버헤드가 크다. 하지만 게스트 OS 종류에 대한 제한이 없어서 하이퍼바이저 위에 기호에 맞게 윈도우, 리눅스 등을 설치해도 되는 편리함이 있다. 그렇게 때문에 구현이 다소 쉽다는 점이 장점이다. 결론적으로 주로 "호스트형"을 많이 사용한다.
"호스트형"을 좀 더 봐보면 하이퍼바이저에 의해 구동되는 VM은 각 VM마다 독립된 가상 하드웨어 자원을 할당 받는다. 위의 그림에서 하드웨어의 코어가 하나씩 각각의 VM에 할당되어있는 것을 볼 수 있다. 이렇게 분리되어 있기 때문에 한 VM에 오류가 발생해도 다른 VM에 영향을 끼치지 않는다.
어떤 환경에서나 실행하기 위해 필요한 모든 요소를 포함하는 소프트웨어 패키지.
컨테이너의 정의는 결국 VM의 목적과 같다. 도커가 선택한 이 기술도 갑자기 나온 것이 아니라 이러한 VM 기술부터 연구되고 있던 가상화 기술의 다른 버전이라고 할 수 있는 것이다. 대신 구동 환경을 얼마나 격리시키는지
에 따라 명확한 구분을 지을 수 있다.
도커는 격리된 환경(컨테이너)에 게스트 OS를 설치하지 않는다. 위의 그림에서 보면 오른쪽의 하이퍼바이저 기반 가상화 구조와 달리 각각의 격리된 환경에 OS가 포함되지 않은 것을 볼 수 있다. 컨테이너 방식은 어플리케이션 실행 시 호스트 OS의 커널을 공유하고 그 위에 어플리케이션의 실행 패키지인 이미지를 배포하기만 하면 되기 때문에 VM방식보다 오버헤드가 적고 가볍다. VM 방식은 어플리케이션 실행을 위해서 VM을 띄우고 자원을 할당한 다음, 게스트 OS를 부팅하여 어플리케이션을 실행 해야 해서 훨신 무겁다.
여기까지만 봐도 컨테이너 방식이 더 좋은 것 같은데, 위 사진 처럼 같은 커널을 공유하며 어떻게 격리된 환경(컨테이너)을 구축 할 수 있을까? 바로 리눅스
에서 제공하는 Cgroup(control group)과 네임스페이스(namespaces)를 사용하기 때문에 가능하다.
Cgroup은 CPU, 메모리, Network Bandwith 등 물리적 자원의 리소스 사용량을 관리할 수 있는 커널의 주요 기능이다. 어떤 어플리케이션 사용량이 너무 많다면 Cgroup에 집어 넣어서 CPU나 메모리 사용량을 제한해줄 수 있다.
네임스페이스는 하나의 시스템에서 프로세스를 격리 시킬 수 있는 가상화 기술이다. 이 기능을 통해 별개의 독립된 공간을 사용하는 것처럼 격리된 환경을 구축할 수 있다.
도커는 이 두 가지를 사용하여 한 컨테이너를 위한 물리적 환경을 한 Infrastructure에서 떼어내어 할당하고 가상화를 통해 격리 시키는 것이다.
그런데 이러한 도커의 동작 원리를 알고 도커를 설치해서 사용하다보면 나는 Mac OS를 사용해서 도커를 쓰고 있고 Cgroup과 네임스페이스는 리눅스 커널의 기능일텐데 이게 어떻게 작동하는 거지?
라는 의문이 든다. 도커는 정밀하게 구조를 살펴보면 내부적으로 Host OS 위에 리눅스 VM이 깔려있고, docker client와 docker server는 리눅스 환경에서 돌아가고 있다. 그래서 도커가 컨테이너를 활용한 가상화를 어느 환경에서든 사용할 수 있는 것이다.
터미널을 켜서 아래의 명령어를 실행하여 현재 도커 환경을 확인해보면 OS가 linux로 되어 있는 것을 확인해 볼 수 있다.
docker version
도커를 더욱 깊게 파보면 알아야 할 지식들이 굉장히 많을 것 같다고 생각한다. 도커를 공부해보며 OS나 하드웨어 지식의 필요성을 다시 한번 느끼게 된다. 앞으로 도커의 이미지와 레이어(Layer) 관리 방식 그리고 도커로 할 수 있는 여러가지 기술들을 공부해보며 개발 지식의 폭을 넓혀 봐야 겠다.