행복한 아빠

파이썬 Docker 이미지 관리하기 본문

Docker

파이썬 Docker 이미지 관리하기

행복한아빠 2016. 9. 22. 19:56

사실 이 문제 때문에 도커 관련 포스트 정리하기로 마음 먹었습니다.


도커로 우리가 만든 파이썬 기반 애플리케이션을 배포하기로 했는데 파이썬 이미지 너무 큽니다. 뭐 파이썬 도커 이미지 중 작은 이미지도 있지만 표준 파이썬 이미지에 올리려고 하니 700MB가 넘습니다.


나의 첫번째 Dockerfile

 "Docker로 파이썬 배포 운영하기" 하기에서 언급했듯이 우리의 파이썬 애플리케이션 서버는 좀 많은 소프트웨어가 설치됩니다. 다음은 우리의 초기버전 Dockerfile입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
FROM python:3-onbuild
MAINTAINER dykim <dykim@cityholic.com>
 
RUN apt-get update
RUN apt-get install -y supervisor
ADD ./conf/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
 
# Nginx
RUN apt-get install -y nginx
ADD ./conf/hello-web /etc/nginx/sites-available/hello-web
RUN ln -/etc/nginx/sites-available/hello-web /etc/nginx/sites-enabled/
RUN rm /etc/nginx/sites-enabled/default
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
RUN chown -R www-data:www-data /var/lib/nginx
 
# uWSGI
RUN pip install uwsgi
ADD ./conf/hello.ini /etc/uwsgi/sites/hello.ini
 
CMD ["/usr/bin/supervisord"]
 
EXPOSE 80
EXPOSE 443
cs


도커파일을 간단히 라인별로 설명하자면


1 라인:

python:3-onbuild로 이미지를 만듭니다. 이 버전은 빌드 시 자동으로 requirements.txt의 패키지를 설치하고 현재 디렉토리의 모든 소스를 이미지로 복사합니다. (이런 개발을 위해 현재 디렉토리에 만든 venv도 복사하는군...)


3 ~ 6 라인:

우리는 한 컨테이너에 nginx와 uwsgi 두 개의 프로세스를 띄울 예정이라 supervisord(프로세스 관리)를 설치합니다.


9 ~ 14 라인:

Nginx 설치와 필요한 설정을 복사합니다.


17 ~ 18 라인:

uWSGI 설치와 필요한 설정을 복사합니다.


20 ~ 23 라인:

프로세스를 구동하고 포트를 엽니다.



Docker 이미지 크기

이미지 버번관리를 위해 버전 붙인 것 하나과 latest 버전를 함께 만듭니다.

$ docker build -t 10.3.0.38:5000/hello-web -t 10.3.0.38:5000/hello-web:1 .

이렇게 만들어진 이미지 크기가 700MB가 넘습니다. 첫번째 이미지를 만들고 Repository에 push 합니다.
한참걸립니다. 운영서버에 pull하고 run 합니다. 한참 걸립니다. 첫번째라 이해하지요.


소스 몇 줄이 변경되어 버전하나 올리고 다시 배포하려고 합니다.

$ docker build -t 10.3.0.38:5000/hello-web -t 10.3.0.38:5000/hello-web:2 .

아니 이미지에 소스카피하고 소프트웨어 설치하고 ... 저 짓을 또 합니다. 한참 걸립니다. Repository에 push 합니다. 한참걸립니다. 운영서버에 push 합니다. 네... 한참 걸립니다.

원인

매번 저 도커파일로 배포하면 python:3-onbuild 기반 이미지를 제외하고 그 후의 작업들(소프트웨어 설치, 나의 소스파일들)은 새로운 이미지 레이어로 취급합니다. 즉 도커는 새로운 이미지로 판단하기에 Repository에 새로 다 push하고 서버들은 새로 다 pull 합니다.


위의 그림에서 보듯 기반 이미지를 제외하고는 이미지 아이디가 다른 새로운 이미지 레이어로 쌓여 두번째 버전은 이미 있는 1번 레이어를 제외한 7~11 버전의 이미지 레이어를 push하거나 pull합니다.

(좀 간략한 이미지 구조입니다. "docker history 이미지이름"을 이용하면 이미지 레이어 구조를 볼 수 있습니다. 좀 더 자세한 사항은 https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/ )



해결책

일반적으로 변경사항은 일부 소스에서 일어납니다. 시스템의 변경사항이 거의 없는 부분과 많이 발생하는 부분으로 나누어 이미지를 관리합니다.
첫번째 빌드는 위와 동일하게 이미지를 만들고 그 이후에는 이미 만들어진 마지막 이미지를 기반으로 변경된 소스 레이어만 추가하는 방법입니다.


