본문 바로가기
  • 오늘처럼
소프트웨어 아키텍처/Docker

Docker and container runtime

by bluefriday 2021. 8. 30.
반응형

1. 컨테이너

컨테이너는 프로세스가 실행되는 루트를 변경해주는 chroot, 프로세스들의 자원을 제어하는 cgroup(control group), namespace 등의 개념을 이용하여 프로세스를 격리하여 소프트웨어 레벨에서 어플리케이션의 실행 환경을 구현해주는 서비스이다.
Virtual Machine 에 비하여 가볍다는 장점이 있어서 2010년 중반 이후 널리 사용되고 있으나, 완전히 새로운 개념은 아니며 과거 Linux 개발자/관리자 사이에서 이미 내부적으로 사용하고 있었던 기능을 쓰기 쉽게 패키징 하였다고 볼 수 있다. (chroot 기능 자체가 이미 1979년 Unix version 7 에서 시스템콜로 구현되었다.) 컨테이너와 도커를 다루는 여러 자료를 보면 runc, lxc, cri-o 와 같이 여러가지 컨테이너 런타임이 존재하는 것을 확인할 수 있다.

 

2. 컨테이너 런타임

일반적인 프로세스의 실행에 대한 관점에서, 런타임은 크게 2가지 의미를 갖는다.

  1. 프로그램이 실행될 때의 수명주기 단계 중 하나
  2. 프로그램이 실행될 수 있도록 지원하는 특정 프로그래밍 언어로 구현된 실행 환경

여기서 말하는 컨테이너 런타임은 두 번째 의미에 해당한다. 위에서 이야기하였듯이 컨테이너를 사용하기 위해서는 cgroup, namespace 등의 제어가 필요하다. 그런데 매번 컨테이너를 생성하고 관리하고 삭제할 때마다 관련 기반 기술을 수동으로 수행하는 것은 부담이 가는 작업이다. 이에 이러한 작업들을 사용하기 쉽게 번들 형태로 제공하는 것이 컨테이너 런타임이다. 즉 컨테이너 런타임은 “컨테이너를 생성하기 위해 필요한 기반 기술을 자동화해주는 라이브러리와 그 라이브러리가 실행될 수 있는 플랫폼” 이라고 볼 수 있다.

 

3. OCI : Open Container Initiative

위에서 이야기한 컨테이너 런타임을 이용하여 컨테이너를 실제로 생성하기 위해서는 다음과 같은 기능들이 필요하다.

  • 컨테이너 이미지를 빌드하고 공유하는 방법
  • 컨테이너 이미지를 관리하는 방법
  • 컨테이너 인스턴스를 관리하는 방법
  • 컨테이너 인스턴스를 실행하는 방법

컨테이너 기술이 널리 쓰이게 되면서, 서로 다른 사용자, 플랫폼 공급자들이 컨테이너 기술을 사용하게 된다. Docker, Google, MS, IBM 과 같은 주요 컨테이너 플랫폼 밴더들은 함께 OCI 라는 오픈 거버넌트 프로젝트를 구성한다. 그리고 이 OCI 표준에서 컨테이너 기술을 구현하기 위해 맞춰야 하는 Cgroup, Namespace 등의 기술에 대한 표준을 정의한다. Runtime-spec, Image-spec 으로 구분되며 Runtime-spec 의 예시는 다음과 같다.

Ex) oci-runtime-spec-v1.0.2

  - MUST, SHOULD, MAY 등의 키워드는 RFC 2119 의 설명대로 해석한다.
  - container runtime 의 환경은 반드시(MUST) config.json 파일의 구성에 따라 생성되어야 하며,
    runtime이 config.json 에 지정된 환경을 생성할 수 없을 경우 오류를 표시한다.

  - container 상태 중 id는, 컨테이너의 ID이며 호스트 안에서 고유해야 하나(MUST), 호스트 간 고유할 필요는 없다.
  - container 상태 중 status는 컨테이너의 런타임 상태이며
    값은 creating / created / running / stopped 중 하나일 수(MAY) 있다.

  - namespace의 유형(type)은 pid/network/mount/ipc/uts/user/cgroup 을 지원해야(SHOULD) 한다.
  - 모든 설정 JSON 파일은 UTF-8 로 인코딩 되어야 한다(MUST).

 

