Docker를 왜 사용하는 것일까?
서버를 관리하는 일은 매우 복잡하고 어려운 작업이다. 만약 서버를 개발할 때 개발 환경이 바뀌게 되면 컴퓨터의 셋팅부터 프로그램의 설치까지 모든 것을 처음부터 다시 설정해야 한다. 시스템 환경, 방화벽, 네트워크 설정 등등 너무 많은 것을 환경이 바뀔때 마다 바꿔 주어야하는 것이다.
게다가 DevOps나 MSA가 유행하면서 서비스가 잘게 나뉘면서 관리가 더욱 복잡해지게 되는데 새로운 툴은 끊임없이 발전하고 설치해야할 서버가 매우 많아지는 상황에서 서버 관리 방식의 변화가 필요해진 것이다.
이때 이러한 환경 속에서 한줄기 빛처럼 등장한 것이 바로 Docker이다
Docker란
도커는 리눅스 컨테이너 리눅스 어플리케이션을 프로세스 격리기술을 사용해서 더 쉽게 컨테이너로 실행하고 관리 할 수 있게 해주는 오픈 소스 프로젝트이다.
무슨 말이냐 하면 다양한 프로그램들과 실행 환경을 컨테이너로 규격화시켜 프로그램의 배포 및 관리를 단순화 할 수 있다는 말이다. 화물선에 담긴 컨테이너를 떠올리면 편하다. 이때 컨테이너에는 프로그램의 코드 뿐만 아니라 실행에 필요한 모든 dependency들도 컨테이너에 담기 때문에 다른 환경에서도 빠르게 애플리케이션을 실행 할 수 있다.
그렇다면 위에서 말한 것처럼 실행/ 개발 환경이 달라도 컨테이너로 규격화한 프로그램들이 정상적으로 작동할 수 있는 이유는 바로 도커 컨테이너(도커 이미지)들은 모두 도커 엔진위에서 실행되기 때문이다.
도커 엔진은 컨테이너를 생성하고 관리하는 주체로서 이 자체로도 컨테이너를 제어할 수 있고 다양한 기능을 제공하는 도커의 프로젝이다. 도커의 생태계에 있는 여러 프로젝트들은 도커 엔진을 좀 더 효율적으로 사용하기 위한 것에 불과하다.
Virtual Machine VS Docker Container
위의 설명만 들으면 가상 머신과 굉장히 흡사한 방식을 생각해볼 수있다. 하지만 두개의 차이점은 분명히 있다.
Virtual Machine
기존의 가상화 기술은 Virtual Machines는 하이퍼 바이저를 이용해서 여러개의 운영체제를 하나의 호스트에서 생성하여 사용하는 방식이였다.
이러한 여러 개의 운영체제는 가상머신이라는 단위로 구별되고 각 가상 머신에는 우분투, CentOS등의 운영체제가 설치되어 사용된다. 그래서 하이퍼 바이저에 의해 생성되고 관리되는 운영체제는 게스트 운영체제라고 하며, 각 게스트 운영체제는 다른 게스트 운영체제와는 완전히 독립된 공간과 시스템 자원을 할당 받아 사용한다.
하지만, 각종 시스템 자원을 가상화하고 독립된 공간을 생성하는 작업은 하이퍼바이저를 반드시 거치기 때문에 일반 호스트에 비해 성능의 손실이 발생한다. 그 뿐만 아니라 가상 머신은 게스트 운영체제를 사용하기 위한 라이브러리, 커널 등을 전부 포함하기 때문에 가상 머신을 배포하기 위한 이미지로 만들었을때 이미지의 크기 또한 커진다.
장점
- 완벽한 운영체제를 생성할 수 있다.
단점
- 일반 호스트에 비해 성능 손실이 있다.
- 수 기가바이트에 달하는 가상 머신 이미지를 애플리케이션으로 배포하기에는 부담스럽다.
Docker Container
도커 컨테이너는 가상화된 공간을 생성하기 위해 리눅스 자체 기능인 chroot, 네임스페이스, cgroup을 사용함으로써 프로세스 단위의 격리 환경을 만들기 때문에 성능 손실이 거의 없다. 컨테이너에 필요한 커널을 공유해서 사용하고, 컨테니어 안에는 러플리케이션을 구동하는데 필요한 라이브러리 및 실행 파일만 존재하기 때문에 컨테이너를 이미지로 만들었을때 이미지의 용량 또한 가상 머신에 비해 대폭 줄어든다. 따라서 컨테이너를 이미지로 만들어 배포하는 시간이 가상 머신에 비해 빠르며, 가상화된 공간을 사용할 때의 성능 손실도 거의 없다.
도커의 구성요소
- Docker Client
- 도커를 설치하면 그것이 Client 이고, build, pull, run 등의 도커 명령어를 수행하게 된다.
- DOCKER_HOST
- 도커가 띄워져있는 서버를 의미한다. DOCKER_HOST에서 컨테이너와 이미지를 관리하게 된다
- Docker daemon
- 도커의 엔진이다
- Registry
- 외부 이미지 저장소이다. 다른 사람들이 공유한 이미지를 내부 도커 호스트에 pull 할 수 있다. 이렇게 가져온 이미지를 run하면 컨테이너가 된다.
도커 이미지
도커에서 서비스 운영에 필요한 서버 프로그램, 코드 및 라이브러리, 컴파일된 실행 파일 등을 묶는 형태를 도커 이미지라고 한다. 즉, 컨테이너 생성에 필요한 모든 파일과 환경을 가진 것으로, 더 이상 Dependency 파일을 컴파일하거나 이것저것 설치할 필요가 없는 상태의 파일을 뜻한다
예를 들어 우분투 이미지는 실행하기 위한 모든 파일과 Dependency들을 포함한다. 이러한 도커 이미지는 컨테이너의 상태가 바뀌거나 삭제되더라도 변하지 않는다. 따라서 다른 환경 혹은 서버에서 미리 만들어 놓은 도커 이미지를 다운로드하고 컨테이너를 생성하면 쉽게 원하는 환경을 구축할 수 있다.
이러한 도커 이미지를 실행(run)하면 도커 컨테이너로 된다. 도커 이미지는 도커 파일이라는 파일로 만들어지는데, 이러한 도커 파일에는 소스코드와 함께 의존성 패키지 등 사용한 설정 파일을 관리하기 쉽도록 명시된다.
도커 컨테이너
도커 컨테이너는 도커 이미지로 생성할 수 있다. 컨테이너를 생성하면 해당 이미지의 목적에 맞는 파일이 들어있는 호스트와 다른 컨테이너로부터 격리된 시스템 자원 및 네트워크를 사용할 수 있는 독립된 공간이 생성된다.
대부분의 도커 컨테이너는 생성될 때 사용된 도커 이미지의 종류에 따라 알맞은 설정과 파일을 가지고 있기 때문에 도커 이미지의 목적에 맞도록 사용되는 것이 일반적이다
ex) 웹 서버 도커 이미지로부터 여러개의 도커 컨테이너를 생성하면 생성된 컨테이너의 갯수 만큼 웹 서버가 생성되고, 이 컨테이너들은 외부에 웹 서비스를 제공하는데 사용된다.
컨테이너는 이미지를 읽기 전용으로 사용하되 이미지에서 변경된 사항만 컨테이너 계층에 저장하므로 컨테이너에서 무엇을 하든지 원래 이미지는 영향을 받지 않는다. 또한 생성된 각 컨테이너는 각기 독립된 파일시스템을 제공받으며 호스트와 분리되어 있으므로 특정 컨테이너에서 어떤 어플리케이션을 설치하거나 삭제해도 다른 컨테이너와 호스트는 변화가 없다.
ex) 같은 도커 이미지로 A, B 두 개의 컨테이너를 생성한 뒤에 A 컨테이너를 수정해도 B컨테이너에는 전혀 영향을 주지 않는다.
도커 레이어
도커는 레이어 라는 개념을 사용한다. 즉, 여러 개의 레이어를 나누어 이미지를 구성하게 된다. 예를 들어 apache이미지를 만든다고 생각해보자 그럼 기존의 우분투 이미지를 base Image로 이용하고, 그 위에 필요한 다른 레이어들을 얹어서 만들 수 있다.
이렇게 레이어 방식을 사용하면 기존의 이미지 레이어를 이용해서 다양한 이미지를 새로 만들수 있다. 또한, 기존 이미지를 이용하기 때문에 용량또한 절약할 수 있다.
컨테이너를 생성할 때도 레이어 방식을 이용해서 기존의 이미지 레이어 위에 읽기/쓰기 레이어를 추가한다. 이미지 레이어를 그대로 사용하면서 컨테이너가 실행중에 생성하는 파일이나 변경된 내용은 읽기/쓰기 레이어에 저장되므로 여러 개의 컨테이너를 생성하더라도 최소한의 용량만 사용하게 된다.
도커 허브
도커는 도커 허브를 통해 수많은 공개 이미지를 무료로 관리한다. 공개된 도커 이미지는 이미 50만개가 넘는다. 이처럼 누구나 쉽게 도커 이미지를 만들고 배포 할 수 있다.
호스트는 도커 허브에서 도커 이미지를 Pull해와서 실행시킬수 있다. 용량이 매우 큰 이미지들도 도커 허브에서 관리해주기 때문에 사용자는 부담없이 도커 이미지를 사용할 수 있다.