티스토리 뷰

리눅스/시스템

LXC의 구현

로또_ 2019. 9. 13. 22:17

LXC의 구현

 

chroot

 

LXC와 비슷한 기술로 “chroot”라는 것이 있습니다. chroot는 프로세스의 루트 디렉토리를 변경하는 것으로, 이를 통해 프로세스가 액세스 할 수있는 디렉토리를 제한하거나 시스템 라이브러리와 관련 라이브러리를 로드 할 수있습니다. 그러나 chroot에서 제어 할 수있는 파일이나 디렉토리에 대한 액세스만으로, 네트워크 및 프로세스 등을 컨트롤 할 수는 없습니다. 또한 FreeBSD 에는 chroot를 발전시킨 툴로서 “jail”라는 기능이 탑재되어있습니다. jail는 파일 시스템에 대한 액세스뿐만 아니라 프로세스 및 장치 등의 자원에 대해서도 제어가 가능합니다. LXC가 jail과 유사한 개념으로 구현 되었습니다. cgroups은 OS가 관리하는 다양한 리소스를 중앙에서 제어하기 위한 도구입니다. 리소스를 그룹화하고 각 그룹에 대해 우선 순위 및 사용 가능한 리소스를 제한하거나 그룹을 분리하고 다른 그룹에서는 보이지하는 등 기능을 제공합니다.
cgroups에서 관리하는 대상은 파일 시스템이나 프로세스뿐만 아니라 CPU 리소스와 메모리, 각종 디바이스, 네트워크 패킷, 네트워크 인터페이스 등 입니다.
cgroups의 이용 예로는 특정 프로세스에서 사용 가능한 메모리와 CPU 시간 등을 제한하는 것이 있으며, LXC는 프로세스에 대해 chroot 같이 특정 디렉토리를 루트 디렉토리로 인식하도록하며 cgroups의 네임 스페이스 기능을 사용하여 다양한 자원을 격리함으로써 가상 환경을 구현합니다.

 

 

컨테이너마다 분할되는 자원에는 다음과 같은 것이 있습니다.


프로세스 테이블컨테이너마다 별도의 프로세스 테이블를 관리하여 컨테이너의 프로세스에서 다른 컨테이너의 프로세스가 보이지 않도록합니다.

 

파일 시스템컨테이너마다 특정 디렉토리를 루트 파일 시스템으로 보이게 합니다. “chroot”와 동일한 개념입니다.

 

네트워크 : 네트워크 네임 스페이스 (netns)의 기능은 컨테이너마다 별도의 네트워크 설정을 구성합니다. “veth”라는 가상 NIC 장치를 이용하여 veth의 한쪽을 컨테이너 내부 네임 스페이스에 할당합니다.


CPU, 메모리 장치 ( “/dev”다음 장치 파일) : cgroups의 기능은 컨테이너에서 사용할 수있는 범위를 제한합니다.

 

 


 

LXC 와 Linux 컨테이너 기술들

 

LXC 외에도 Linux에서 컨테이너를 실현하기위한 소프트웨어는 여러가지 있으며, 다음에서 대표적인 몇가지를 설명합니다.
( OpenVZ, Virtuozzo, libvirt, Docker, systemd, Warden)


OpenVZ
OpenVZ 는 Linux 커널에 컨테이너 관련 기술이 충분히 구현되지 않은 오래전부터 Linux 커널에 패치 컨테이너를 구현한 것입니다. OpenVZ와 그것을 바탕으로 한 상용 소프트웨어 인 페러럴즈의 Virtuozzo 는 이전부터 전세계의 호스팅 서비스에서 널리 사용되어 왔으며, 현재에도 널리 사용되고 있는 안정적인 상용 소프트웨어입니다. 현재 Linux 커널에 구현되어있는 컨테이너 관련 구현은 OpenVZ 에서 유래한 것이 많이 있고, 현재에도 OpenVZ 개발자가 구현을 추진하고있는 기능이 존재합니다.

 

libvirt
libvirt 는 가상 머신을 수행 공통 API를 제공하는 라이브러리에서 다양한 가상화를 지원합니다. 그 중에서도 “LXC”을 지원합니다.

 

