#!if 넘어옴1 != null
''''''{{{#!if 넘어옴2 != null
, ''''''}}}{{{#!if 넘어옴3 != null
, ''''''}}}{{{#!if 넘어옴4 != null
, ''''''}}}{{{#!if 넘어옴5 != null
, ''''''}}}{{{#!if 넘어옴6 != null
, ''''''}}}{{{#!if 넘어옴7 != null
, ''''''}}}{{{#!if 넘어옴8 != null
, ''''''}}}{{{#!if 넘어옴9 != null
, ''''''}}}{{{#!if 넘어옴10 != null
, ''''''}}}은(는) 여기로 연결됩니다.
#!if 설명 == null && 리스트 == null
{{{#!if 설명1 == null
다른 뜻에 대한 내용은 아래 문서를}}}{{{#!if 설명1 != null
{{{#!html 동음이의어}}}에 대한 내용은 [[컨테이너]] 문서{{{#!if (문단1 == null) == (앵커1 == null)
를}}}{{{#!if 문단1 != null & 앵커1 == null
의 [[컨테이너#s-|]]번 문단을}}}{{{#!if 문단1 == null & 앵커1 != null
의 [[컨테이너#|]] 부분을}}}}}}{{{#!if 설명2 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단2 == null) == (앵커2 == null)
를}}}{{{#!if 문단2 != null & 앵커2 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단2 == null & 앵커2 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명3 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단3 == null) == (앵커3 == null)
를}}}{{{#!if 문단3 != null & 앵커3 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단3 == null & 앵커3 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명4 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단4 == null) == (앵커4 == null)
를}}}{{{#!if 문단4 != null & 앵커4 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단4 == null & 앵커4 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명5 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단5 == null) == (앵커5 == null)
를}}}{{{#!if 문단5 != null & 앵커5 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단5 == null & 앵커5 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명6 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단6 == null) == (앵커6 == null)
를}}}{{{#!if 문단6 != null & 앵커6 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단6 == null & 앵커6 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명7 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단7 == null) == (앵커7 == null)
를}}}{{{#!if 문단7 != null & 앵커7 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단7 == null & 앵커7 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명8 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단8 == null) == (앵커8 == null)
를}}}{{{#!if 문단8 != null & 앵커8 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단8 == null & 앵커8 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명9 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단9 == null) == (앵커9 == null)
를}}}{{{#!if 문단9 != null & 앵커9 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단9 == null & 앵커9 != null
의 [[#|]] 부분을}}}}}}{{{#!if 설명10 != null
, {{{#!html }}}에 대한 내용은 [[]] 문서{{{#!if (문단10 == null) == (앵커10 == null)
를}}}{{{#!if 문단10 != null & 앵커10 == null
의 [[#s-|]]번 문단을}}}{{{#!if 문단10 == null & 앵커10 != null
의 [[#|]] 부분을}}}}}}
#!if 설명 == null
{{{#!if 리스트 != null
다른 뜻에 대한 내용은 아래 문서를}}} 참고하십시오.
#!if 리스트 != null
{{{#!if 문서명1 != null
* {{{#!if 설명1 != null
동음이의어: }}}[[컨테이너]] {{{#!if 문단1 != null & 앵커1 == null
문서의 [[컨테이너#s-|]]번 문단}}}{{{#!if 문단1 == null & 앵커1 != null
문서의 [[컨테이너#|]] 부분}}}}}}{{{#!if 문서명2 != null
* {{{#!if 설명2 != null
: }}}[[]] {{{#!if 문단2 != null & 앵커2 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단2 == null & 앵커2 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명3 != null
* {{{#!if 설명3 != null
: }}}[[]] {{{#!if 문단3 != null & 앵커3 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단3 == null & 앵커3 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명4 != null
* {{{#!if 설명4 != null
: }}}[[]] {{{#!if 문단4 != null & 앵커4 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단4 == null & 앵커4 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명5 != null
* {{{#!if 설명5 != null
: }}}[[]] {{{#!if 문단5 != null & 앵커5 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단5 == null & 앵커5 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명6 != null
* {{{#!if 설명6 != null
: }}}[[]] {{{#!if 문단6 != null & 앵커6 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단6 == null & 앵커6 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명7 != null
* {{{#!if 설명7 != null
: }}}[[]] {{{#!if 문단7 != null & 앵커7 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단7 == null & 앵커7 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명8 != null
* {{{#!if 설명8 != null
: }}}[[]] {{{#!if 문단8 != null & 앵커8 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단8 == null & 앵커8 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명9 != null
* {{{#!if 설명9 != null
: }}}[[]] {{{#!if 문단9 != null & 앵커9 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단9 == null & 앵커9 != null
문서의 [[#|]] 부분}}}}}}{{{#!if 문서명10 != null
* {{{#!if 설명10 != null
: }}}[[]] {{{#!if 문단10 != null & 앵커10 == null
문서의 [[#s-|]]번 문단}}}{{{#!if 문단10 == null & 앵커10 != null
문서의 [[#|]] 부분}}}}}}
1. 개요
실행중인 컴퓨터의 커널에 라이브러리, 실행파일을 격리하고, 이 공간 내에 독립된 프로세스 및 네트워크를 실행시키는 기술과 이를 위한 소프트웨어 구성 일체를 이야기한다. 같은 버전 커널에서 동일한 동작을 보장한다.어원은 화물 컨테이너로, 컨테이너를 이용하면 화물을 규격화하여 어디든 쉽게 옮길 수 있다는 특성과, 컨테이너 안에 있는 화물은 외부와 격리되어 바깥을 볼 수 없다는 특성 등에서 착안한 이름으로 보인다.
2. 원리
프로그램이 정해진 구역 바깥의 리소스를 보지 못하도록 프로세스를 격리하자는 아이디어 자체는 오랫동안 있었다. 특정 프로세스가 인식하는 루트 디렉토리를 다른 곳으로 변경하는 유닉스 시스템 콜인chroot
(Change Root)는 1979년 AT&T의 Version 7 Unix에 처음 도입되었고, 이렇게 프로세스가 격리된 환경을 흔히 "chroot jail"이라고 불렀다.이 chroot에서 착안하여, 특정 프로세스의 파일시스템에 대한 접근, 사용자, 네트워크 서브시스템 등을 모두 격리시킬 수 있도록 만든 것이 FreeBSD의 Jail이고, 현대에 사용되는 컨테이너 기술의 원형이다. 한편 이러한 부류의 기술에 컨테이너(container)라는 이름을 붙인 것은 썬 마이크로시스템즈로, 솔라리스 10의 컨테이너 기술인 "솔라리스 컨테이너"에서 이를 처음 사용하였다.
한편 리눅스에서는 커널 2.6.24에서 cgroup(컨트롤 그룹)이 도입되면서, cgroup과 namespace를 이용한 컨테이너 구현이 가능해졌다. 이후 리눅스 진영에서는 Docker가 너무 유명해진 나머지 한동안 컨테이너=Docker라는 인식이 박히게 될 정도였으나, Docker 이전에도 IBM에서 처음 개발한 LXC(Linux Containers)나 OpenVZ 등의 컨테이너 구현체가 존재했으며, 지금도 containerd나 CRI-O 등이 활발하게 개발되고 있다.
윈도우 커널에 의존하는 컨테이너 기술이 구현되긴 했다. 하지만 라이선스 문제[1]가 있고, Windows는 서버 목적보다는 개인 단말 목적의 네이티브 상태가 가장 이상적이기 때문에, 단순히 가능성만 열어두고 그 규모가 커지지는 않았다. Windows에 Windows Subsystem for Linux(WSL)이 탑재된 이후부터 리눅스 커널에 의존하는 컨테이너를 끌어다 쓸 수 있게 되면서 더 외면받고 있는 상황이다. 다만 Microsoft Azure 서버에는 컨테이너 기술이 활용되고 있다.
macOS의 XNU 커널은 FreeBSD와는 달리 Jail을 구현하지 않았다. 대신 MACF라는 자체적인 샌드박싱 시스템을 구현했는데, 특성상 컨테이너를 구현하기에는 적합하지 않다. 이 때문에 macOS에서 Docker Desktop이나 Podman 등을 구동하면, 그냥 백그라운드에서 리눅스 가상머신을 하나 띄운 뒤 그 위에서 컨테이너를 돌린다.
3. 가상머신과 차이점
컨테이너 기술은 가상화 기술과 자주 비교된다. 이 둘의 차이점은 구현 수준과 이에 따른 동작속도 및 구현의 제약이다.
VMware/VirtualBox/QEMU로 대표되는 가상화란 물리적 실체가 존재하는 하드웨어를 그 동작원리만 소프트웨어로 구현하는 기술이다. 그리고 그 가상화된 하드웨어 위에 운영체제를 포함한 다른 소프트웨어를 설치할 수 있다. 컴퓨터 안에 컴퓨터를 만들어내는 것이다. 하드웨어 수준부터 구현해야 하기 때문에 많은 시간과 자원을 소모한다. 대신 하드웨어 수준에서 구현하기 때문에 컨테이너와 달리 다른 운영체제 환경까지 구현할 수 있다. 예를 들어 x86 CPU를 사용하고 Windows 10을 운영체제로 하는 컴퓨터가 있을 때, ARM CPU를 사용하는 Raspberry Pi에서 구동되는 소프트웨어를 개발하고 이를 테스트하기 위해 새로운 하드웨어를 구비하는 것은 비효율적이므로, 소프트웨어를 이용해 ARM CPU가 구동되는 하드웨어 환경을 가상으로 구현하는 식이다. 또 다른 예로 Windows 10 환경에서 Windows XP 이하에서만 돌아가는 소프트웨어를 구동해야 할 경우 가상머신 소프트웨어로 가상의 컴퓨터를 구현해 Windows XP를 설치하여 사용하는 방식도 가능하다. 이러한 가상머신의 하드웨어는 호스트 컴퓨터로부터 완벽히 독립적으로 운영되고, 커널, 라이브러리, 실행파일 또한 가상머신에 종속된다.
반면 컨테이너는 기존 운영체제 안에 그냥 격리된 구역, 즉 컨테이너를 만들고 이 안에서 라이브러리, 실행파일을 작동시키는 것이다. 하나의 컨테이너는 다른 컨테이너의 네트워크나 프로세스의 상태를 알 수 없고, 다른 컨테이너의 라이브러리와 실행파일이 격리되어야 한다. 종종 컨테이너 기술은 소프트웨어를 가상화하는 기술이라고 표현하는 비전문가들도 있는데, 가상화란 물리적인 것을 비물리적으로 구현하는 기술이기 때문에 소프트웨어를 가상화한다는건 문법적으로 틀렸다. 컨테이너는 기존 운영체제 안에서 격리된 구역만 만드는 기술이기 때문에 속도는 빠르지만 다른 운영체제의 환경까지 구현하진 못한다.
4. 컨테이너의 한계
컨테이너를 복사해 사용할 환경이 컨테이너를 빌드한 환경과 커널 버전이 다르면 컨테이너가 구동되지 않을 수도 있다. 리눅스 커널 5.15에서 구성한 컨테이너가 커널 리눅스 커널 6.2에서 돌아가지 않을 수도 있다는 뜻이다.만약 컨테이너가 x86_64 하드웨어에 맞는 커널에서 빌드하였지만 ARM 하드웨어에 설치된 커널이 x86_64로 만들어진 컨테이너를 호환하여 지원하던지 컨테이너가 다양한 커널을 지원한다면[2] 컨테이너는 커널에 의존하기 때문에 가상머신에 비해 효율적으로 동작할 수 있다. 보통 컨테이너에 의존하는 커널은 하드웨어 또는 가상머신에서 만든다.
또한, 컨테이너는 자신의 커널이 없고 호스트의 커널을 그대로 재사용하므로 호스트에서 OS 취약점이 발생할 경우 컨테이너로도 악성코드 침투가 가능하다.