4. 도커와 컨테이너 런타임

도커는, 이렇게 컨테이너 런타임을 기반으로 리눅스 컨테이너를 쉽게 사용할 수 있도록 패키징한 프로그램 중 하나이다.
도커 진영은 컨테이너를 쉽게 사용할 수 있도록 하기 위하여 기반기술인 Cgroup, Namespace 를 활용해야했는데, 배포판 및 커널 버전 등에 따라 기반기술의 사용법이 조금씩 상이했다. 그래서 초기에는 외부 라이브러리인 LXC/libvirt 를, 후기에는 자체개발한 libcontainerd 등을 중간 레이어 역할로 사용하게 된다.

 

4-1. LXC(Linux Container)

LXC는 Canonical(Enterprise Ubuntu)이 지원하고 있는 리눅스 컨테이너 프로젝트로, 컨테이너 기능을 위한 사용자 영역의 인터페이스이다. Solaris Zones, BSD Jails 와 마찬가지로 시스템 관리자에게 VM보다 경량의 환경을 제공해주며, API와 툴을 이용하여 쉽게 컨테이너를 생성하고 관리할 수 있도록 해준다. 내부적으로, 컨테이너를 만들기 위해 리눅스 커널과 통신하여 seccomp, AppArmor, SELinux, Cgroup 등의 기능을 사용하며 이렇게 컨테이너의 라이프 사이클을 관리한다는 점에서 도커와 동일한 레벨로 볼수 있다. 실제로 도커 또한 v0.8 버전까지는 LXC를 사용하였다.

 

4-2. libcontainerd

libcontainer 는 LXC 드라이버를 대체하기 위해 도커 진영에서 자체 개발한 라이브러리이다. Namespace, Cgroup, AppArmor, firewall 등을 컨테이너를 생성하고, 생성된 컨테이너에 대한 수명주기를 관리할 수 있다. LXC, libvirt, systemd-snpawn 과 같은 리눅스 사용자 공간(user-space)의 구성요소에 의존하지 않으며, 기본적으로 go언어로 작성되어 있다. 도커는 v0.9 버전부터 libcontainer를 사용하며 LXC 등의 외부 모듈 의존성을 제거한다.

 

4-3. runC

도커 진영은 기존의 libcontainer를 다시 한번 리팩토링하여 runC 라는 구현체로 통합한다. OS 레벨에서 볼 때 패키지가 아닌 하나의 바이너리 파일(/bin/runc)로 존재한다. 도커에서 소개하는 runC 의 특징 및 장점은 다음과 같다.

  • 보안성을 고려하여 설계
  • 대규모 운영 환경을 고려하여 설계
  • 컨테이너 런타임을 제외한 도커 플랫폼에 대한 종속성 제거
  • ARM, Intel, Qualcomm, IBM 및 전체 하드웨어 업체 지원
  • 사용자 네임스페이스를 포함한 모든 네임스페이스에 대한 완전한 지원
  • Linux 에서 사용가능한 모든 보안 기능 지원 : SELinux, AppArmor, seccomp, cgroup.
    (리눅스에서 가능하면 runC 도 가능하다)

 

다음에는

여기서는 컨테이너 런타임과 도커의 컨테이너 런타임에 대하여 알아보았다. 이 후에는 컨테이너 런타임의 세부 구조와, kubernetes에서의 컨테이너 런타임에 대해서 알아보도록 한다.

'소프트웨어 아키텍처 > Docker' 카테고리의 다른 글

Docker registry API - pull  (0) 2021.09.22
Docker compose 의 사용  (0) 2021.09.07
Docker registry 내부 구조  (1) 2018.06.21
Docker registry service 2  (0) 2018.06.20
Docker registry service  (0) 2018.06.17

댓글