Why Should We Dockerize?

바야흐로(?) 커먼컴퓨터 인턴 과제에서 Docker를 접하고 배우기 시작하였다. 이전에는 Docker에 대해 말만 들어봤고, 심지어 프로젝트를 배포까지 해본 적도 없었다.

그런데 한 번 써보니 너무 편한 것!!
기본적으로 가상환경을 편리하게 구축하고, 그 후 배포도 할 수 있다. Docker Hub에 내 도커 이미지 올려두면 다른 사람과도 공유할 수 있다.

나도 이전에 몇 개 올려둔 게 있는데, 주로 거의 Github에 크기 제한으로 인해 push되지 않는 데이터나 학습된 NLP 모델을 올려둔 경우가 많다.

그거 외에는 KoNLP와 jupyter를 사용할 수 있는 아나콘다 가상환경도 하나 업로드했던 거 같다. 쓰실 분은 언제든 이미지 다운로드 받으셔서 쓰시길..

오늘은 그러한 기본적인 역할에 더 나아가서 왓챠에서 어떻게 도커 컨테이너를 추천서비스에 활용하고 있는가에 감명받아서 거기에 대한 내용을 조금만 기록해두고자 한다.
※ 약간의 운영체제(OS) 배경 지식이 있으면 좋다.


가상머신보다는 컨테이너

컨테이너는 어플리케이션 실행에 필요한 모든 환경(운영체제, 실행 파일, 환경 변수, 라이브러리, 컴파일러 버젼 등)을 패키징하여 호스트와 분리된 환경을 구축하는 기술이다.
컨테이너는 운영체제(OS)를 가상화하여 호스트와 커널을 공유하기 때문에 호스트OS 위에 여러 게스트 OS를 구동하는 가상머신(VM)에 비해 가볍고 빠르게 실행할 수 있다. 또한 어플리케이션 실행에 필요한 최소한의 환경을 구성할 수 있어 리소스 낭비 없이 효율적인 운영이 가능하다.

이외에도 다양한 장점이 있다.

  • 동일한 실행 환경 제공 : 위에서 언급했듯 내가 만든 이미지를 다른 사람과 공유할 수 있다.
  • 소스코드와 실행 환경의 통합 : Dockerfile Code는 세상 간단하기 때문에 코드만 보면 어떤 라이브러리, 이미지 등을 썼는지 바로 파악이 가능하다.
    예는 위에서 언급한 konlpy-jupyter 사용 환경에 쓰인 Dockerfile 내용이다.
FROM continuumio/anaconda3
RUN /opt/conda/bin/conda install jupyter -y
RUN mkdir /opt/notebooks
RUN mkdir -p /usr/share/man/man1
RUN apt-get update --fix-missing && apt-get install -y default-jre
ENV JAVA_HOME /usr/lib/jvm/java-1.7-openjdk/jre
RUN pip install konlpy
  • 환경 구성에 필요한 비용 감소: 이미지 빌드하면 이미지의 레이어마다 캐싱되어서 변경사항만 반영되는 장점이 있다. 이외에도 이전의 이미지에 레이어를 한층 더 쌓아서 커스터마이징하기에도 좋다.

대신 한 가지 아쉬운 점은 도커에서 더 나아가 도커의 컨테이너를 자동으로 관리(오케스트레이션)해주는 k8s(Kubernetes)를 다루어본 적은 없다..ㅠ

k8s는 구글에서 만든 오픈소스 컨테이너 오케스트레이션 도구로서 각 오브젝트에 대한 명세를 통해 전반적인 시스템을 구성할 수 있다. k8s를 활용하면 배포 스케줄링은 어떻게 할지, 배포 버전 관리는 어떻게 할지, 장애가 발생했을 때 어떻게 복구할지, 트래픽 분산을 위한 오토 스케일링은 어덯게 처리할지와 같은 다양한 문제를 쉽게 해결할 수 있다.

k8s의 HPA는 다음 순서와 같이 작동한다.
1. 메트릭 서버에서 주기적으로 메트릭 수집.
2. 수집된 내용을 토대로 오토 스케일링 여부 판단.
3. 변경이 필요한 경우 kube-scheduler에 의해 Scale-in/out 요청
4. 실제 Pod 조정


기존에는 Amazon S3로부터 추천 데이터를 다운로드 받아 메모리에 로드한 후 추천에 활용했다. 추천 데이터는 서비스를 새로 시작하거나 워커에서 주기적으로 갱신될 때마다 다운로드했는데, 이러한 방식은 추천 데이터의 크기가 커질수록 파일 입출력에 대한 부담이 생겼고, 특히 서비스가 새로 시작될 때 추천 데이터를 다운로드 받는 시간이 존재하여 급작스러운 Scale-out 상황에 예민하게 반응하지 못하는 문제 발생한다.

실제로도 Amazon은 아니지만 Firebase에서 Model Serving 해본 결과 데이터가 크면 리스너가 해당 변경 사항을 인지하고 그에 따른 결과를 반영하는 데에는 시간이 꽤 소요되었다.

그래서 왓챠 ML팀에서는 이러한 문제점을 해결하기 위해서 K8S Persistent Volume과 네트워크 스토리지인 AWS Elastic File System을 활용하였다고 한다.(나는 이렇게 큰 서비스를 제공해볼 필요가 전혀 없었다.)
PV는 클러스터 내 각 컨테이너의 볼륨 관리를 추상적인 레벨에서 손쉽게 관리할 수 있도록 K8S에서 제공하는 오브젝트이다. PV에 EFS를 등록함으로써, 쉽게 클러스터 내 여러 Pod에 EFS를 볼륨 마운트할 수 있게 되었다고 한다.


결국 모든 Pod들은 위 그림과 같이 동일한 EFS를 볼륨 마운트하여 추천 데이터를 공유할 수 있게 되었고, 이로 인해 불필요한 파일 입출력을 하지 않는 것뿐 아니라 서비스 부트스트랩 시간이 줄어들어 급작스런 트래픽 증가에도 대응할 수 있게 되었다.

이외에도 Node의 유휴 리소스를 관리하여 새로운 컨테이너가 적절한 Node에 배치할 수 있도록 Pod와 Node를 스케줄링하거나 컨테이너 장애 발생 시에 이를 감지하고 빠르게 복구할 수 있도록 도와주는 등 K8S를 쓰면 서비스 운영에 많은 부분이 자동적으로 돌아간다!


상당히 재밌는 부분이 많아 직접 K8S와 Amazon을 돌려보고 싶은데, 개인적으로는 힘들고 회사 들어가서 꼭 써보고 익히고 싶은 기술이다ㅎㅎ물론 이거를 무조건적으로 신뢰하는 것도..좋지는 않은 거 같다. 최근에 왓챠에서 로드밸런싱 오류로 인한 과금 문제가 논란이 되었기 때문이다. (A 사용자의 네트워크 사용량이 B에게 고지되어 결제된 사건ㄷㄷ)

그래도 왓챠 팀의 고민의 흔적들이 느껴져서 좋은 포스트였다.!

좋은 웹페이지 즐겨찾기