컨테이너는 애플리케이션, 실행 라이브러리, 시스템 도구, 시스템 라이브러리 등을 포함하여 애플리케이션과 그 애플리케이션을 실행하는 환경을 패키징하여 이식성이 뛰어난 소프트웨어 패키지로 만든것이다.
- 컨테이너화를 통해 더욱 신속하게 작업을 진행할 수 있다.
- 효율적으로 소프트웨어를 배포할 수 있다.
- 매우 높은 수준의 확장성을 확보할 수 있다.
서버 가상화 컴퓨터의 성능을 효율적으로 사용하기 위해 가상화 기술이 등장하였다. 서버 관리자 입장에서 리소스 사용률이 적은 서버들은 낭비라고 생각할 수 있다. 그렇다고 모든 서비스를 한 서버 안에 올린다면 안정성에 문제가 생길 수 있다. 이에 따라 안정성을 높이며 리소스를 최대한 활용할 수 있는 방법으로 고안된 방법이 서버 가상화이다.
컨테이너 정의
컨테이너는 소프트웨어 서비스를 실행하는 데 필요한 특정 버전의 프로그래밍 언어 런타임 및 라이브러리와 같은 종속 항목과 애플리케이션 코드를 함께 포함하는 경량 패키지이다.
컨테이너는 운영체제 수준에서 CPU, 메모리, 스토리지, 네트워크 리소스를 쉽게 공유할 수 있게 해주며 컨테이너가 실제로 실행되는 환경에서 애플리케이션을 추상화 할 수 있는 논리 패키징 매커니즘을 제공한다.
컨테이너의 이점
책임 분리
컨테이너화를 통해 책임을 깔끔하게 분리할 수 있다.
개발자는 애플리케이션의 로직과 종속 항목에 집중하고, IT 운영팀은 특정 소프트웨어 버전 및 구성과 같은 애플리케이션의 세부 요소 대신 배포 및 관리에 집중할 수 있다.
워크로드 이동성
컨테이너는 Linux, Windows, Mac 등 운영체제를 가리지 않고, 가상머신 물리적 서버, 개발자 컴퓨터, 데이터 센터, 온프레미스 환경, 퍼블릭 클라우드 등 사실상 어느 환경에서나 구동되므로 개발 및 배포가 크게 쉬워진다.
애플리케이션 격리
컨테이너는 운영체제 수준에서 CPU, 메모리, 스토리지, 네트워크 리소스를 가상화 하므로 개발자에게 다른 애플리케이션으로부터 논리적으로 격리된 OS 환경을 제공한다.
컨테이너와 VM의 차이
VM은 기본 하드웨어에 대한 엑세스 권한을 갖는 호스트 운영체제 위에서 Linux또는 Windows 같은 게스트 운영체제를 실행하기 때문에 컨테이너와 비교되는 경우가 많다.
컨테이너는 가상 머신과 마찬가지로 애필리케이션을 관련 라이브러리 및 종속 항목과 함께 패키지로 묶어 소프트웨어 서비스 구동을 위한 격리 환경을 마련해준다. 그러나 컨테이너를 사용하면 훨씬 작은 단위로 업무를 수행할 수 있어 이점이 훨씬 많다.
- VM 보다 훨씬 더 가볍다.
- OS 수준에서 가상화되고, VM은 하드웨어 수준에서 가상화된다.
- OS 커널을 공유하며 VM에서 필요한 것 보다 훨씬 적은 메모리를 사용한다.
컨테이너의 용도
애플리케이션을 실제 구동 환경으로부터 추상화할 수 있는 논리 패키징 메커니즘을 제공함. 이러한 분리를 통해 어떤 환경에서도 컨테이너 기반 애플리케이션을 쉽게 지속적으로 배포할 수 있음.
민첩한 개발
컨테이너를 사용하면 개발자가 종속 항목과 환경에 미치는 영향을 신경쓰지 않고 훨씬 더 빠르게 개발을 진행할 수 있다.
효율적인 운영
컨테이너는 경량이며 필요한 컴퓨팅 리소스만 사용하면 된다. 따라서 애플리케이션을 효율적으로 구동할 수 있다.
폭넓은 구동 환경
컨테이너는 거의 모든 곳에서 구동할 수 있어 환경에 영향 없이 사용할 수 있다.
컨테이너 기술
Namespaces
VM에서는 각 게스트 머신별로 독립적인 공간을 제공하고 서로가 충돌하지 않도록 하는 기능을 갖추고 있다.
리눅스에서는 이와 동일한 역할을 하는 namespaces 기능을 커널에 내장하고 있다.
- mnt(파일시스템 마운트): 호스트 파일 시스템에 구애받지 않고 독립적으로 파일 시스템을 마운트하거나 언마운트 가능
- pid(프로세스): 독립적은 프로세스 공간을 할당
- net(네트워크): namespace간 network 충돌 방지(중복 포트 바인딩 등)
- ipc(SystemV IPC): 프로세스간의 독립적인 통신통로 할당
- uts(hostname): 독립적인 hostname 할당
- user(UID): 독립적인 사용자 할당
namespaces를 지원하는 리눅스 커널을 사용하고 있다면 다음 명령어를 통해 바로 namespace를 만들어 실행할 수 있다.
|
|
|
|
PID namespace에 실행한 bash가 PID 1로 할당되어 있고, 바로 다음 실행한 ps aux 명령어가 PID 2를 배정 받았다.
cgroups - Control Groups
cgrups는 자원(resources)에 대한 제어를 가능하게 해주는 리눅스 커널 기능으로 아래와 같은 자원들을 제어할 수 있다.
- 메모리
- CPU
- I/O
- 네트워크
- device 노드 (
/dev/
)
|
|
|
|
/sys/fs/cgroup/*/groupname
경로에 있는 파일을 통해 그룹의 여러 옵션들을 변경 가능
|
|
정리
LXC
, LibContainer
, runC
등은 위에서 설명한 cgrups
, namespaces
를 표준으로 정의해둔 OCI(Open Container Initative) 스펙을 구현한 컨테이너 기술의 구현체이다.
LXC는 캐노니컬(Canonical)이 지원하고 있는 리눅스 컨테이너 프로젝트로 Docker의 경우 1.8 이전 버전까지 LXC를 이용해 구현해서 사용되었다.
이후 Docker는 libcontainer → runC(libcontainer의 리팩토링 구현체)로 자체 구현체를 갖게 되었다.
Docker
도커는 1.11버전부터 위와 같은 구조로 작동한다.
containerd는 OCI 구현체(주로 runC)를 이용해 container를 관리해주는 deamon이다.
도커 엔진 자체는 이미지, 네트워크, 디스크 등의 리소스 관리 역할을 수행하며, 여기서 도커 엔진과 containerd 각각이 완전히 분리되어 도커 엔진을 재시작 해도, 컨테이너 재시작 없이 사용할 수 있다.
위와 같이 각각 역할이 분리됨에 따라 도커는 4개의 독립적인 프로세스로 작동하고 있다. (docker
, docker-containerd
, docker-containerd-shim
, docker-runc
)