[Docker 이해하기] 2. 컨테이너 기술과 Docker의 개요

Titu·2021년 7월 16일
3

Docker

목록 보기
2/6

Docker는 컨테이너 기술을 사용하여 애플리케이션의 실행 환경을 구축하고 운용하기 위한 플랫폼이다. 애플리케이션의 실행에 필요한 것을 하나로 모아, Docker 이미지를 관리함으로써 애플리케이션의 이식성을 높일 수 있다.

이 장에서는 애플리케이션 개발자가 알아두어야 할 컨테이너 기술Docker의 개요, Docker가 작동하는 구조에 대해 살펴보기로 한다.

2.1 컨테이너 기술의 개요

Docker를 이해하는 데 있어서는 그 배경에 있는 컨테이너 기술이 어떤 것인지를 알아야 한다.

컨테이너

전통적 방식

  • 보통 물리 서버 상에 설치한 호스트 OS의 경우 하나의 OS 상에서 움직이는 여러 애플리케이션은 똑같은 시스템 리소스를 사용한다.
  • 이때 작동하는 여러 애플리케이션은 데이터를 저장하는 디렉토리를 공유하고, 서버에 설정한 동일한 IP주소로 통신을 한다.
  • 그래서 여러 애플리케이션에서 사용하고 있는 미들웨어나 라이브러리의 버전이 다른 경우에는 각 애플리케이션이 서로 영향을 받지 않도록 주의해야 한다.

컨테이너

전통적 방식과 달리, 컨테이너 기술을 사용하면 OS나 디렉토리, IP 주소 등과 같은 시스템 자원을 마치 각 애플리케이션이 점유하고 있는 것처럼 보이게 할 수 있다.

  • 컨테이너란 호스트 OS상에 논리적인 구획(컨테이너)을 만들고, 애플리케이션을 작동시키기 위해 필요한 라이브러리나 애플리케이션 등을 하나로 모아, 마치 별도의 서버인 것처럼 사용할 수 있게 만든 것이다.
  • 호스트 OS의 리소스를 논리적으로 분리시키고, 여러 개의 컨테이너가 공유하여 사용한다.
  • 컨테이너는 오버헤드가 적기 때문에 가볍고 고속으로 작동한다는 것이 특징이다.
  • 또한, 컨테이너는 애플리케이션의 실행에 필요한 모듈을 컨테이너로 모을 수 있기 때문에, 여러 개의 컨테이너를 조합하여 하나의 애플리케이션을 구축하는 마이크로 서비스형 애플리케이션과도 친화성이 높은 것이 특징이다.

서버 가상화 기술

컨테이너 기술과 매우 비슷한 기술로 서버 가상화 기술이 있다. 두 기술은 비슷해보이지만 다른 목적을 갖고 있는데, 컨테이너 기술이 애플리케이션의 실행 환경을 모음으로써 이식성을 높이고 확장성이 좋은 환경에서 작동하는 것을 지향하고 있는 반면, 가상화 기술의 대부분은 서로 다른 환경을 어떻게 효율적으로 에뮬레이트할지라는 점을 지향하고 있다.

서버 가상화 기술은 크게 두 가지 방식으로 나뉘는데 하이퍼바이저형과 호스트형이다.

  • 하이퍼바이저형 서버 가상화
    • 하드웨어 상에 가상화를 전문으로 수행하는 소프트웨어인 '하이퍼바이저'를 배치하고, 하드웨어와 가상환경을 제어한다. Microsoft Windows Server의 'Hyper-V'나 Citrix의 'XenServer'등이 있다.
    • 호스트 OS 없이 하드웨어를 직접 제어하기 때문에 자원을 효율적으로 사용할 수 있다. 단, 가상 환경마다 별도의 OS가 작동하므로 가상 환경의 시작에 걸리는 오버헤드가 커진다.
    • 하이퍼바이저형은 펌웨어로서 구축하는 경우가 많다.
  • 호스트형 서버 가상화
    • 하드웨어 상에 베이스가 되는 호스트 OS를 설치하고, 호스트 OS에 가상화 소프트웨어를 설치한 후, 이 가상화 소프트웨어 상에서 게스트 OS를 작동시키는 기술을 말한다.
    • 가상화 소프트웨어를 설치하여 간편하게 가상 환경을 구축할 수 있기 때문에 개발 환경 구축 등에 주로 사용한다. Oracle에서 제공하는 'Oracle VM VirtualBox'나 VMware의 'VMware Workstation Player'등이 있다.
    • 하지만 이 방식은 컨테이너와는 다르게 호스트 OS 상에서 다른 게스트 OS를 움직이고 있기 때문에 오버헤드(가상화를 수행하기 위해 필요한 CPU자원, 디스크 용량, 메모리 사용량)가 커진다.
    • 따라서 간편하게 도입할 수 있지만, 사양이 낮은 컴퓨터의 경우 속도가 느려진다.

