Infra/Docker

[Docker] 도커와 컨테이너

jimkwon 2022. 8. 12. 14:05
반응형

개발에 조금이라도 발을 담가봤다면 대부분 '도커'라는 개념을 들어본 적이 있을 것이다.

필자의 경우 주위에서 '도커 참 좋더라~' 라고 하는데,  '그래서 도커가 뭔데..?' 라는 생각이 머리를 맴돌았다.

 

출처 : 대학일기

 

그 후 도커에 대한 내 생각의 흐름은 이렇게 흘러갔다.

대충 구글에 도커 검색 -> 아~ -> (1주일 뒤) 도커가 뭐더라? -> 대충 구글에 도커 검색 -> 아~ 

 

이 무한의 굴레를 끊고자.. 제대로 마음잡고 도커에 대해 공부하고 직접 실습해보며 어느 정도 감을 잡기 시작했다.

그 좌충우돌의 과정을 한 달이 지난 이제서야 포스팅으로 정리해보려 한다.

(포스팅으로 정리하는건 배우는 것과 별개로 정말 어렵고 번거롭다..흑흑.. 모든 블로거들에게 무한한 존경을..)

 

도커에 대한 개념을 쉽게 훑어보고, '정확한 용어'로 기억해 스스로 정의할 수 있도록 하는 것이 이 포스팅의 목표다. 

 

 

 컨테이너의 탄생과 진화과정

 

먼저, 도커를 제대로 이해하기 위해서는 컨테이너에 대한 이해가 필요하다.

 

도커 = 컨테이너?

꽤 많은 사람들이 위와 같이 도커와 컨테이너를 동일시하는 경우가 있었다. (필자도 마찬가지)

결론부터 말하자면 둘은 엄연히 다르다.

컨테이너의 탄생 배경을 훑어 보며 둘의 차이점에 대해 확실히 짚고 넘어가보자.

 

1.  chroot의 탄생

 

컨테이너의 역사는 1979년 chroot를 발표 한 것으로부터 시작된다.

chroot는 프로세스의 루트 디렉토리를 변경하여 프로세스 마다 접근할 수 있는 디렉토리를 제한한다.

 

https://securityqueens.co.uk/im-in-chroot-jail-get-me-out-of-here/

윈도우나 리눅스에서 터미널을 켠 후, 'ls /' 명령어를 통해 가장 최상위 디렉토리에 대한 목록이 나오게 된다.

(위 사진의 경우 노란색 폴더로 명시된 bin, etc, home, usr)

 

여기서 만약 chroot 명령어를 통해 chroot디렉토리를 루트로 설정하면, 'ls /'로 조회했을 때, 위와 같이 빨간 사각형 안의 초록색 디렉토리 bin, etc, home, usr가 조회될것이다.

 

따라서 chroot를 통해 루트 디렉토리를 하위로 설정하게 되면, 해당 프로세스에서는 bob, alice와 같은 노란색 폴더에 접근이 제한된다. 이러한 방식으로 사용자 별로 격리된 공간을 할당 받아 주어진 일을 수행할 수 있게 되었다.

이를 chroot 감옥(JAIL)이라고 부른다. 사용자들을 지정된 감옥에 수감시켜 그 감옥 내에서만 일을 수행하도록 하는..

(뭔가 귀여우면서 섬짓한 느낌..)

 

2. FreeBSD Jail의 탄생

 

chroot는 위와 같이 단순히 파일 접근에 대한 제어만 가능했다. 이후 프로세스, 네트워크까지 분리할 수 있는 기술이 탄생했는데 그것이 FreeBSD가 출시한 Jail이다.

 

단순히 파일 엑세스를 제어하는 것을 넘어 Jail이라는 OS 가상화 환경에서 파일 시스템, 프로세스, 네트워크를 분리할 수 있는 획기적 기술을 제공했다. 이것이 바로 컨테이너의 시작이다!

 

 

3. Namespace, cgroup 그리고 LXC의 탄생

 

[Namespace]

시간이 흘러 이번엔 RedHat에서 시스템 자원을 논리적으로 분할하는 Namespace를 발표하게 된다.

Namespace는 lightweight(경량) 가상화 솔루션이다. (그게 뭔데..)

이는 한 시스템 내에서 '독립된 공간'을 '격리된 환경'에서 운영하는 가상화 기술이다.

즉, 프로세스 별로 시스템의 리소스를 분리해서 실행하도록 도와주는 기능을 제공한다.

 

아직도 말이 너무 어렵게 느껴진다면.. 이를 '아파트'로 추상화해서 생각해보자!

한 아파트에는 101호, 102호..등 호수마다 독립된 주거 환경을 제공해준다.

아파트 = 시스템

101호, 102호... = 프로세스

주거 환경 (거실, 안방, 주방...) = 리소스 (PID, IPC, Network, UID, Mount, UTS)

라고 치환하면,

 

Namespace는 개별 프로세스(101호) 마다 시스템(아파트)의 리소스(주거 환경)를 제공한다.

이 개념이 좀 더 직관적으로 와닿을 것이다.

 

