도커의 컨테이너

을 요약/번역한 글입니다.

컨테이너와 VM의 차이

  • 목적은 비슷함: 애플리케이션과 그 디펜던시들을 독립된 단위로 묶어 격리, 어디서든 실행 가능하게 하기

  • 컨테이너와 VM 모두 물리적 하드웨어가 없어도 되게 하여 컴퓨터의 자원을 보다 더 효율적으로 (에너지 / 비용면 둘다)

  • 결정적인 차이는 설계에 있음

VM

  • 실제 컴퓨터의 에뮬레이션으로, 프로그램을 실제 컴퓨터처럼 실행한다.

  • 물리적 머신 위에서 “하이퍼바이저”를 이용해서 실행된다
    하이퍼바이저는 호스트 머신이나 “bare metal”상에서 실행된다.

  • 하이퍼바이저? VM이 실행되는 소프트웨어/펌웨어/하드웨어. 호스트 머신이라 불리는 물리적 기계 위에서 돌아간다. 호스트 머신은 VM에 램과 CPU 등의 자원을 제공한다.
    자원은 VM들이 나누어서 사용하고, 원하는대로 할당할 수 있다. (가중치를 다르게 줄 수 있는 것)

  • 호스트 머신 위에서 하이퍼바이저를 이용하여 돌아가는 VM을 보통 게스트 머신 이라고도 부른다. 이 게스트머신은 보통 그 애플리케이션을 실행하기 위한 모든 것(바이너리, 라이브러리 등) + 애플리케이션을 포함, 거기에 가상화된 네트워크 어댑터, 저장소, CPU등의 모든 하드웨어 스택도 포함한다. 즉, 그 안에 또다시 게스트 OS를 가지고 있는 것.
    내부에서 보면, VM은 이로써 자신만의 자원을 할당받은, 하나의 독립된 유닛처럼 작동한다. 외부에서 봤을때는 우리는 이게 VM이라는 것을 알고 있다. (호스트 머신에서 자원을 할당받음을 알고 있으므로..)

  • 이처럼 가상 머신은 호스트가 있는 하이퍼바이저, 혹은 bare-metal 하이퍼바이저에서 실행된다. 이 둘에는 중요한 차이가 있다.

  • hosted virtualization hypervisor : 호스트 머신의 OS에서 돌아간다. VM은 곧바로 하드웨어에 접근할 수 없으며, 호스트 OS를 거쳐야 한다.

  • Bare metal hypervisor 환경은 위와 같은 퍼포먼스 이슈를 호스트머신의 하드웨어에 직접 설치하고 실행함으로 해결한다. 하드웨어에서 인터페이스로서 돌아가기 때문에 따로 OS가 필요없다. 이 경우에는 하이퍼바이저가 첫번째 OS가 된다.

    • hosted 하이퍼바이저와는 달리, bare-metal 하이퍼바이저는 자신만의 디바이스 드라이버를 가지고 I/O, 처리, OS 관련 task들을 컴포넌트들과 직접 교류하여 처리한다.
    • => 더 나은 퍼포먼스, 유연성, 안정성.
    • 안좋은 점: hardware compatibility가 제한되어있으므로, 하이퍼바이저는 그 한도 안에서만 드라이버를 설치할 수 있다.
    • VM들이 각자의 OS를 가지고 있으므로, 하이퍼바이저가 VM들에게 게스트 OS를 실행하고 관리할 수 있게끔 돕는 역할을 한다.
    • 호스트가 자원을 VM(게스트 머신들)에게 배분할수 있도록 하이퍼바이저가 지원

컨테이너

  • 하드웨어 가상화의 VM과는 달리, 컨테이너는 OS레벨의 가상화를 제공한다. 이는 “user space”를 추상화 한것이다.

  • 컨테이너도 VM처럼 private space, 루트 권한, 사설 네트워크, IP 주소, 커스텀 라우트 / iptable 규칙, 파일 시스템 등을 가지고 있다.
    하지만 컨테이너는 호스트 시스템의 커널을 다른 컨테이너들과 공유한다는 것이 큰 차이점이다.

  • 컨테이너는 유저 스페이스 (app + bin/lib) 만을 묶어서 이용한다는 것을 알 수 있다.

  • 각각의 컨테이너는 자기만의 분리된 유저 스페이스를 갖고, 여러개의 컨테이너가 하나의 호스트에서 돌아갈 수 있다.

  • 즉, OS레벨의 설계는 모든 컨테이너가 공유한다.

  • 이렇게 해서 컨테이너는 훨씬 가벼워진다.

도커는 그럼 무슨 역할을 하는가?

  • 네임스페이스, 컨트롤 그룹과 같은 리눅스 커널 기능을 이용해서 OS위에 컨테이너를 생성한다.

