본문 바로가기

Tech/Docker

Docker의 구성 요소 : 이미지, 컨테이너, 레이어

도커의 필요성

도커를 처음 공부했을 때는 “어렵기만 하다”생각했습니다. 내가 왜 이 어려운 내용을 배우고 있는 건지, 그 어떤 목적성과 필요성이 없었기 때문이죠. 이처럼, 무작정 도커를 공부하려 하면 이해 안 가는 게 투성이 일 것입니다. 어렵기도 하고요. 하지만, 도커가 필요한 순간을 몇 번 마주치고 그 맥락을 인지하게 되면, 도커만큼 재밌고 또 잘 다루고 싶은 툴은 없을 거라 생각합니다. (깃도 비슷한 맥락이겠네요)

Docker logo

그러한 관점에서, 개인적으로 도커의 필요성을 느낀 순간을 공유하고자 합니다.
작년, 딥러닝 관련 외주 프로젝트를 진행할 당시였습니다. 마감 기한을 2일 남겨놓고 필요한 모든 코드와 테스트를 완료해 놓았습니다. 최종 데모를 위해 다른 컴퓨터에 실행만 시키면 되는 상황이었기에 매우 여유로웠습니다. 하지만, 다른 컴퓨터에서 프로젝트를 위한 가상환경을 구축하는 것부터가 난관이었습니다. 마감 기한도 얼마 안 남았는데, 고작 환경 세팅 때문에 조바심을 느끼며 발을 동동 구르고 있었죠.. 그 순간, ‘그냥 잘 실행됐던 기존 컴퓨터 자체를 들고 올걸’이라는 바보 같지만 확실한 방법을 떠올리기도 했습니다. 그런데 그렇게 할 수 있는 방법이 있더라고요. 컴퓨터 자체가 아닌, 컨테이너의 개념으로요. 그때부터 컨테이너에 대한 개념과 도커에 관심을 가지게 되었습니다.

 

도커는 컨테이너를 기반으로 한 가상화 플랫폼 입니다. 컨테이너는 특정 애플리케이션을 구동시키는데 필요한 모든것을 포함하게 되죠. 이 내부에는 운영체제, 코드, 시스템 도구, 라이브러리 등 필요한 모든것이 다 구비되어있다 보시면 됩니다. 이 덕분에 컨테이너 하나만 있으면, 실행하는 서버 환경과 개발 환경에 영향받지 않고 동일하게 실행되는것을 보장해 주게 됩니다. 서버 관리와 개발 방식이 완전히 편해지고 빨라지게 되었죠. 만약 위의 제 사례에서 해당 프로젝트를 컨테이너로 구성하는 방법만 알았더라면, 저렇게 다른 컴퓨터에서 데모하는데 고생할 필요가 없었겠습니다. 이러한 필요성을 인지한 채, 도커를 구성하는 이미지와 컨테이너 그리고 레이어에 대한 개념을 살펴보도록 하겠습니다.

도커의 이미지

도커의 이미지는, 애플리 케이션을 실행하는데 필요한 모든 설치파일과 설정값들을 가진 파일입니다. 개발을 공부하기 전까진, 애플리케이션을 사용자들이 사용할 수 있도록 하기 위해선(이를 배포라고 하겠습니다), 특정 코드 파일만 있으면 된다고 생각했습니다. 그 코드 파일을 어디론가? 전송하면 멋진 애플리케이션을 컴퓨터로, 또 모바일로 사용할 수 있게 될 줄 알았죠. 하지만 배포는 그리 쉽지 않은 일이었고, 이것저것 따져야 할게 많았습니다.

  • 해당 코드를 구동할 OS는 뭘로 할 것이며,
  • 필요한 소스코드들의 버전은 어떻게 관리할 것이며,
  • 100명이 접속할 때, 10000명이 접속할때 서비스의 확장성은 어떻게 할 것이며,
  • 등등..

