도커에 대한 얕은 지식

J-USER·2022년 2월 16일
0

DevOps

목록 보기
3/10
post-thumbnail

도커는 직접 써보지는 않았지만 한번쯤은 들어본 용어일 것이다. + 대충 컨테이너 형태의 두루뭉술한 가상 서버?

그래서 도커가 뭔데? 라고 하면 사실 정확히 설명하지 못하기 때문에 이번 기회에 정리하며 넘어가도록 하겠슴다..( 이후 반말..)

가상화

가상화는 하나의 서버의 자원이 100% 사용하지 않는다는 문제점을 해결하고자 다양한 가상화 기법이 탄생하게 되었고 가상화의 종류 대표적으로 자바의 JVM, VPN 등이 있다.

🙋‍♂️그럼 서버를 가상화하면서 얻을 수 있는 이점은 무엇이 있을까?
바로 컴퓨팅 자원을 여러 개로 분할하여 최대한 사용하여 그 효율성을 극대화할 수 있다는 점이다.

서버 가상화

서버 가상화에서 가장 핵심이 되는 것이 바로 하이퍼바이저이다. 우리가 사용하고 있는 윈도우, 리눅스, mac os 등은 기본적으로 컴퓨터에 직접 설치되고 하드웨어와 프로그램 및 스케줄링과 같은 대부분의 중요 작업은 운영체제의 커널에서 수행된다. 즉, 우리가 어떤 운영체제를 사용하는지에 따라서 커널의 역할을 비슷하지만 그 동작 방식이 다르다고 할 수 있으며, 이에 따라 다른 운영체제와 호환할 수 있는 애플리케이션을 제작하기 위해서는 응용 프로그래머가 이에 맞춰서 별도로 개발해야 하는 수고스러움이 존재한다.

위 그림을 보자면 기존에는 3가지의 애플리케이션을 실행하기 위해서는 3개의 서버가 별도로 존재하는 것을 알 수 있다. 하지만 가상화를 사용하면 하나의 하드웨어 즉 서버에 3가지의 운영체제와 각각의 애플리케이션이 동작하는 모습을 볼 수 있다.

🙋‍♂️ 우리가 사용하는 애플리케이션이 하나의 컴퓨팅에서 여러 개 동작하듯이 서버 하나에서 여러 개의 애플리케이션을 동작하면 되지 않을까?
🤖 가..가능...근데 서버의 장애가 발생하거나, 서비스의 자원이 부족하면 어떡하실..?
🙋‍♂️ 크...큰일남

가상화를 사용하면 사용하는 컴퓨팅 자원 즉 하드웨어는 동일하지만 격리된 공간에서 독립적으로 구성되기 때문에 특정 서버에 문제가 발생하더라도 다른 서버에 문제가 생기지 않고, 서버 구입 비용을 획기적으로 줄일 수 있으며 백업과 복구의 관리가 용의 해진다는 장점이 있다.

서버 가상화의 종류

종류의 구분에 앞서 일반적으로 알아야 하는 내용부터 빠르게 보고가자.
일반적으로 운영체제를 설치하면 설치된 운영체제가 커널을 통해 하드웨어를 제어하게 되는데, 하이퍼바이저의 자체에서는 하드웨어를 제어할 수 없기 때문에 Dom0 (Domain 0)라는 관리 머신이 함께 동작한다.Dom0는 하드웨어에 접근할 수 있는 특별한 권한을 가지고 있고 디바이스 드라이버 역시 포함되어 있다.

즉 하이퍼바이저에서는 Dom0가 없이는 동작할 수 없다. 따라서 Dom0가 얼마나 많은 역할을 담당하는지에 따라 가상화의 종류가 결정됨.(사진 2)

이와 별개로 DomU (Domain U)는 하드웨어에 직접 접근할 수 있는 권한이 없는 비특권 도메인으로 가상 디스크나 네트워크 접근에 대한 부분을 관리한다. 만약 DomU가 실질적으로 물리 하드웨어에 동작을 원한다면 반드시 Dom0와 통신해야 한다. (사진 1)

사진1
사진2

🙋‍♂️ 그래서 타입 1,2 차이가 뭔데???

타입 1 hypervisor (native / bare-metal / 반가상화).

hypervisor를 bare-metal로 부르는 이유는 "어떤 소프트웨어도 담겨있지 않은 하드웨어"라는 의미

