Docker 의 개념 및 핵심 설명
Docker 란 Go 언어로 작성된 Linux 컨테이너 기반의 오픈소스 가상화 플랫폼이다.
컨테이너란?
컨테이너는 가상화 기술 중 하나로 대표적인 컨테이너는 Linux Container (이하 LXC) 가 있다.
기존 OS 가상화와는 달리 컨테이너는 OS 레벨의 가상화로 프로세스를 격리시켜 동작하는 방식 으로 이루어진다.
한 서버의 여러 OS 를 가상화 하는 것과 컨테이너 방식으로 프로세스를 격리시켜 동작하는 방법은 어떠한 차이점이 있을까?
컨테이너와 VM (가상머신) 의 차이
기존에 우리에게 익숙한 VM 같은 경우엔 Host OS(운영체제) 위에 가상화를 시키기 위한 Hypervisor 엔진 그리고 그 위에 Guest OS 를 올려 사용한다. 이는 가상화된 하드웨어 위에 OS가 올라가는 형태로 거의 완벽하게 Host 와 분리된다고 봐도 무방하다. 반면에 컨테이너 기반 가상화는 Docker 엔진 위에 Application 실행에 필요한 바이너리가 올라가게 된다. OS 가상화를 보면 Host OS 와 완전히 분리되는 장점은 있찌만 OS 위에 OS 를 올리기 때문에 무겁고 느릴 수 밖에 없다. 하지만 컨테이너 기반 가상화는 Host OS 그리고 Docker 엔진 위에서 바로 동작하며 Host 의 커널(운영체제의 핵)을 공유한다.
커널을 공유하게 되면 io 처리가 쉽게 되어 성능의 효율을 높일 수 있다.
컨테이너를 사용하는 것은 가상 머신을 생성하는 것이 아니라 HOST OS가 사용하는 자원을 분리하여 여러 환경을 만들 수 있도록 하는 것이다.
그러면 다들 컨테이너기반 가상화를 쓰지 VM 은 왜씀...?
위에서 정리한 내용 대로면 컨테이너기반이 OS 가상화보다 뛰어나다라고 말하는 것 같지만 실제로 그렇지만은 않다.
단지 이 포스팅이 Docker 를 소개하는 글이다 보니 컨테이너 기반 가상화의 장점을 강조하여 Docker 를 왜 사용해야하는지에 대해 설명을 한 것 뿐이다.
VM 을 이용한 OS 가상화는 컨테이너기반 가상화보다 더 높은 격리 레벨을 지원한다. (하드웨어를 다른 걸 쓰는 거랑 같은 원리니 어찌보면 당연하다) 이는 자연스레 보안적인 측면에서 더욱 유리하게 작용한다.
또한 커널을 공유하지 않는 것이 장점으로 작용한다. 커널을 공유하지 않는 만큼 멀티 OS가 가능하다는 것이다. 커널을 공유하지 않아 멀티 OS 가 가능하다는 것이다.
그럼에도 Docker 를 쓰는 이유는 '성능향상', '뛰어난 이식성', '손쉽게 Scale Out 이 가능한 유연성'
Docker Image
Docker Image 란 컨테이너를 실행할 수 있는 실행파일, 설정 값 들을 가지고 있는 것이라고 생각하면 된다.
그림과 같이 Image 를 컨테이너에 담고 실행을 시킨다면 해당 프로세스가 동작을 하게 되는 것이다.
그럼 어떻게 이미지가 만들어지는가?
ubuntu 이미지를 만들기 위해 Layer A,B,C 가 들어간다.
그럼 nginx 이미지를 만든다고 생각했을땐 어떻게 될까?
이미 Layer A,B,C 로 만들어진 ubuntu 이미지를 베이스 이미지로 사용하여 베이스 이미지에 nginx 만 더하게 된다.
그렇다면 실질적으로 Layer A,B,C + nginx 가 더해진 것이지만 과정은 ubuntu + nginx 가 더해진 것이다.
그렇다면 web app 이미지를 만들려고 할 때는??
ubuntu 이미지에 nginx 를 올리고 web app 을 올리는게 아닌 이미 만들어진 nginx 베이스 이미지에 web app 을 올려 이미지를 만든다.
Docker 파일
Docker Image 들을 저장하고 배포하는 Docker Hub 는 정말 잘 활성화가 되어있다.
이미 여러 회사들은 SW 를 Docker Hub 를 통해 배포하기 시작했고 우린 Docker Hub 에서 image 를 pull 하여 간단하게 컨테이너에 넣어 사용할 수 있다.
만약 배포판이 없거나 보완하고 싶다면? Docker File 을 사용한다.
Docker File 은 이미지 생성 출발점으로 이미지를 구성하기 위한 명령어들을 작성하여 image 를 구성할 수 있다. 그 뜻은 Docker File 을 읽을 수만 있다면 해당 image 가 어떻게 구성되어 있는지도 알 수 있다는 의미이다.
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=example-0.0.1-SNAPSHOT.jar
EXPOSE 60431
COPY ${JAR_FILE} myboot.jar
WORKDIR /opt
ENTRYPOINT ["java","-jar","/myboot.jar"]
각 명령어를 뜯어서 본다면
- FROM : 생성할 image 의 베이스 이미지를 지정해준다.
- ARG : 변수를 선언한다.
- EXPOSE : 생성된 image 로 컨테이너를 구동할 때 어떤포트로 사용하는지 알려준다. EXPOSE 를 사용한다고 해서 컨테이너를 구동할 때 자동으로 해당 포트를 호스트 포트와 연결하지 않는다. 외부와 연결하려면 지정한 포트를 호스트 포트와 연결해야한다는 정보를 제공할 뿐이다.
- COPY : 호스트에서 새로 생성하는 컨테이너 image 로 필요한 파일을 복사한다.
- WORKDIR : 현재 작업 위치를 opt 디렉토리로 변경한다.
- ENTRYPOINT : ["명령어","옵션" ,"옵션" ..."옵션" ] 의 형식이다. 컨테이너 구동 시 ENTRYPOINT 뒤에 나오는 대괄호 안에 든 명령을 실행한다. 첫번째 문자열은 명령어이고 두번째 문자열부터 명령어를 실행할 때 추가하는 옵션이다.
이 과정까지 끝나고 docker build 를 하게 되면 image 가 생성이 된다. 여기서 캐시를 비활성화 하려면 --no-cache 를 추가하면 된다.
docker-compose.yml
지난번 포스팅 했던 yml 파일로 docker 의 컨테이너를 통합하여 관리한다.
docker-compose.yml 파일을 이용하면 컨테이너를 쉡게 생성할 수 있다.
다른 블로거분이 스프린트 간 사용했던 예제를 통해 간단하게 구조를 파악해보자
version: "3.0"
service:
frontend:
build: frontend
image: liveloper/client
ports:
-target: 80
publishes: 80
x-aws-protocol: http
depends_on:
-backend
backend:
build: backend
image: liveloper/server
ports:
-target: 3333
publishes: 3333
x-aws-protocol: http
위 과정이 모두 끝나면 아래의 두 명령어를 실행하면 빌드 및 컨테이너 생성이 완료된다.
// docker image build
sudo docker-compose build
// compose up
sudo docker-compose up
참고 블로그 : 일상을 개발하는, liveloper jay / CV DOODLE 님의 블로그
https://liveloper-jay.tistory.com/92
[Docker] Dockerfile을 이용한 이미지 빌드 예제 (+ docker-compose)
Summary Docker 이미지 생성은 다음과 같이 할 수 있습니다.(제가 모르는 방법이 있다면 댓글로 알려주시면 감사하겠습니다!) 1. pull을 이용하여 docker hub로부터 이미지 다운로드 // 이미지 pull sudo docke
liveloper-jay.tistory.com
개념과 예제만으로 주루룩 갈기다 보니 막연했던 docker 에 대해서 어느 정도 개념은 잡히는 듯 했다.
하지만 체술형 개발자인 나는 아마 실제로 코드를 적용해보면서 배우는게 더 많을거 같다.
당분간 git 이던 app 이던 잠시 쉬어가며 docker 고래사냥을 떠나봐야겠다.
가자~!!