그러면 Repository나 docker 서버들은 마지막 이미지는 이미 있기에 변경된 이미지 레이어만 가지고 와서 이미지를 완성하고 구동합니다.


우리가 사용할 기반 이미지 도커파일 (Dockerfile)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
FROM python:3
MAINTAINER dykim <dykim@cityholic.com>
 
RUN apt-get update
 
# Application
RUN git clone https://username:password@your-git-host/xxx/hello-web.git /usr/src/app
RUN pip install -/usr/src/app/requirements.txt
 
# Nginx
RUN apt-get install -y nginx
ADD ./conf/hello-web /etc/nginx/sites-available/hello-web
RUN ln -/etc/nginx/sites-available/hello-web /etc/nginx/sites-enabled/
RUN rm /etc/nginx/sites-enabled/default
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
RUN chown -R www-data:www-data /var/lib/nginx
 
 
# uWSGI
RUN pip install uwsgi
ADD ./conf/hello.ini /etc/uwsgi/sites/hello.ini
 
# Supervisor
RUN apt-get install -y supervisor
ADD ./conf/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
 
CMD ["/usr/bin/supervisord"]
 
EXPOSE 80
EXPOSE 443
cs

첫번째 방법과 다른 점만 설명한다면


1 라인:

소스 자동설치 하지 않는 그냥 python docker 이미지를 기반으로 합니다.


7 ~ 8 라인:

소스를 git에서 가져옵니다. 그리고 필요한 파이썬 패키지도 직접 설치합니다.



소스만 변경될 때 사용하는 도커파일 (Dockerfile-u)


1
2
3
4
5
6
7
FROM 10.3.0.38:5000/hello-web
MAINTAINER dykim <dykim@cityholic.com>
 
RUN pip install -/usr/src/app/requirements.txt
 
WORKDIR /usr/src/app
RUN git pull
cs


1 라인:

최종 버전(latest) 이미지를 기반으로 합니다.


4 ~ 7 라인:

혹 추가된 패키지가 있으면 설치하고 변경된 소스를 pull 받습니다.



개선 후 이미지 크기

첫번째 이미지야 기존과 비슷하여 비슷한 빌드, push, pull 시간이 소용됩니다.

그러나 소스만 변경된 경우는 휘리릭~ 빌드되고 Repository에 올라가고 서버에 pull 됩니다. 올레~


Version 1 --> 좀 걸림

$ docker build -t 10.3.0.38:5000/hello-web -t 10.3.0.38:5000/hello-web:1 .

$ docker push 10.3.0.38:5000/hello-web


Version 2 : 소스 업데이트용 도커파일은 이름을 달리 했음 --> 휘리릭~

$ docker build -f Dockerfile-u -t 10.3.0.38:5000/hello-web -t 10.3.0.38:5000/hello-web:2 .

$ docker push 10.3.0.38:5000/hello-web


Version 3 -> 휘리릭~

docker build -f Dockerfile-u -t 10.3.0.38:5000/hello-web -t 10.3.0.38:5000/hello-web:3 .

docker push 10.3.0.38:5000/hello-web


...


실제 이미지 레이어 예)



보는 것과 같이 Version 2, 3는 작은 량의 이미지 레이어만 추가되고 Repository에 push하거나 pull 할 때 이 부분만 전송됩니다.

물론 소스, 패키지외 시스템/소프트웨어 구성에 변경이 생기면 기본 이미지 다시 만들어서 하시면 됩니다.


삽질 그리고...

남들 다 쓰는 도커, 시작한 지 얼마 안되었는데 이미지 관리하고 구성하려고 하니 구체적으로 어떤 식으로 하는지 자료 찾기가 어렵네요. 그리고 이런 문제에 대한 질문이 Stack Overflow에 간간히 있는데 시원한 답은 못 찾겠고

결국 삽질하고 이렇게 기록해 둡니다.

더 좋은 practice가 있다면 알려주시면 감사하겠습니다~


시간 되면 빌드 서버에서 여러 대의 원격 도커 컨테이너 죽이고 새로운 이미지 구동하는 파이썬 스크립트 정리해서 공유하겠습니다. (필요한 분 있을려나???)


'Docker' 카테고리의 다른 글

파이썬 Docker 이미지 관리하기  (1) 2016.09.22
Docker로 파이썬 배포 운영하기  (0) 2016.09.22
1 Comments
댓글쓰기 폼