즉 하드웨어 위에 운영체제가 설치되지 않고 하이퍼바이저가 하드웨어를 직접 컨트롤하는 것을 말한다.

단일 하이퍼바이저가 하드웨어를 종합적으로 관리하기 때문에 오버헤드가 적고 리소스 관리에 유연하다는 장점이 있다.

하지만 운영체제 즉 커널이 정상적으로 동작하기 위해서는 system call이 아닌 hyper call를 통해 요청을 처리해야 한다. 이는 위에서 설명한 하이퍼바이저의 Dom0와 DomU에 명령을 실행하기 위한 별도의 명령어가 필요하다는 뜻이기 때문에 커널을 수정하지 않는 이상 Type 1 hypervisor 방식을 사용할 수 없다.

리눅스나 유닉스의 경우 오픈소스 형태이기 때문에 커널을 수정하는 것이 쉬웠으나 윈도우의 경우 커널을 공개하지 않기 때문에 원칙적으로라면 실행하지 못하는 게 정상이다. 하지만 XEN과 마이크로소프트가 Type 1 hypervisor를 지원하도록 커널을 수정하고 해당 프로그램을 제공하기 때문에 사용하는데 지장은 없다.

종류에는 VMware ESX and ESXi, Microsoft Hyper-V, Citrix XenServer, Oracle VM...

타입 2 hypervisor (hosted / Full virtualization / 전가상화)

Type 2 hypervisor의 경우 하드웨어 위에 일반적인 운영체제가 동작하고 있고 그 위에 하이퍼바이저를 설치하고, 모든 하드웨어 자원을 가상화하여 운영하는 방식이다.

모든 자원을 가상화하고 이를 각각의 하이퍼바지어저가 전달해주는 방식이기 때문에 Type 1 hypervisor 보다 상대적으로 오버헤드가 크게 나타날 수밖에 없지만! 게스트 OS의 수정이 전혀 필요하지 않다. 또한 기존 운영체제를 사용하면서 가상 머신을 운영할 수 있다는 장점이 있기 때문에 우리가 가장 흔하게 접근할 수 있는 방식이다.

컨테이너

도커의 핵심적인 개념으로 학습할 컨테이너도 운송용 컨테이너와 다르지 않다. 만약 본인이 Go로 작성된 어떠한 애플리케이션을 만들고 있다고 가정한다. 당연히 본인 컴퓨터에서는 관련 환경설정이 되어 있기 때문에 개발하고 운영하는데 아무런 지장이 없겠지만 다른 이가 내가 만든 애플리케이션을 이어서 개발하거나 실행하고자 한다면본인과 다른 컴퓨팅 한경 때문에 정상적으로 실행이 되지 않을 것이고 이를 실행하기 위한 별도의 세팅 과정이 필요할 것이다.
만약 이렇게 만들어진 애플리케이션이 다양한 라이브러리와 의존성을 가지고 있다면, 서로 다른 개발자 컴퓨터 사이의 개발환경 세팅에 따라 오류가 발생할 수 있고 이를 해결하기 위한 엄청난 노력이 필요할 것이다.
이를 효과적으로 해결할 수 있는 방법이 바로 컨테이너이다.

도커는 운영체제 수준에서 가상화하는 방식을 채택하기 때문에 별도의 하드웨어가 필요하지 않고 본인이 실행하고 있는 운영체제 커널을 공유해서 컨테이너를 실행하게 되며 하이퍼바이저를 사용하는 가상화 기술 대비 매우 빠른 속도로 실행되는 특징을 가지고 있다.

약간의 오버헤드를 가질 수 있지만 하이퍼바이저에서 발생하는 오버헤드에 비하면 미미한 수준이며, 하나의 운영체제에서 다수의 프로세스가 실행되고 있는 것과 같이 다수의 컨테이너를 실행하는 것도 가능하다.

이렇게 격리된 컨테이너는 호스트의 환경이 아닌 독자적인 실행환경을 가지고 있기 때문에 다른 운영체제 혹은 다른 개발 환경에서도 독립적으로 실행이 가능하고, 상태를 가지지 않는 특성 때문에 다른 컨테이너에게 영향을 주지 않으면서 파일 혹은 이미지 형식으로 쉽게 공유할 수 있다.

리눅스 컨테이너 LXC : 컨테이너 기능을 제공하기 위한 인터페이스

이러한 컨테이너의 기능을 잘 이해하기 위해서는 리눅스 컨테이너의 동작을 이해할 필요가 있다.

