Docker는 Go언어로 작성된 리눅스 컨테이너 기반으로 하는 오픈소스 가상화 플랫폼이다.
Docker란 애플리케이션을 컨테이너화하여 실행할 수 있도록 돕는 플랫폼이다. Docker는 개발자가 애플리케이션과 그 환경을 독립적이고 일관성 있게 실행할 수 있게 해주며, 이를 위해 컨테이너라는 가상화된 환경을 사용한다. 컨테이너는 호스트 OS 위에서 실행되며, 애플리케이션과 그에 필요한 모든 라이브러리 및 종속성을 함께 패키징하여 배포한다.
이를 통해 개발, 테스트, 배포 과정에서 발생할 수 있는 환경 차이로 인한 문제를 해결하고, 애플리케이션을 다양한 환경에서 효율적이고 안정적으로 실행할 수 있게 한다. Docker는 Docker Engine을 통해 컨테이너를 관리하고, Docker Hub와 같은 저장소를 통해 이미지 공유가 가능하다.
Docker를 사용하면 저 사람 컴퓨터에서는 되는데 왜 내 컴퓨터에서는 안돼? 같은 문제가 해결된다.
가상화란 하나의 물리적 시스템(서버, 네트워크 장비 등)을 여러 개의 독립된 가상 시스템으로 분할하여 자원을 효율적으로 사용하는 기술이다.
가상 머신(Virtual Machine)이란 물리적 하드웨어 시스템에 구축되어 자체 CPU, 메모리, 네트워크 인터페이스 및 스토리지를 갖추고 가상 컴퓨터 시스템으로 작동하는 가상 환경이다.
요즘은 향상된 컴퓨터의 성능을 더욱 효율적으로 사용하기 위해 가상화 기술이 많이 등장했다.
서버가 CPU 사용률이 10%도 되지 않는다면 활용도가 낮은 서버들의 리소스 낭비일 것이다.
그렇다고 모든 서비스를 한 서버 안에 올린다면 안정성에 문제가 생길 수도 있다.
그래서 안정성을 높이며 리소스도 최대한 활용할 수 있는 방법으로 나타난게 서버 가상화이다.
가상화 전
가상화 후
가상화 기술 등장 이후, 한 개의 물리 서버를 두 개 이상의 가상 서버로 동작시킬 수 있게 되었다.
덕분에 더 이상 서버 리소스를 낭비하지 않고 효율적으로 사용할 수 있게 됐다.
대표적인 가상화 플랫폼으로는 VM이 있다.
Docker를 사용하면 팀원 및 서버와 개발 환경을 쉽게 동기화 할 수 있다.
개발을 하다보면 팀원들과의 언어나 프레임워크의 버전이 달라 오류가 나는 경우가 있다.
도커를 사용하면 이런 문제를 쉽게 해결할 수 있다. 도커 이미지에 언어나 프레임워크 버전을 미리 정해두었기 때문에 해당 이미지를 컨테이너화 시키면 그 컨테이너는 로컬 환경의 간섭 없이 독립적으로 구동하여 위와 같은 문제를 해결할 수 있다.
예를 들면 프론트엔드 개발자는 백엔드 개발자가 만든 웹 애플리케이션 서버를 Docker를 사용해 실행할 수 있다. 이때, 로컬에 설치된 자바 버전이나 프레임워크 버전과 관계없이 Docker 컨테이너 내에서 실행되는 서버는 백엔드 개발자가 설정한 환경 그대로 동작하게 된다.
가장 큰 장점은 서버를 옮기거나 늘릴 때 환경설정을 따로 할 필요가 없는 것이다.
만약 서버를 늘리거나 더 좋은 사양의 서버로 옮긴다면, 새로운 서버에 전 서버에서 사용하던 언어나 프레임워크를 설치해야 될 것이다.
이때 도커를 사용하면 이미지만을 가져와 서버에 컨테이너를 만들어 쉽게 동일한 환경을 구축할 수 있다.
또한, 하나의 물리 서버에서 여러 도커 컨테이너를 돌려 여러 서비스를 배포하는 것도 가능하다.
이때 각 서비스마다 같은 언어와 프레임워크를 사용해도 필요한 버전이 다를 수 있는데, 도커 컨테이너는 각각 독립적으로 구동되기 때문에 버전 차이에서 오는 이슈를 걱정할 필요가 없다.
물리적 서버에 설치된 버전이 아닌 각 컨테이너의 이미지에 정의된 버전의 언어나 프레임워크를 사용하기 때문이다.
컨테이너는 가상화 기술 중 하나로 대표적으로 Linux Container가 있다.
기존 OS를 가상화 시키던 것과 달리 컨테이너는 OS레벨의 가상화로 프로세스를 격리시켜 동작하는 방식으로 이루어진다.
Linux Container - 리눅스 컨테이너는 운영체제 수준의 가상화 기술로 리눅스 커널을 공유하면서 프로세스를 격리된 환경에서 실행하는 기술이다.
요약 - VM 가상화는 독립된 OS를 가지며 이 위에서 동작한다. 반면 Docker 가상화는 Host OS의 커널을 공유한다.
인프라 - 개발이나 서비스를 하기 위해 물리적으로 구성된 Network, DB, Server, Cloud 등을 의미한다.
Hypervisor - 호스트 컴퓨터로 다수의 운영체제를 동시에 실행하기 위한 논리적 플랫폼으로서 Guest OS와 Guest OS에서 구동되는 프로그램을 실제 물리적 장치에서 분리하는 프로세스이다.
하이퍼바이저를 통해 새로운 가상 서버를 생성하고, 물리 서버가 가진 컴퓨팅 리소스를 각 가상 서버에 할당해준다.
Container Engine - 유저가 컨테이너를 쉽게 사용할 수 있게 해주는 주체로써 이미지, 볼륨, 네트워크 관리와 컨테이너의 라이프 사이클 관리를 해준다.
Container Engine에서 가장 유명한 것이 Docker Engine이다.
하드웨어를 가상화하여 각 VM이 독립된 OS를 실행하도록 한다. 이를 위해 Hypervisor(VMware)가 사용되며, 각 VM은 자체 커널과 사용자 공간을 갖는다.
OS 수준에서 가상화를 수행한다. 모든 컨테이너는 호스트 OS의 커널을 공유하며, 애플리케이션과 필요한 라이브러리만 격리된다. VM보다 가볍고 실행 속도가 빠르며 리소스 효율적이다.
예시)
큰 건물에 여러 사무실이 입주해 있다고 생각하자.
이때 각 사무실은 전기와 물을 사용해야 한다. 이를 위해 각 사무실마다 발전소와 물탱크를 설치해야 된다면 비용이 엄청날 것이다. 이것이 VM 가상화이다.
이 방식이 아닌 건물에 있는 커다란 발전소와 물탱크를 각 사무실이 유동적으로 나눠 쓰는 방식이 Docker 가상화이다.
이것이 Docker 가상화가 효율적인 이유이다.
1) Host OS 위에 가상화를 시기키 위한 Hypervisor 엔진 그리고 그 위에 Guest OS를 올려 사용하기 때문에 거의 완벽하게 Host와 분리된다고 봐도 무방하다.
2) 높은 격리 레벨을 지원하여 보안적인 측면에서 더욱 유리하다.
3) 커널을 공유하지 않는 만큼 멀티 OS가 가능하다.
1) OS 위에 Guest OS를 올리기 때문에 무겁고 느리다.
2) 각 환경마다 사용할 수 있는 자원이 고정으로 정해져있기 때문에 컴퓨터의 성능과 환경이 제한된다.
1) Host OS, Docker 엔진 위에서 바로 동작하며 Host의 커널을 공유하기 때문에 IO 처리가 쉽게 되어 성능의 효율을 높일 수 있다.
2) 각 환경마다 사용할 수 있는 자원이 고정되어 있지 않다.
3) 성능향상, 뛰어난 이식성, 쉽게 Scale Out을 할 수 있는 유연성이 있다.
1) 우선 내 로컬 PC와 서버에 Docker를 설치한다.
2) 로컬 PC에서 Docker Image로 만들 Application이 있는 디렉토리에 Docker File을 생성하고, Docker build 명령어를 Docker File을 기반으로 Docker Image를 생성한다.
3) 생성된 Docker Image를 Docker push로 Docker Hub와 같은 Public 또는 Private 저장소에 업로드한다.
4) 서버에서 Docker pull 명령어로 해당 이미지 저장소에서 이미지를 받아서 docker run을 사용하여 Docker image를 기반으로 Docker Container를 실행시킨다.
Docker File은 Docker Image를 생성하기 위한 명령어와 설정을 정의한 파일로, 보통 이미지를 만들고자 하는 Application의 디렉토리 안에 생성한다.
이 파일에는 이미지 생성 과정에서 필요한 환경변수, 의존성, 실행 명령등을 포함하여 이미지의 구성을 지정한다.
이 Docker File을 빌드하면 Docker Image를 만들 수 있다.
Docker Image란 컨테이너를 실행할 수 있는 실행파일, 설정 값들을 가지고 있는 것으로, 더 이상의 의존성 파일을 컴파일하거나 이것저것 설치 할 필요 없는 상태의 파일을 의미한다.
Docker Image를 실행한 상태이다.
응용프로그램의 종속성과 함께 응용프로그램 자체를 패키징/캡슐화 하여 격리된 공간에서 프로세스를 동작시키는 기술이다.
Docker는 기본적으로 Server-Client 아키텍처를 사용한다.
Docker의 Client는 사용자의 입력을 받아서 Docker Daemon과 통신한다.
Docker Client와 Docker Daemon은 같은 시스템에서 실행되거나 UNIX 소켓, REST API 등으로 원격으로 통시도 가능하다.
사용자가 명령어를 입력하면 Docker Client가 Docker Daemon에게 전달하고, Docker Daemon이 Images에 해당 이미지가 있는지 확인하여 있다면 실행하고, 없다면 Registry에서 이미지를 가져와 실행한다.
Docker Client는 사용자와 상호작용 하는 곳이다.
명령어를 입력하면 Docker Daemon에게 Docker API를 통해 전달한다.
한 개의 Client는 두 개 이상의 Docker Daemon과 통신이 가능하다.
Docker Daemon은 Docker Client 측에서 보낸 명령어롤 Docker API를 통해 전달받고 Docker의 이미지, 컨테이너, 네트워크, 볼륨 등 Docker 객체를 관리한다.
Docker Registry는 Docker 이미지를 저장하는 공간이다.
개인 레지스트리를 구성할 수도 있으며, 공용 레지스트리인 Docker Hub도 존재한다.
Docker Compose는 여러 개의 Docker 컨테이너들을 하나의 서비스로 정의하고 구성해 하나의 묶음으로 관리할 수 있는 하나의 애플리케이션을 만드는 것이다.
Docker Compose를 사용하지 않을 경우에는 각각의 서비스를 따로 실행해야 하기 때문에 번거롭다.
Docker Compose는 여러 개의 컨테이너의 옵션과 환경을 정의한 파일을 읽어 컨테이너를 순차적으로 생성하는 방식으로 동작한다.
Docker Compose의 설정 파일은 도커 엔진의 run 명령어의 옵션을 그대로 사용할 수 있으며, 각 컨테이너의 의존성, 네트워크, 볼륨 등을 함께 정의할 수 있다.