컨테이너는 Docker와 Kubernetes의 바탕이 되는 기술입니다. 이 기술은 리눅스 커널의 네임스페이스(namespace)와 리눅스 컨트롤 그룹(cgroup)을 이용해 자원을 격리하고 제어합니다. 컨테이너는 이 두 기능으로 단순한 이미지 실행 환경을 넘어서 리눅스의 강력한 자원 격리와 제한 기능을 활용합니다. 이 글에서는 리눅스 커널의 네임스페이스와 cgroup의 개념을 살펴보고, 두 기능의 사용법을 실습 예제와 함께 알아보겠습니다.
이 글은 AWS EC2의 Ubuntu 20.04 LTS 환경을 기준으로 작성했습니다.
컨테이너 격리의 핵심: 리눅스 커널의 네임스페이스
리눅스 커널의 네임스페이스는 커널 자원을 분할해 프로세스마다 격리된 시스템 환경을 제공하는 중요한 커널 기능입니다. 예를 들어, 하나의 건물 안에 여러 개의 독립된 방이 있는 것처럼, 네임스페이스로 컨테이너 내부의 프로세스가 호스트 시스템이나 다른 컨테이너 자원에 접근하지 못하도록 논리적 경계를 설정합니다. 이러한 격리 기능 덕분에 여러 컨테이너가 동일한 호스트에서 안전하고 효율적으로 실행될 수 있습니다.
주요 네임스페이스 종류
리눅스 커널은 다양한 네임스페이스를 제공하며, 각각 특정 자원을 격리합니다. 컨테이너 기술에서 주로 사용하는 8가지 네임스페이스는 다음과 같습니다.
- 마운트(mnt): 독립적인 파일 시스템 환경을 위한 마운트 지점 격리
- 프로세스 ID(pid): 컨테이너 내부의 프로세스를 독립적으로 관리하기 위한 PID 공간 분리
- 네트워크(net): IP 주소와 포트 등 독립적인 네트워크 스택 제공
- IPC: 프로세스 간 통신(IPC) 자원의 격리
- UTS: 호스트 이름과 도메인 이름의 격리
- 사용자(user): 사용자와 그룹 ID의 격리, 호스트 시스템에서 root 권한 제한
- cgroup: 자원 제어 그룹 계층 구조 격리
- 타임(time): 시스템 시간을 독립적으로 설정하도록 지원
unshare
명령어를 사용하면 원하는 네임스페이스를 생성해 지정한 프로그램을 격리된 환경에서 실행할 수 있습니다. 또 다양한 옵션으로 필요한 네임스페이스를 자유롭게 설정할 수 있습니다.
네임스페이스 격리 실습
간단한 예시로 PID 네임스페이스의 격리를 확인하겠습니다. 아래는 해당 명령어와 출력 예시입니다.
$ sudo unshare --pid --fork --mount-proc ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 10540 3128 pts/0 R+ 09:33 0:00 ps aux
위 명령어는 새로운 PID 네임스페이스를 생성하고 /proc
파일 시스템을 마운트한 뒤, ps aux
를 실행합니다. 명령어 아래 출력 예시에서 보듯, 이 새로운 네임스페이스 안에서는 격리된 프로세스 목록만 확인할 수 있으며, 이때 프로세스는 PID 1부터 시작하는 독립된 프로세스 트리를 갖습니다.
네트워크 격리의 핵심: 네트워크 네임스페이스와 가상 이더넷(veth) 쌍
네트워크 네임스페이스는 각 컨테이너에 독립적인 네트워크 환경을 제공하는 핵심 기능입니다. 각 네임스페이스는 자체 네트워크 인터페이스, IP 주소, 라우팅 테이블, 방화벽 규칙이 있습니다. 이로써 여러 컨테이너가 한 호스트 위에서 동시에 동작해도 서로 네트워크 설정에 간섭받지 않습니다.
가상 이더넷(veth: virtual ethernet) 쌍은 네임스페이스 간 통신을 구성할 때 사용됩니다. veth는 두 개의 가상 네트워크 인터페이스로, 한쪽에서 전송한 패킷이 곧바로 다른 쪽에 수신됩니다. 이를 이용하면 한쪽 인터페이스를 컨테이너의 네트워크 네임스페이스에, 나머지 한쪽을 호스트나 다 른 컨테이너 네임스페이스에 연결해 컨테이너와 호스트 간 또는 컨테이너 간에 네트워크 통신을 설정할 수 있습니다.
리눅스 네트워크 네임스페이스 환경에서 컨테이너 간 통신 구조네트워크 네임스페이스 생성, veth 인터페이스 구성 실습
지금부터 네트워크 네임스페이스 두 개를 만들고, veth 쌍을 생성해 각각 연결하겠습니다. 네트워크 네임스페이스와 veth 인터페이스를 수동으로 구성해 리눅스 기반 컨테이너 네트워크가 격리된 환경을 만들고, 서로 통신하도록 연결되는 방식을 직접 확인할 수 있습니다.
-
네트워크 네임스페이스 생성: 독립적인 네트워크 환경을 테스트하기 위해 두 개의 네임스페이스(ns1, ns2)를 생성합니다.
sudo ip netns add ns1
sudo ip netns add ns2