Post

Docker 개념 및 정리

1. 도커(Docker)란

img001

도커는 2013년 3월 산타클라라에서 열린 Pycon Conference에서 dotCloud의 창업자인 Solomon Hykes가 The future of Linux Containers라는 세션을 발표하면서 처음 세상에 알려졌다.

도커는 리눅스의 응용 프로그램들을 소프트웨어 컨테이너 안에 배치시키는 일을 자동화하는 오픈 소스 프로젝트이다. 도커 웹 페이지의 기능을 인용하면 다음과 같다.

도커 컨테이너는 일종의 소프트웨어를 소프트웨어의 실행에 필요한 모든 것을 포함하는 완전한 파일 시스템 안에 감싼다. 여기에는 코드, 런타임, 시스템 도구, 시스템 라이브러리 등 서버에 설치되는 무엇이든 아우른다. 이는 실행 중인 환경에 관계없이 언제나 동일하게 실행될 것을 보증한다.

img002

도커는 리눅스에서 운영 체제 수준 가상화의 추상화 및 자동화 계층을 추가로 제공한다. 도커는 cgroups와 커널 이름 공간과 같은 리눅스 커널, 또 aufs와 같은 유니언 가능 파일 시스템의 리소스 격리 기능을 사용하며, 이를 통해 독립적인 “컨테이너”가 하나의 리눅스 인스턴스 안에서 실행할 수 있게 함으로써 가상 머신을 시작하여 유지 보수해야 하는 부담을 없애준다.

리눅스 커널의 이름 공간 지원은 대체로 프로세스 트리, 네트워크 사용자 ID, 마운트된 파일 시스템을 포함한 운영 환경에 대한 응용 프로그램의 관점을 격리시키지만, 커널의 cgroup들은 CPU, 메모리, 블록 입출력, 네트워크를 포함한 리소스 제한을 제공한다.

버전 0.9부터 도커는 libvirt, LXC(리눅스 컨테이너), systemd-nspawn을 통한 추상화된 가상화 인터페이스를 사용하는 것뿐 아니라 리눅스 커널이 제공하는 가상화 기능을 직접 사용하기 위한 유일한 수단으로 libcontainer 라이브러리를 포함하고 있다.

즉, Docker란 Go 언어로 작성된 리눅스 컨테이너 기반 오픈소스 가상화 플랫폼이다.

2. 컨테이너(Container)

img003

컨테이너는 가상화 기술 중 하나로 대표적으로 LXC(Linux Container)가 있다. 기존 OS를 가상화시키던 것과 달리 컨테이너는 OS 레벨의 가상화로 프로세스를 격리시켜 동작하는 방식으로 이루어진다.

우리에게 익숙한 VMware나 VirtualBox 같은 가상머신은 호스트 OS위에 게스트 OS 전체를 가상화하여 사용하는 방식이다. 이 방식은 여러 가지 OS를 가상화 할 수 있고 비교적 사용법이 간단하지만 무겁고 느려서 운영환경에서는 사용할 수 없다.

3. VM 가상화 플랫폼 vs Docker 가상화 플랫폼

img004

전가상화든 반가상화든 추가적인 OS를 설치하여 가상화하는 방법은 성능 문제가 있었고 이를 개선하기 위해 프로세스를 격리하는 방식이 등장한다.

리눅스에서는 이 방식을 리눅스 컨테이너라고 하고 단순히 프로세스를 격리시키기 때문에 가볍고 빠르게 동작한다. CPU나 메모리는 프로세스가 필요한 만큼만 추가로 사용하고 성능적으로도 거의 손실이 없다.

도커의 기본 네트워크 모드는 Bridge 모드로 약간의 성능 손실이 있다. 네트워크 성능이 중요한 프로그램의 경우 –net=host 옵션을 고려해야 한다.

기존에 우리에게 익숙한 VM같은 경우엔 Host OS 위에 가상화를 시키기 위한 Hypervisor 엔진 그리고 그 위에 Guest OS를 올려 사용한다. 이는 가상화된 하드웨어 위에 OS가 올라가는 형태로 완벽하게 Host와 분리된다고 봐도 무방하다.

반면에 컨테이너 기반 가상화는 Docker 엔진 위에 Application 실행에 필요한 바이너리만 올라가게 된다. OS 가상화를 보면 Host OS와 완전히 분리되는 장점은 있지만 OS 위에 OS를 올리기 때문에 무겁고 느릴 수 밖에 없다.

하지만 컨테이너 기반 가상화는 Host OS 그리고 Docker 엔진 위에서 바로 동작하며 Host의 커널을 공유한다. 커널을 공유하게 되면 I/O 처리가 쉽게 되어 성능의 효율을 높일 수 있다.

컨테이너를 사용하는 것은 가상 머신을 생성하는 것이 아니라, Host OS가 사용하는 자원을 분리하여 여러 환경을 만들 수 있도록 하는 것이다.

4. 이미지(Image)

img005

도커에서 가장 중요한 개념은 컨테이너와 이미지라는 개념이다.

이미지는 컨테이너 실행에 필요한 파일과 설정값 등을 포함하고 있는 것으로, 상태 값을 가지지 않고 변하지 않는다(Immutable).