또한 프로세스 끼리는 IP로 통신을 하는데, 이는 서로의 공간을 방문하기 위해 101호, 102호와 같이 호실을 알아야 방문할 수 있는 것과 똑같은 개념이다!

 

 

[cgroup]

이번엔 Google에서 프로세스 자원 이용량을 제어하는 cgroup을 발표했다.

이는 커널의 기능 중 하나로 네트워크, 시스템 메모리, cpu 시간과 같은 자원을 사용자 정의 프로세스에 할당 할 수 있는 기능을 지원한다.

 

즉, 한 프로세스 안에 사용자 원하는 만큼 자원을 할당해줄 수 있는 기능을 제공하는 것이다.

 

[LinuX Containers]

IBM에서 위의 두 기술 Namespace와 cgroup을 사용하여 LXC를 탄생시켰다.

이는 최초의 Linux 컨테이너 엔진으로 컨테이너 기술의 시초라고 볼 수 있다. (근본!)

 

Namespace를 통해 격리된 공간으로 구성된 환경을 만들고, cgroup을 통해 각 환경에 원하는 만큼 자원을 할당할 수 있도록 구현되어있다.

우리가 '컨테이너'라고 부르는 시초격인 이 엔진은 단일 Linux 커널에서 동작하며 처음으로 Linux 상에서 컨테이너 개념을 가장 완벽하게 구현했다고 한다.

 

여기서 '커널'이라는 단어가 언급되는데, 해당 개념이 컨테이너와 가상머신의 차이점을 비교할 때 자주 언급된다.
커널은 CPU, 메모리 등 운영체제의 핵심으로, 거의 모든 하드웨어를 제어하는 프로그램이다. 
(쉽게 말해 컴퓨터의 뇌를 담당해 손, 발을 움직이듯 하드웨어를 제어한다고 보면 편하다)

 

 도커의 탄생

 

컨테이너 (LXC)가 개발된 이후 2013년, 도커가 드디어 오픈 소스 소프트웨어로 공개된다.

도커는 Debian, SUSE 등 모든 Linux 배포판을 지원하며 컨테이너 기술 확산 박차를 가하게 되며,

도커의 시대가 열리기 시작한다.

 

도커에 대해 한 번이라도 찾아본 사람들은, 주로 가상머신과 비교하는 글들을 많이 봤을 것이다.

잠시 방금 다뤘던 LXC의 개념을 복기해보면, 이 엔진은 '단일 Linux 커널'에서 동작한다고 언급하였다.

 

다시 복습해보자! 

커널은 CPU, 메모리 등 운영체제의 핵심으로, 거의 모든 하드웨어를 제어하는 프로그램이다. 

 

(컴퓨터의 뇌를 담당해 사람의 손, 발을 움직이듯 하드웨어를 제어한다.)

 

단일 커널에서 동작한다는 개념은 컨테이너의와 가상머신을 구분하는 핵심 내용이다. 사진과 함께 얘기해보자.

출처 :  https://cloud.google.com/containers/?hl=ko

도커의 내용을 다루며 이와 비슷한 사진을 수도 없이 봤는데, 그럼에도 한 번에 와닿지가 않았다.

(OS를 직접 올리지 않아 자원이 절약...뭐시기..그렇구만.. 라는 모호한 결론으로 끝났다.)

 

시스템을 운영하는 운영 체제는 종류가 다양하다. 가상머신의 경우 그림 가운데에 놓인 Hypervisor가 '하드웨어'를 물리적으로 구분해서 가상화를 진행하므로 App1, App2, App3 환경에는 각기 다른 커널을 통해 하드웨어 제어가 이루어진다.

 

즉, 원래의 Host OS 위에 3개의 Guest OS가 통째로 올라가고, 각각의 Guest OS는 각기 다른 커널을 가지고 하드웨어 제어가 이루어지는 것이다.

본체를 이루는 두뇌와, 그 위의 쫄병 셋의 두뇌까지 올라가 있다고 생각해보라. 상당히 차지하는 공간도 무거울 것이고, 4개의 뇌까지 사용할 만큼의 일이 거의 없으니 불필요한 자원이 낭비되고 부팅이 상당히 오래 걸리게 되는 것이다.

 

반면에 컨테이너의 경우, 본체의 뇌를 같이 공유한다. 따라서 App1~3이 각기 작동하기 위해 필요한 최~소한의 OS만 받아와 구동되기 때문에 훨씬 가볍고 당연히 속도도 훨씬 빨라지게 되는 것이다.

 

 도커 = 컨테이너?

 

이제 게시글의 맨 처음에서 다뤘던 이 질문에 대해 확실하게 대답할 수 있을 것이다.

(아니더라도 걱정하지 말라.. 필자도 수십번을 다시 찾아보면서 이해했으니..^_ㅜ)

 

컨테이너는 '격리된 공간에서 프로세스가 동작하게 해주는 가상화 기술'이고,

도커는 해당 기술을 사용자에게 편리하게 제공해주는 '플랫폼'이다.

(이제 어디가서 도커 = 컨테이너라고 말하지 말기로 나 스스로에게 약속ㅎ)

 

도커와 LXC의 차이