도커 세부 개념들

  • 도커 엔진: 도커가 실행되는 레이어. 컨테이너, 이미지, 빌드 등을 관리하는 런타임이자 도구. 다음의 세가지로 구성된다

    • 호스트에서 돌아가는 도커 데몬: 명령어를 클라이언트로부터 전달받아 실행한다. 호스트 머신에서 돌아가고, 반드시 클라이언트를 통해서만 접근 가능하다.
    • 도커 데몬과 통신하여 명령어를 실행하는 도커 클라이언트: 유저가 마주하는 단계. 도커의 UI라고 보면 된다.
    • 도커 데몬과 원격으로 교류하는 REST API
  • Docker File : 도커 이미지를 생성할 상세 사항을 적는 파일.

    • RUN apt-get y install some-package =>패키지 설치
    • EXPOSE 8000 => 포트 노출
    • ENV ANT_HOME /usr/local/apache-ant => 환경변수를 전달
    • etc etc

예시: https://gist.github.com/iam-peekay/9e5e7440919d39a78a2b#file-dockerfile

  • 도커 이미지:
    • Docker file의 지시사항을 기준으로 생성하는 read-only 템플릿. 패키지화된 애플리케이션 + 디펜던시들의 형태와 실행시에 어떤 프로세스를 실행할지를 정의한다.
    • 도커파일의 각 지시 항목은 새로운 “레이어”로서 이미지에 추가된다. 이 레이어가 도커의 가벼우면서도 강력한 구조의 핵심이다.
  • Union File Systems
    • 스택으로 쌓을 수 있는 파일 시스템이라고 볼 수 있다. 서로 다른 파일 시스템(브랜치)의 파일과 디렉토리가 서로 겹쳐져서 하나의 파일 시스템을 구성할 수 있다는 뜻이다.
    • 이렇게 하나로 겹쳐져 있는 브랜치들 중에서 같은 경로를 가지고 있는 디렉토리들의 내용은 하나의 합쳐진 디렉토리로 인식된다. 즉, 각각의 레이어에 따라 별도의 버전을 따로 만들지 않는다. (중복을 없앤다)
      따로 만들지 않는 대신, 동일한 자원으로의 포인터를 배정받는다. 특정 레이어가 수정된다면 그때 로컬 카피를 생성,수정하여서, 원본은 바뀌지 않게 한다.
    • 이렇게 해서 실제로 write를 하지 않고도 많이 수정이 일어난 것 처럼 파일시스템을 보여줄 수 있는 것이다.
    • 레이어드 시스템은 두가지의 좋은 점이 있다
      • duplication-free : 레이어들로 이루어져 있다는 것은 모든 파일들을 매번 새로운 컨테이너를 시동할때마다 복사하지 않아도 되게 해준다. 즉, 도커 컨테이너들의 인스턴스화는 매우 빠르고 자원이 적게 든다.
      • Layer segregation: 변경사항이 더 빠르게 반영된다. 하나의 이미지를 변경하면, 도커는 그 수정사항을 해당 레이어에만 반영하도록 한다.
  • Volumes: 컨테이너의 ‘데이터’ 부분이다. 컨테이너가 생성되면 초기화된다.
    • 컨테이너의 데이터를 유지하고 공유할 수 있도록 한다.
    • 데이터 볼륨은 Union File System과는 별도로, 평범한 디렉토리/파일들로 호스트의 파일 시스템에서 존재한다.
    • 컨테이너를 파괴, 수정, 재생성 하더라도 데이터 볼륨은 그대로 유지된다.
    • 여러개의 컨테이너에서 공유/재사용 할 수 있다.
  • Docker Container
    • 도커 컨테이너는 애플리케이션과 해당 애플리케이션이 필요로 하는 모든것을 하나로 묶은 것이다.
    • OS, 애플리케이션의 코드. 런타임, 시스템도구, 시스템 라이브러리 등
      도커 이미지로부터 빌드된다.
    • 이미지는 read-only이므로, 그 이미지에 read-write 파일시스템을 더해서 컨테이너를 만든다.
    • 도커는 컨테이너가 로컬호스트와 통신할 수 있도록 네트워크 인터페이스도 생성한다. 즉, IP 주소를 컨테이너에 붙인다.
    • 생성되면 IP주소가 붙고, 도커 이미지에서 지정된 항목들을 실행한다.
    • 성공적으로 컨테이너를 생성했다면, 어떤 환경에서든 부가적인 변경 없이 컨테이너를 실행할 수 있다.
  • 컨테이너에 대해 더 자세히: 컨테이너는 결국 몇가지의 기능들이 합쳐진 추상적 개념이다.
    • Namespace : 컨테이너들이 인식/접근할 수 있는 것에 제한을 건다. 컨테이너를 실행시키면, 도커가 해당 컨테이너가 사용할 네임스페이스를 생성한다.
    • 네임스페이스의 종류 (예시):
      • NET: 컨테이너만의 네트워크 스택 (네트워크 디바이스, IP 주소, 라우팅 테이블, /proc/net 디렉토리, 포트 번호….)
      • PID: Process ID.
      • MNT
      • UTS
      • IPC
      • User
    • Control Groups : 리눅스 커널이 각 프로세스가 어떻게 자원을 사용할 것인지 정하는 (isolate, prioritize) 기능으로, 도커 컨테이너가 필요한 자원만 사용하도록 제어한다. 필요하다면 , 컨테이너가 사용 가능한 자원의 한도도 지정한다.
      하나의 컨테이너가 과도하게 많은 자원을 사용하여 시스템이 중단되는 경우도 미리 방지한다.
    • Isolated Union File System: Union File System과 동일
Share