2.2 Docker의 개요

Docker는 애플리케이션의 실행에 필요한 환경을 하나의 이미지로 모아두고, 그 이미지를 사용하여 다양한 환경에서 애플리케이션 실행 환경을 구축 및 운용하기 위한 오픈소스 플랫폼이다.

Docker의 도입

  • Before Docker

    • 폭포형(waterfall) 개발 방식으로 애플리케이션을 개발할 때는, 개발 환경이나 테스트 환경에서 올바르게 작동해도 스테이징 환경에서나 제품 환경으로 전개하면 정상적으로 작동하지 않는 경우가 있다.
      • 스테이징 환경이란 지속적 딜리버리가 일어나는 시스템 개발에서 개발한 애플리케이션을 제품 환경에 전개하기 직전에 확인하는 테스트 환경을 말한다.
  • After Docker

    • Docker에서는 이러한 인프라 환경을 컨테이너로 관리한다. 애플리케이션의 실행에 필요한 모든 파일 및 디렉토리들을 컨테이너로 모아버리는 것이다. 이러한 컨테이너의 바탕이 되는 Docker 이미지를 Docker Hub와 같은 레포지토리(repository)에 공유한다.
    • 프로그래머는 Docker를 사용하여, 개발한 애플리케이션의 실행에 필요한 모든 것이 포함되어 있는 Docker 이미지를 작성한다. 이 이미지는 컨테이너의 바탕이 되고, 이렇게 작성한 이미지를 바탕으로 컨테이너를 가동시킨다.
    • Docker 이미지는 Docker가 설치되어 있는 환경이라면 기본적으로 어디서든 작동되므로 '개발/테스트 환경에서는 움직이지만 제품 환경에서는 움직이지 않는다'는 리스크를 줄일 수 있다.
      - 한 번 만들면 어디서든 움직이는 소프트웨어의 특성을 이식성(portability)이라고 한다. Docker는 이식성이 높기 때문에 클라우드 시스템과의 친화력이 높은 것이 특징이다. Docker 컨테이너의 바탕이 되는 Docker 이미지만 있으면 애플리케이션을 동일한 환경에서 가동시킬 수 있다.
      - 따라서, 클라우드 -> 온프레미스, 온프레미스 -> 클라우드와 같이 시스템 요건이나 예산에 따라 손쉽게 실행 환경을 선택할 수 있다.

2.3 Docker의 기능

Docker 이미지를 만드는 기능(Build)

  • Docker 이미지는 애플리케이션의 실행에 필요한 파일들이 저장된 디렉토리다.
    • Docker 명령을 사용하면 이미지를 tar 파일로 출력할 수 있다.
  • Docker는 애플리케이션의 실행에 필요한 프로그램 본체, 라이브러리, 미들웨어, OS나 네트워크 설정 등을 하나로 모아서 Docker 이미지를 만든다.
  • Docker 이미지는 Docker의 명령을 사용하여 수동으로 만들 수도 있고, Dockerfile이라는 설정 파일을 만들어서 자동으로 만들 수도 있다.

Docker 이미지를 공유하는 기능(Ship)

  • Docker 이미지는 Docker 레지스트리에서 공유할 수 있다.
    • Docker의 공식 레지스트리인 Docker Hub에서는 Ubuntu나 CentOS같은 Linux 배포판의 기본 기능을 제공하는 베이스 이미지를 배포하고 있다. 이러한 베이스 이미지에 미들웨어나 라이브러리, 애플리케이션 등을 넣어 새로운 Docker 이미지를 만들어 가는 것이다.
  • 공식 이미지 외에도 개인이 작성한 이미지를 Docker Hub에 자유롭게 올릴 수 있으며, Docker Hub에 올려져 있는 Docker 이미지들을 자유롭게 다운로드 할 수 있다.

Docker 컨테이너를 작동시키는 기능(Run)

  • Docker는 리눅스 상에서 컨테이너 단위로 서버 기능을 작동시킨다.
    • 이 컨테이너의 바탕이 되는 것이 Docker 이미지다. Docker 이미지만 있으면 Docker가 설치된 환경에서 항상 컨테이너를 작동시킬 수 있다.
  • Docker는 하나의 리눅스 커널을 여러 개의 컨테이너에서 공유하고 있다. 컨테이너 안에서 작동하는 프로세스를 하나의 그룹을 관리하고, 그룹마다 각각 파일 시스템이나 호스트명, 네트워크 등을 할당하고 있다. 그룹이 다르면 프로세스나 파일에 대한 액세스를 할 수 없다. 이러한 구조를 사용해서 컨테이너를 독립된 공간으로 관리하고 있다.