조금 더 세부적으로 둘의 차이를 다뤄보겠다.

LXC(LinuX Container)는 아까 컨테이너의 시초로 다룬 엔진이다.

도커도 물론 처음에는 LXC 기술을 기반으로 구축되었으나, 그 이후 종속 관계를 벗어나 독자적인 기술로 발전했다.

 

LXC는 가상화 기술로 자원의 경량화를 이뤄내는 유용한 방법이지만 사용자에 친숙하지 않다.

그 외의 차이점에 대해 그림과 함께 다뤄보자!

 

 

 

LXC는 하나의 컨테이너에 여러 응용프로그램을 띄우지만, 도커는 1컨테이너 = 1응용프로그램을 권장하고 그와 관련된 여러 툴을 제공한다.

 

  1. 애플리케이션의 기능을 분해해 MSA방식에 유용하고 필요한 기능들 중 필요한걸 골라서 재사용이 용이함
  2. SOA 작동 방식처럼 각 컨테이너 별 기능을 모듈화 하여 여러 애플리케이션 사이에서 프로세스를 공유할 수 있다.

패션 쇼핑몰을 예로 들어서 생각해보자. 기능을 대략적으로 설계해보면 구매, 장바구니, 마이페이지 등이 존재할것이다.

이때 구매, 장바구니, 마이페이지가 한 어플리케이션이 있지않고 각각 독자적으로 만들어 분리된 환경(컨테이너)에서 돌아가도록 하는 것이 MSA 방식이다. (MSA 방식에 대한 자세한 글은 이곳을 참고해보자.)

 

이후 뷰티 쇼핑몰을 만들었을 때, 기존에 돌아가던 장바구니 기능을 그대로 가져와(필요하면 조금 수정해서) 재사용할 수 있으니 상당히 효율적인 방식이다.

 

 

또한  Docker에서는 컨테이너 생성 시 '도커 이미지'를 이용해 구축한다. 그림을 통해 도커 컨테이너 구조를 살펴보자.

 

맨 아래는 아까 언급했던 커널이다. Host OS에서 공유받아 사용한다.

그 위는 컨테이너를 구성하기 위한 Base Image이다. 이 이미지의 특성은 겹겹이 쌓이는 구조를 가지고 있다.

이를 layer형태로 쌓여있다고 하는데, 해당 방식의 이점이 뭐냐면

 

이후 새 컨테이너를 만들 때, 이전 컨테이너를 만들 당시 생성했던 layer가 중복될 경우 또 설치하지 않고 재사용하기 때문에 속도가 더 빠르고 효율성이 개선된다는 것이다.

(요리에 비교를 하면, 김치찌개(컨테이너1)와 김치볶음밥(컨테이너2)를 만들 때, 이미 김치찌개에 사용된 재료(김치)는 재설치 없이 바로 사용하게 되어 중복이 사라진다는 것이다.

 

이 방식을 통해 도커를 통해 가상화 환경을 구축하면 재사용성이 높아져 자원을 효율적으로 다룰 수 있게 되는 것이다.

 

 도커는 만능이 아니다.

 

도커의 장점을 다시 정리해보자.

 

1. 한 서버에 여러 개의 컨테이너를 구동해 가상화가 가능하다.

(마치 여러 서버를 구매해서 돌리는 것 같지만, 한 서버 안에 여러 개의 컨테이너를 생성해 다양한 응용프로그램이 독립된 각각의 환경에서 돌아가는 것이 가능해진다.)

 

2. 필요한 리소스를 사용자가 할당 가능하므로 개발 환경에 구애받지 않는다. 
(컨테이너 1은 CentOS가 돌아가고.. 컨테이너 2는 Ubuntu가 돌아가게 구현이 가능하다)

 

3. 2번 방법이 가능한 가상머신보다 심지어 훨씬 가볍고 빠르게 경량화가 되어있다.
(HostOS의 커널을 공유하기 때문의 일일이 OS를 새로 만들지 않아도 최소한의 OS로만 동작한다.)

 

 

이렇게만 보면 도커는 완벽해보인다. 완전 짱이잖아..? 하지만 이러한 도커에도 단점이 존재한다.

 

'독립된 환경'이 도커의 장점이자 단점이 될수 있다. 이게 무슨말일까?

도커의 권장사항은 1컨테이너 = 1응용프로그램이다.

 

그 의미는 개발자가 만들고자 하는 서비스의 규모가 커질수록 구현해야 할 응용프로그램이 늘어나고, 그 만큼 컨테이너의 수가 무수히 많아질 것이다. 문제는 컨테이너가 독립된 환경이기 때문에 각자 도생하는 녀석을 한 데 불러모으기가 상당히 어렵다는 것이다. (다 갠플하는 놈들이라 팀플이 쉽지않다...)

 

이렇게 갠플하는 녀석들을 하나로 그룹화하여 관리할 수 있는 시스템이 있는데, 그게 바로 쿠버네티스이다.

이 내용은 다음 포스팅에서 다루도록 하자.

 

 

 

이 글을 읽고 조금이라도 도커와 컨테이너의 이해에 도움이 됐으면 좋겠다.