하나의 애플리케이션을 실행시키기 위해 필요한 모든 것을 하나하나 신경 써가며 배포하기란 좀 처럼 쉽지 않습니다. 도커의 이미지는 이러한 관점에서 힘을 발휘합니다. 위의 여러 사사건건들을 하나의 객체로 포장을 해버리는 겁니다. 마치 떡볶이를 만들기 위해 양파, 쪽파, 떡, 소스 등등 하나하나 따져 가면서 장을 보는 것보단, 밀키트 하나를 사버리는 게 훨씬 더 편한 것처럼 말이죠. 도커의 이미지는 이 밀키트 같은 역할을 수행합니다. 밀키트가 있다면 사막 한가운데서도 불만 있다면 똑같은 맛의 떡볶이를 만들어 먹을 수 있는 것처럼, 이 도커 이미지 하나만 있으면 도커엔진이 설치된 모든 컴퓨터에서 우리가 구현한 애플리케이션을 바로 실행할 수 있습니다. 아래 그림처럼 말이죠.

도커 이미지화

도커의 컨테이너

앞서 도커의 이미지에 대해서 알아보았습니다. 하지만, 이미지 그 자체로는 아무런 일이 발생하지 않습니다. 이 이미지를 도커엔진 위에서 실행시켜주면, 그때 비로소 컨테이너화 되며 우리가 원했던 동작을 독립된 공간 속에서 수행하게 됩니다. 이처럼 컨테이너는 이미지를 실행한 상태를 뜻합니다. 하나의 도커 이미지로 여러개의 도커 컨테이너를 실행시킬 수 있으며, 각 컨테이너는 독립된 공간속에서 구동되기에 다른 컨테이너에게 영향을 주지 않습니다.

도커 컨테이너화

이러한 컨테이너 개념이 없었더라면, pytorch를 사용하기 위한 os를 설치하고, 코드를 읽기 위해 python을 설치하고, pytorch를 또 설치해야만 했습니다. 뿐만 아니라, pytorch를 설치할 때 os의 종류는 무엇인지, python은 버전에 맞는지 여러 조건들을 고려했어야 했죠. 하지만 컨테이너를 활용하게 되면 저희가 해야 할 일은 단순히 pytorch의 이미지를 가져와 컨테이너로 실행(RUN)만 하면 됩니다. 이 이미지 안에 os, python과 관련된 모든 버전들이 서로 짜 맞춰져 있기에, 훨씬 더 간단해진 것이죠. 이는 실행 환경 관점에서의 장점일 뿐이며, 실제 서비스를 배포하는 관점에서는 확장성과, 배포 관리 등 다양한 이점들이 있습니다.

도커의 레이어

위에서 도커의 이미지와 컨테이너의 장점에 대해서 알아봤습니다. 여기서 도커 이미지에 대해 좀 더 자세히 알아보면, 이미지는 레이어라는 단위로 구성되어 있습니다. 별거 아닌 이야기처럼 보이지만, 이 덕분에 우리는 용량이 큰 이미지를 아주 효율적으로 보관하고 관리할 수 있게 됩니다. 만약 ubuntu를 사용하기 위해, ubuntu 이미지를 설치해 본다고 가정해 보겠습니다. 해당 이미지에는 ubuntu를 실행하기 위한 모든 설치파일과 설정값을 가지고 있기에, 수백 MB 정도로 용량이 꽤 클 것입니다. 뭐 수백 MB야 충분히 감당할 수 있는 용량처럼 보입니다. 하지만, ubuntu를 기반으로 한 다른 이미지들을 불러올 때 문제가 발생합니다. 매번 수백 MB의 ubuntu 이미지를 추가로 불러오는 상황이 발생하는 거죠. 이는 매우 비효율적입니다. 이를 해결하고자, 도커는 이미지를 layer라는 단위로 구성해놓고 해당 레이어를 다른 이미지들끼리 공유할 수 있도록 설계해 놓았습니다. 아래 이미지를 보면 좀 더 이해하기 쉽습니다.

도커의 레이어 구성

위 사진에서 (B)와 같이, ubuntu 기반의 python 이미지를 불러올 때는, 기존에 ubuntu를 위한 레이어를 가지고 있는 상태이기에, 이를 제외하고 추가적인 레이어만을 설치하게 됩니다. 그리고는 기존에 있던 ubuntu 레이어를 공유해 python의 컨테이너를 구동시킬 수 있게 되죠. 더 나아가 (C)와 같이, ubuntu & python 기반의 pytorch라는 이미지를 불러오기 위해서는 같은 맥락으로 기존에 있던 레이어를 공유하고, 필요한 레이어만을 가져올 수 있게 되겠죠. 이러한 레이어 방식은 이미지를 설치하고 실행할 때, 우리의 컴퓨터 리소스를 효율적으로 사용할 수 있게 해 줍니다.

 

 

Reference