백엔드 세미나[1] - Docker의 소개

다양성은 개발의 자유라는 측면에서는 충분히 좋은 일이지만, 때때로는 개발자를 귀찮게 만들기도 합니다. 갈수록 빠르게 발전하는 소프트웨어 세상 속에서, 개발자들은 점점 서버의 관리에 한계와 싫증을 느끼기 시작했습니다. 이런 상황에 혜성같이 등장한 기술이 바로 Docker입니다.

2018. 03. 05. #development #docker

서버의 운영 환경은 갈수록 복잡해지고 있습니다. 세상에는 수 백 가지가 넘는 리눅스 배포판이 존재하며, 위키피디아에 등록되어있는 프로그래밍 언어의 종류만 해도 1천여 개에 달합니다. 이들 프로그래밍 언어로 구현되어있는 각종 DB, 웹 서버 등의 애플리케이션 종류는 더욱 다양하구요.

물리 장비를 구입하여 OS를 셋팅하고, 프로그램을 실행하기 위한 바이너리와 각종 의존성을 설치하고, 그 위의 애플리케이션을 올린 뒤 유저에게 서비스를 제공하기까지의 과정은 결코 간단하지 않습니다. 이런 과정에 설치하는 프로그램 중 하나라도 버전이 달라지면 어제까지 잘 써먹던 설치 과정이 오늘은 에러를 내뿜는 참사가 벌어지기도 합니다.

다양성은 개발의 자유라는 측면에서는 충분히 좋은 일이지만, 때때로는 개발자를 귀찮게 만들기도 합니다. 갈수록 빠르게 발전하는 소프트웨어 세상 속에서, 개발자들은 점점 서버의 관리에 한계와 싫증을 느끼기 시작했습니다. 이런 상황에 혜성같이 등장한 기술이 바로 Docker입니다.

Docker 로고

Docker란?

Docker는 애플리케이션을 컨테이너로 규격화하여 빌드, 배포, 실행하는 소프트웨어입니다.

여기서의 컨테이너는, 흔히 떠오르는 네모난 그 컨테이너와 비슷한 개념입니다. 운송업에서의 컨테이너는 물건을 효율적으로 옮기기 위해 표준화, 규격화한 상자를 말합니다. 비슷한 의미로, Docker에서의 컨테이너는 애플리케이션을 효율적으로 배포, 서빙하기 위해 가상화, 규격화시켜놓은 것을 일컫습니다.

Python Flask 앱을 서빙하는 환경의 예시를 들어보겠습니다. Docker가 없던 시절에는 우선 서버 장비에 OS를 올린 뒤, 각종 Python 바이너리 및 의존성을 설치합니다. 이후 서버에 애플리케이션 소스 코드를 옮기고 프로세스 매니저를 통해 서비스의 형태로 소스 코드를 실행해야합니다. 이런 과정은 번거로울 뿐만 아니라, 글머리에 언급한 것처럼 OS 버전이나 라이브러리 버전 등이 조금이라도 틀어져 실행이 안되면 그 원인을 찾아 삽질을 해야하는 문제도 빈번하게 일어납니다.

반면 Docker를 사용하면, 서버 OS에 Docker Engine을 설치한 후, Python 바이너리와 라이브러리, 애플리케이션 코드가 모두 포함된 하나의 컨테이너만 실행시키면 됩니다. 후술하겠지만 모든 의존성 정보가 컨테이너 이미지 안에 포함되기 때문에 더 이상 고민할 거리가 없습니다.

VM과 Docker의 구성 비교

비슷한 개념으로는 기존의 가상 머신(VM, Virtual Machine)을 들 수 있습니다. VM은 운영 체제 자체를 가상화하는 기술입니다. 호스트 OS(=장비에 설치되어있는 OS) 위에 게스트 OS를 얹고, 그 안에 각종 바이너리나 라이브러리를 설치하는 형태를 가지고 있습니다. 하지만 '운영체제를 하나 얹는다'는 말에서 느낄 수 있듯이, 이러한 과정은 굉장히 무겁고 느립니다.

이에 반해 Docker는 프로세스를 격리하는 방법을 사용합니다. 호스트 OS에 Docker를 설치하고, 모든 서비스는 Docker 위에 컨테이너의 형태로 동작하게 됩니다. 호스트 OS 입장에서는 하나의 컨테이너는 곧 하나의 프로세스이기 때문에 VM에 비해 부하가 훨씬 적은 이점이 있습니다.

이미지와 컨테이너

이미지는 컨테이너를 실행하기 위한 모든 정보를 담고 있는 파일입니다. 예를 들어 Python Flask 웹 서비스의 이미지에는:

  • Python을 실행하기 위한 바이너리
  • Flask 등의 라이브러리
  • 애플리케이션 스크립트
  • 서버를 시작하는 명령어 등의 설정

등이 모두 포함되어있습니다.

이미지는 Dockerfile이라는 텍스트 파일을 통해 생성됩니다. 아래는 Python Flask 애플리케이션의 Dockerfile 예제입니다.

FROM python:3.6

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

COPY ./requirements.txt ./requirements.txt
RUN pip install -r requirements.txt

COPY . .

ENV PYTHONUNBUFFERED 1
ENV PYTHONPATH /usr/src/app
ENV FLASK_APP app
CMD [ "flask", "run", "-h", "0.0.0.0" ]

위의 Dockerfile을 해석하자면 다음과 같습니다.

  • FROM python:3.6
    새로운 이미지는 Python 3.6가 설치되어있는 이미지를 바탕으로 생성하게 됩니다.
  • WORKDIR /usr/src/app
    모든 명령어는 /usr/src/app 디렉토리에서 실행합니다.
  • COPY ./requirements.txt ./requirements.txt 및 다음 줄
    호스트에서 requirements.txt 파일을 복사한 뒤, pip로 필요한 의존성을 설치합니다.
  • COPY . .
    모든 애플리케이션 파일을 복사합니다.
  • ENV ~~~
    애플리케이션을 실행하기 위한 각종 환경 변수를 설정합니다.
  • CMD [ "flask", "run", "-h", "0.0.0.0" ]
    애플리케이션을 실행합니다.

보시다시피 이 파일 하나에 Flask 애플리케이션을 설치, 배포하기 위한 모든 과정이 기술되어있습니다. 따라서 기존과 같은 복잡한 의존성 관리나 빌드 과정을 전혀 거칠 필요가 없게됩니다.

다음 포스트에서는 Docker를 설치하고, 예제 프로젝트의 이미지를 빌드하여 컨테이너로 띄우는 방법에 대해 소개하도록 하겠습니다.

크리에이티브 커먼즈 라이선스

이 저작물은 크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.

© 2011 - 2020 Do Hoerin, LYnLab