Docker
Docker 는 Docker Inc.에 의해 개발 된 Go 언어로 작성된 소프트웨어입니다. 원래는 컨테이너를 실현하기 위해 LXC을 사용하고있었지만, Docker 0.9 버전 부터는 기본으로 직접 만든 자체 컨테이너를 사용하고 있습니다. Docker는 단순한 컨테이너의 구현을 넘어 컨테이너 기반 가상화 에코시스템을 구축하고 있습니다.

 

이 외에도 systemd에 간단한 컨테이너를 제공하는 명령이 포함되어 있고, Cloud Foundry에서 컨테이너 기능을 실현하기위한 Warden 등 일부 컨테이너의 구현이 있습니다, 물론 Linux 이외에도 컨테이너의 구현은 몇 하나 존재합니다.

 


 

 

더 나아가기에 앞서 cgroupnamespace에 대해 자세히 알아보고 가겠습니다

 

 

Cgroup (Control Group)

 

 

Cgroup은 CPU, Network, Memory 등 하드웨어 자원을 그룹별로 관리 할 수 있는 리눅스의 모듈입니다. 하나 또는 복수의 장치를 묶어서 하나의 그룹을 만들 수 있으며 개별 그룹은 시스템에서 설정한 값만큼 하드웨어를 사용할 수 있습니다. 설정하는 값은 예를 들면 이런 것들입니다.

  • 어떤 그룹이 CPU를 더 많이 차지 할 것인지?
  • 그룹이 얼마만큼 메모리를 사용 할 수 있는지?
  • 네트워크 우선순위를 얼만큼 줄 것인가.

시스템에 생성된 프로세스들은 장치 별로 특정한 cgroup에 속하며 프로세스가 사용하는 하드웨어 자원의 총량은 속한 cgroup의 통제를 받게 됩니다. 이말은 곧 프로세스가 아무리 효율적으로 동작하도록 만들어져 있어도 cpu 점유율이 낮은 cgroup에 속해 있으면 속도가 느릴 수 밖에 없고 cgroup 자체가 CPU 점유율이 높아도 이 그룹에 속한 프로세스가 많으면 전반적인 속도가 저하 될 수 밖에없습니다. 리눅스에선 하드웨어와 프로세스 사이에 cgroup 계층을 두어서 자원을 관리할 수 있도록 만들었습니다.

 

하드웨어와 cgroup, 프로세스간의 관계는 아래의 그림처럼 표현 할 수 있습니다.

 

 

 

cgroup 서브시스템

커널 v5.0 기준 14개의 서브시스템이 있다.

(cpuset, cpu, cpuacct, io, memory, devices, freezer, net_cls, perf_event, net_prio, hugetlb, pids, rdma, debug)


장점

CPU 코어별 jobs 배치 및 코어 스위칭 코스트 감소

 

 

 


 

 

Namespace

VM에서는 각 게스트 머신별 독립적인 공간을 제공하고 서로가 충돌하지 않도록 하는 기능을 갖고 있습니다. 리눅스에서 동일한 역활을 하는 것이 Namespace이며 커널에 내장되어 있습니다. Hypervisor는 Hardware Resource를 가상화 하고 위에 올라가는 Guest OS에는 가상화 된 형태의 H/W를 제공하게 되므로 각 Guest OS는 완전히 다른 환경으로 분리됩니다. 하지만 Namespace의 경우 Hardware Resource 레벨의 가상화가 아니고 동일한 OS와 동일한 Kernel에서 작동하게 됩니다. 단지 격리된 환경만 제공하는 것입니다. (Namespace는 H/W 자원을 가상화하는 것이 아니라 Linux 내의 자원을 가상화 하는 것)

 

하나의 시스템에서 프로세스를 격리시킵니다.

 