컨테이너는 이미지를 실행한 상태라고 볼 수 있고, 추가되거나 변하는 값은 컨테이너에 저장된다. 같은 이미지에서 여러 개의 컨테이너를 생성할 수 있고 컨테이너의 상태가 바뀌거나 컨테이너가 삭제되더라도 이미지는 변하지 않고 그대로 남아있다.

ubuntu이미지는 ubuntu를 실행하기 위한 모든 파일을 가지고 있고, MySQL이미지는 Debian을 기반으로 MySQL을 실행하는데 필요한 파일과 실행 명령어, 포트 정보 등을 가지고 있다. 좀 더 복잡한 예로 Gitlab 이미지는 CentOS를 기반으로 Ruby, Go, Database, Redis, Gitlab Source, Nginx 등을 가지고 있다.

즉, 이미지는 컨테이너를 실행하기 위한 모든 정보를 가지고 있기 때문에 더 이상 의존성 파일을 컴파일하고 설치할 필요가 없다. 새로운 서버가 추가되면 미리 만들어 놓은 이미지를 다운받고 컨테이너를 생성만 하면 된다. 한 서버에 여러 개의 컨테이너를 실행할 수 있고, 수십, 수백, 수천 대의 서버도 문제없다.

img006

도커 이미지는 Docker Hub에 등록하거나 Docker Registry 저장소를 직접 만들어 관리할 수 있다. 현재 공개된 도커 이미지는 50만개가 넘고 Docker Hub의 이미지 다운로드 수는 80억회에 이른다. 누구나 쉽게 이미지를 만들고 배포할 수 있다.

5. 레이어 저장방식

img007

도커 이미지는 컨테이너를 실행하기 위한 모든 정보를 가지고 있어서 보통 용량이 수백 메가에 이른다. 처음 이미지를 다운받을 때는 크게 부담이 안 되지만, 기존 이미지에 파일 하나 추가했다고 수백 메가를 다시 다운받는다면 매우 비효율적일 수밖에 없다.

도커는 이러한 문제를 해결하기 위해 레이어(Layer)라는 개념을 사용하고 유니온 파일 시스템을 이용하여 여러 개의 레이어를 하나의 파일 시스템으로 사용할 수 있게 해준다. 이미지는 여러 개의 읽기 전용(Read Only) 레이어로 구성되고 파일이 추가되거나 수정되면 새로운 레이어가 생성된다.

ubuntu 이미지가 A + B + C의 집합이라면, ubuntu 이미지를 베이스로 만든 nginx 이미지는 A + B + C + nginx가 된다. webapp 이미지를 nginx 이미지 기반으로 만들었다면 예상대로 A + B + C + nginx + source 레이어로 구성된다. webapp 소스를 수정하면 A, B, C, nginx 레이어를 제외한 새로운 source(v2) 레이어만 다운받으면 되기 때문에 효율적으로 이미지를 관리할 수 있다.

컨테이너를 생성할 때도 레이어 방식을 사용하는데, 기존의 이미지 레이어 위에 읽기/쓰기(Read-Write) 레이어를 추가합니다. 이미지 레이어를 그대로 사용하면서 컨테이너가 실행 중에 생성하는 파일이나 변경된 내용은 읽기/쓰기 레이어에 저장되므로 여러 개의 컨테이너를 생성해도 최소한의 용량만 사용한다.

6. 이미지 경로

img008

이미지는 URL 방식으로 관리하며 태그를 붙일 수 있다. ubuntu 14.04 이미지는 docker.io/library/ubuntu:14.04 또는 docker.io/library/ubuntu:trusty 이고 docker.io/library는 생략 가능하여 ubuntu:14.04 로 사용할 수 있다.

이러한 방식은 이해하기 쉽고 편리하게 사용할 수 있으며 태그 기능을 잘 이용하면 테스트나 롤백도 쉽게 할 수 있다.

7. Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
FROM ubuntu:14.04

# app 디렉토리 생성
RUN mkdir -p /app

# Docker 이미지 내부에서 RUN, CMD, ENTRYPOINT의 명령이 실행될 디렉터리 설정
WORKDIR /app

# 현재 디렉터리에 있는 파일들을 이미지 내부 /app 디렉터리에 추가함
ADD ./app

RUN apt-get update
RUN apt-get install apache2
RUN service apache2 start

VOLUME ["/data", "/var/log/httpd"]

# 포트 외부 노출
EXPOSE 80

# 쉘을 사용하지 않고 컨테이너가 시작되었을 때 logbackup 스크립트 실행
CMD ["/app/log.backup.sh"]

도커는 이미지를 만들기 위해 Dockerfile이라는 파일에 자체 DSL(Domain-Specific Language) 언어를 이용하여 이미지 생성 과정을 적는다.

서버에 어떤 프로그램을 설치하려고 의존성 패키지를 설치하고 설정 파일을 만들었던 경험이 있다면, 그 과정을 메모장이 아닌 Dockerfile로 관리하면 된다. 이 파일은 소스와 함께 버전 관리 되고 누구나 이미지 생성과정을 보고 수정할 수 있다.

8. 커뮤니티

[출처 및 참고]

This post is licensed under CC BY 4.0 by the author.