리눅스 컨테이너 LXC가 운영체제 수준 가상화이기 때문에 namespce, Apparmor와 SELinux, Seccomp, chroot, CGroups과 같은 커널 기능을 사용하는데, 여기서 가장 중요하게 살펴봐야 할 것이 namespace와 CGroups이다.

namespace

하이퍼바이저에서는 게스트 머신이 독립적인 공간을 제공하고 서로 충돌이 나지 않도록 관리하는 기능을 가지고 있는데, 리눅스 커널에는 namespace가 동일한 역할을 담당한다. 리눅스 커널에는 8가지의 namespace가 제공되고 있는데 살펴보면 다음과 같다.

mnt (파일 시스템 마운트): 호스트 파일 시스템에 구애받지 않고 독립적으로 파일 시스템을 마운트 하거나 언마운트 가능
pid (프로세스): 독립적인 프로세스 공간을 할당
net (네트워크): namespace 간에 network 충돌 방지 (중복 포트 바인딩 등)
ipc (SystemV IPC): 프로세스 간의 독립적인 통신 통로 할당
uts (hostname): 독립적인 hostname 할당
user (UID): 독립적인 사용자 할당
Time Namespace : 독립적인 시스템 시간 할당
Control group (cgroup) Namespace : 자신이 속한 cgroup의 그룹의 상대적인 경로 제공

CGroups

커널에서 사용되는 자원에 대한 제어를 가능하게 하는 기능을 말한다. 이 기능 없이는 각각의 컨테이너에서 별도의 자원을 사용할 수 없기 때문에 실행 자체가 불가능하다. CGroups에서는 다음과 같은 자원을 제어한다.

도커

docker image

  • 이미지는 컨테이너 실행에 필요한 파일과 설정값 등을 포함하고 있는 것으로 상태 값을 가지지 않고 변하지 않는다.

  • 컨테이너는 이미지를 실행한 상태라고 볼 수 있고, 추가되고 변하는 값은 컨테이너에 저장된다.

  • 같은 이미지를 여러 개의 컨테이너에서 생성할 수 있고 컨테이너의 상태가 변경되거나, 삭제되어도 이미지는 변하지 않고 그대로 남아있다.

  • Ubuntu이미지는 ubuntu를 실행하기 위한 모든 파일을 가지고 있고 MySQL이미지는 debian을 기반으로 MySQL을 실행하는데 필요한 파일과 실행 명령어, 포트 정보 등을 가지고 있습니다. 좀 더 복잡한 예로 Gitlab 이미지는 centos를 기반으로 ruby, go, database, redis, gitlab source, nginx 등을 가지고 있다.

  • 컨테이너를 실행하기 위한 모든 정보를 가지고 있기 때문에 의존성 파일을 컴파일하고 이것저것 설치할 필요성이 사라진다.

  • 새로운 서버가 추가되면 미리 만들어 놓은 이미지를 다운로드하고 컨테이너를 생성하면 된다.

Docker에서 이미지는 컨테이너를 실행하기 위한 모든 정보를 가지고 있기 때문에 용량이 수백MB 이상인 경우가 많다. 처음 이미지를 pull 하게 될 경우 전체 이미지를 다운로드하기 위해 시간이 걸리지만 기존 이미지에 수정사항이 생겼을 경우 이를 위해 이미지 전체를 받는 경우는 비효율적이기 때문에 유니온 파일 시스템을 이용하여 여러 개의 레이어를 하나의 파일 시스템으로 사용할 수 있게 한다.

예를 들어 ubuntu 이미지가 A + B + C의 집합이라면, ubuntu 이미지를 베이스로 만든 nginx 이미지는 A + B + C + nginx가 된다. webapp 이미지를 nginx 이미지 기반으로 만들었다면 예상대로 A + B + C + nginx + source 레이어로 구성된다. webapp 소스를 수정하면 A, B, C, nginx 레이어를 제외한 새로운 source(v2) 레이어만 다운로드하면 되기 때문에 굉장히 효율적으로 이미지를 관리할 수 있다!

docker pull 명령어를 실행할 때, 버전을 지정하지 않으면 가장 최신 버전으로 이미지를 받는다고 이야기했다. Docker에서는 이미지에 태그를 달아서 버전을 관리할 수 있는데 구조는 다음과 같다.

출처

profile
호기심많은 개발자

0개의 댓글