리눅스에서 namespace는 lightweight 가상화 솔루션입니다. XEN이나 KVM 같은 가상화 솔루션들은 커널 인스턴스들을 생성하여 동작시키는 것에 반하여 리눅스의 namespace는 커널 인스턴스를 만들지 않고 기존의 리소스들을 필요한 만큼의 namespace로 분리하여 묶어 관리하는 방법으로 사용합니다. 리눅스의 cgroup과 namespace를 사용하여 container를 생성하여 사용하는 LXC, 그리고 LXC를 사용하는 docker 솔루션 등이 구현되었습니다.  커널이 부팅된 후 관리 자원은 각각의 초기 디폴트 namespace에서 관리합니다. 그런 후 사용자의 필요에 따라 namespace를 추가하여 자원들을 별도로 분리하여 관리할 수 있습니다. 관리 가능한 namespace 리소스들은 다음과 같습니다. 총 6가지의 namespace가 존재합니다.

 

 

pid namespace

 

프로세스에 대응하는 pid, CONFIG_PID_NS 커널 옵션 사용

프로세스 ID를 분할하여 관리하기 위해 필요합니다. systemd 프로세스만 가질 수 있는 PID 1번을 독립적으로 추가 할당하며 동일한 OS에서 systemd프로세스 뿐만 아니라 여러 프로세스가 PID 충돌없이 실행 가능하게 합니다. namespace가 다른 프로세스 끼리는 서로 엑서스할 수 없습니다.

 

 

uts namespace

 

“uname” syscall 에서 보여주는 호스트명 및 커널 버전 정보, CONFIG_UTS_NS 커널 옵션 사용합니다.

namespace 별로 호스트명이나 도메인 명을 독자적으로 가질 수 있습니다.(독립적인 Hostname 할당)

각각의 리눅스 컨테이너가 자신의 식별자(hostname -f로 확인)를 유지관리하기 위해 호스트 이름과 도메인이름을 네임스페이스 별로 격리합니다.

 

 

ipc namespace

 

SYSVIPC와 posix mqueue, CONFIG_IPC_NS 커널 옵션 사용합니다.

프로세스간 데이터 교환 및 프로세스와 쓰레드간의 작업을 동기화하는 기능을 제공합니다. 프로세스간 통신(IPC) 오브젝트를 namespace 별로 독립적으로 가질 수 있습니다. semaphore, file locking, mutex 기타 자원에 대한 접근제어를 제공하며 컨테이너에서 실제 프로세스를 분리하기 위해서도 필요합니다.

 

 

net namespace

 

네트워크 디바이스, IP, 라우팅 정보, IP 테이블 정보, CONFIG_NET_NS 커널 옵션 사용합니다.

네트워크 디바이스, IP 주소, Port번호, 라우팅 테이블, 필터링테이블 등의 네트워크 리소스를 namespace마다 격리시켜 독립적으로 가질 수 있습니다. 이 기능을 사용하면 OS상에서 사용중인 Port가 있더라도 컨테이너 안에서 동일한 Port를 사용 가능합니다

namespace 간의 network 충돌을 방지합니다(중복 포트 바인딩 등). 네트워크 장치, 주소, 경로 및 방화벽 규칙 같은 네트워크 자원을 격리합니다. 네트워크 스택의 논리적 복사본을 효과적으로 생성하여 여러 namespace가 동일 포트로 다수의 서비스 제공하는 것을 가능하게 합니다(iproute2 package등을 이용하여 구현 가능합니다)

 

user namespace

 

CONFIG_USER_NS 커널 옵션, 사용자 정보 (커널 v3.8에 소개되어 아직도 많은 리눅스 파일 시스템이 user namespace를 지원하지 않는다.)를 사용합니다.

프로세스가 namespace 내부와 기본 namespace 간에 각기 다른 사용자 및 그룹 ID를 가질 수 있도록 지원합니다. 독립적인 사용자 할당, UID와 GID를 격리합니다.

 

 

mount namespace

 

마운트 파일 시스템 마운트 포인트를 격리합니다. 호스트 파일시스템에 구애받지 않고 독립적으로 파일시스템을 마운트하거나 언마운트 할 수 있습니다. 호스트 OS와 namespce가 서로 다른 격리된 파일시스템 트리를 가질 수 있도록 합니다.(마운트는 컴퓨터에 연결된 기기나 기억장치를 OS에 인식시켜 사용가능한 상태로 만드는 것을 의미한다.)

반응형