리눅스 컨테이너(Linux container)란?
리눅스 컨테이너는 리눅스 커널의 기능들을 사용해서 격리된 프로세스를 만드는 기술을 의미합니다. 리눅스에서 프로세스를 격리하는 기능으로는 커널 네임스페이스, Chroot, CGroups 등의 기능이 있습니다.
눅스 컨테이너의 줄임말인 LXC 프로젝트에서는 리눅스 상에서 이러한 기능들을 조합해서 프로세스를 격리할 수 있는 사용자 인터페이스를 제공했습니다. 초기에 LXC는 사용이 어렵고 안정화가 되어있지 않아 널리 사용되지는 않았습니다.
2013년에는 Docker가 공개되었습니다. Docker는 사용자 친화적인 인터페이스를 제공하고, Docker Hub를 통해 격리된 프로세스를 실행할 수 있는 환경을 그대로 공유할 수 있는 서비스를 함께 제공했습니다. 이를 통해 이식성을 극대화하고, 지속적인 안정화를 통해 리눅스 컨테이너 기술을 보급하는데 기여했습니다.
리눅스 컨테이너 기술#
리눅스 컨테이너는 하나의 기술이 아니라, 다양한 기능들의 조합으로 이루어져있습니다. 특히 리눅스 커널 기능들이 주를 이루지만, 커널 기능 이외에 다른 추가 패키지가 필요한 경우도 있습니다. 예를 들어 LXC 프로젝트에서는 프로세스 격리를 위해 리눅스 커널의 다음과 ��은 기능들을 사용한다고 소개하고 있습니다.
- Kernel namespaces (ipc, uts, mount, pid, network and user)
- Apparmor and SELinux profiles
- Seccomp policies
- Chroots (using pivot_root)
- Kernel capabilities
- CGroups (control groups)
커널 네임스페이스는 시스템 자원을 프로세스에 별도로 할당하는 기능입니다. 호스트가 되는 리눅스 시스템은 전역 네임스페이스를 가지고 있습니다. 이 안에서 프로세스 별로 독립된 네임스페이스를 만들고 이를 특정 프로세스에 할당해서 사용할 수 있습니다. 예를 들어 사용자(user) 네임스페이스는 프로세스의 리눅스 사용자를 별도로 관리합니다. pid 네임스페이스를 분리하면, 분리된 네임스페이스에서 실행된 프로세스의 pid가 1번부터 시작됩니다. 이외에도 디스크 마운트를 관리하는 마운트 네임스페이스, 가상 네트워크 인터페이스를 격리하는 네트워크 인터페이스 등이 있습니다.
Chroots는 프로세스에서 사용하는 루트 디렉터리를 변경해줍니다. 이를 통해서 프로세스는 마치 호스트와는 완전히 별개로 실행된 것과 같은 효과를 누릴 수 있습니다. 이는 또한 이미지 컨셉으로 연결되는 굉장히 강력한 기능이기도 합니다.
CGroups는 컨테이너뿐만 아니라 자원 관리로 이미 많이 사용되는 기술입니다. CGroups를 통해서 프로세스 별로 CPU나 메모리와 같은 자원에 Limit을 설정하고 사용할 수 있습니다.
이외에도 Apparmor, SELinux profiles, Seccomp polices 등은 리눅스 컨테이너의 보안 관련 설정 및 격리를 도와주며, Kernel capabilities는 프로세스에서 사용가능한 리눅스 커널 시스템 콜 권한을 지정할 수 있는 기능입니다.
Docker 역시 이와 같은 기술을 직접 사용하거나 일부는 구현 및 보완해서 사용하고 있습니다. Docker 초기에 주목할만한 특징 중 하나는 이미지 공유를 통한 이식성의 극대화에 있습니다. 이를 위해서 Docker Hub 서비스를 제공했으며, 효과적인 이미지 빌드 및 레이어 구성을 위해 유니온 마운트 파일 시스템들을 적극 채용했습니다. 유니온 마운트로는 OverlayFS, ZFS, VFS, Btrfs, Device Mapper 등을 지원하고 있습니다. 현재 ZFS, Btrfs, OverlayFS 등은 커널 기능으로 사용할 수 있습니다만, Docker 초기에는 리눅스 커널 버전이나 운영체제에 따라 지원 여부가 상이해서 어려움이 있었습니다.
컨테이너 런타임들은 이런 기능들을 통합 인터페이스로 제공해서 컨테이너를 편리하게 사용할 수 있도록 도와줍니다. 하지만 리눅스 커널 프로세스 격리 기능들은 별도로 기능이므로 프로세스에 각각 적용해서 사용해보는 것도 가능합니다. 또한 저수준에서 각 기능들을 조합해서 사용해볼 수 있도록 도와주는 Haconiwa 같은 프로젝트도 있습니다.
가상머신과의 차이#
리눅스 컨테이너는 크게 시스템 컨테이너와 애플리케이션 컨테이너 두 가지 방식으로 나뉩니다. 시스템 컨테이너는 컨테이너 안에서 init 프로세스를 실행해 컨테이너를 마치 가상머신과 같은 독립된 OS로 사용하기 위한 컨테이너입니다. LXC에서는 시스템 컨테이너 방식이 많이 사용되었으며 사용자 입장에서는 가상머신과 큰 차이가 없습니다.
하지만 2013년 Docker가 공개된 이후에는 시스템 컨테이너보���는 애플리케이션 컨테이너 방식이 보편적으로 활용되고 있습니다. 애플리케이션 컨테이너는 실행하는 애플리케이션 프로세스 자체에 컨테이너 격리를 적용하는 방식입니다. 이 때는 온전히 호스트 머신의 프로세스로서 동작하기 때문에 호스트 입자에서는 다른 애플리케이션 프로세스들과 차이가 없습니다. 또한 사용자 입장에서도 OS 수준 OpenSSH나 파일 등에 접근할 수 있는 방법이 제공되지 않기 때문에 가상머신과는 차이가 있습니다.
가상머신과 컨테이너의 가장 큰 차이점은 가상머신은 일반적으로 하드웨어 에뮬레이션을 통해 가상 머신의 하드웨어와 OS레이어가 호스트와는 분리되어있다는 점입니다. 이는 성능 저하와 시스템 준비 및 애플리케이션 실행까지 상당한 시간이 걸린다는 의미를 가지고 있습니다. 이와 달리 컨테이너는 호스트의 리눅스 커널을 그대로 사용하기 때문에 프로세스가 실행되는 정도의 시간밖에는 걸리지 않습니다.
격리 수준은 컨테이너보다 가상머신이 더 높은 편입니다. 원칙적으로 컨테이너에서는 허용되지 않은 호스트의 자원에 접근할 수 없어야하지만, 컨테이너를 통해 호스트의 시스템을 그대로 사용하고 있는만큼 보안 위협에 노출될 수 있습니다. 현재는 가상머신의 장점과 컨테이너의 장점을 결합한 하이브리드 Micro-VM과 같은 방식도 많이 논의되고 있습니다.
도커(Docker)#
Docker는 리눅스 컨테이너 기술을 구현한 대표적인 도구입니다. 2013년 처음 공개되었으며 지금까지도 많은 사랑을 받고 있습니다. Docker의 가장 중요한 특징은 편리한 인터페이스와 Docker Hub를 기반으로 한 뛰어난 이식성에 있습니다. 특히 리눅스가 아닌 맥이나 윈도우에서도 Docker를 사용할 수 있도록 Docker Desktop을 제공하고 있습니다.
Docker의 가장 중요한 특징 중 하나는 유니온 마운트 기반의 이미지 기능을 제공한다는 점입니다. 도커의 핵심 개념인 컨테이너와 이미지에 대해서는 다음 글에서 상세히 알아봅니다.
Docker를 아직 사용해보지 않았다면, 튜토리얼을 따라해보는 걸 추천합니다.
Docker 사용법에 대해서는 다음 문서에서 정리하고 있습니다.
추천 문서#
리눅스 컨테이너에 대한 더 자세한 정보는 다음 글들을 참고해주세요.