2.4 Docker의 작동 구조

Docker의 핵심 기능이 어떤 구조로 움직이는지 살펴보도록 한다.

컨테이너를 구획화하는 장치(namespace)

  • Docker는 컨테이너라는 독립된 환경을 만들고, 그 컨테이너를 구획화하여 애플리케이션의 실행 환경을 만든다. 이 컨테이너를 구획화하는 기술은 Linux 커널의 namespace라는 기능을 사용하고 있다.
  • Linux 커널의 namespace는 Linux 오브젝트에 이름을 붙임으로써 아래와 같은 6개의 독립된 환경을 구축할 수 있다.
    • PID namespace
      • Linux에서 PID란 각 프로세스에 할당된 고유한 ID를 말한다. namespace가 다른 프로세스끼리는 서로 액세스 할 수 없다.
    • Network namespace
      • Network namespace는 네트워크 디바이스, IP 주소, 포트 번호, 라우팅 테이블, 필터링 테이블 등과 같은 네트워크 리소스를 격리된 namespace마다 독립적으로 가질 수 있다.
      • 이 기능을 사용하면 호스트 OS 상에서 사용 중인 포트가 있더라고 컨테이너 안에서 동일한 번호의 포트를 사용할 수 있다.
    • UID namespace
      • UID namespace는 UID(사용자 ID), GID(그룹 ID)를 namespace별로 독립적으로 가질 수 있다.
      • 예를 들어, namespace 안에서 UID/GID가 0인 root 사용자를, 호스트 OS 상에서는 일반 사용자로 취급할 수 있다. 즉, namesapce 안의 관리자 계정은 호스트 OS에 대해서는 관리 권한을 일절 갖지 않는다는 뜻이므로 보안에 뛰어난 환경으로 격리시킬 수 있다.
    • MOUNT namespace
      • Linux에서 파일 시스템을 사용하기 위해서는 마운트가 필요하다. 마운트란 컴퓨터에 연결된 기기나 기억장치를 OS에 인식시켜 이용 가능한 상태로 만드는 것을 말한다.
      • MOUNT namespace는 마운트 조작을 하면 namespace 안에 격리된 파일 시스템 트리를 만든다. 다른 namespace 기능과 마찬가지로 namespace 안에서 수행한 마운트는 호스트 OS나 다른 namespace에서는 액세스 할 수 없다.
    • UTS namespace
      • UTS namespace는 namespace별로 호스트명이나 도메인명을 독자적으로 가질 수 있다.
    • IPC namespace
      • IPC namespace는 프로세스 간의 통신(IPC) 오브젝트를 namespace별로 독립적으로 가질 수 있다.
        • IPC는 System V 프로세스 간의 통신 오브젝트라고 하는 공유 메모리나 세마포어/메시지 큐를 말한다.
          • 세마포어는 프로세스가 요구하는 자원 관리에 이용되는 배타제어 장치이고, 메시지 큐는 여러 프로세스 간에서 비동기 통신을 할 때 사용되는 큐잉 장치다.

릴리스 관리 장치(cgroups)

  • Docker에서는 물리 머신 상의 자원을 여러 컨테이너가 공유하여 작동한다. 이때 Linux 커널의 기능인 'control groups(cgroups)' 기능을 사용하여 자원 할당 등을 관리한다.
  • cgroups는 프로세스와 스레드를 그룹화하여, 그 그룹 안에 존재하는 프로세스와 스레드에 대한 관리를 수행하기 위한 기능이다. cgroups는 컨테이너 안의 프로세스에 대해 자원을 제한함으로써 예를 들면 어떤 컨테이너가 호스트 OS의 자원을 모두 사용해버려 동일한 호스트 OS상에서 가동되는 다른 컨테이너에 영향을 주는 일을 막을 수 있다.
    • Linux에서는 프로그램을 프로세스로서 실행한다. 프로세스는 하나 이상의 스레드 모음으로 움직인다.
  • cgroups는 계층 구조를 사용하여 프로세스를 그룹화하여 관리할 수 있고, 부모자식 관계에서 자식은 부모의 제한을 물려받는다.

본문은 'Asa Shijo, <완벽한 IT 인프라 구축을 위한 Docker>, 정보문화사(2020)' 를 참고하여 정리한 글입니다.

[참고: 완벽한 IT 인프라 구축을 위한 Docker]

profile
This is titu

0개의 댓글