풀스택 개발 들여다보기

[Docker] Dockerizing 예 - 파이썬 플라스크 서버

영바이트 2022. 3. 23. 19:40

약 10여 개의 포스팅에 걸쳐 도커란 무엇인지, 기본적인 사용법, 도커 이미지 만들기, docker-compose, 그리고 Dockerfile에 대해 살펴보았다. 이제 도커 이미지를 만드는 예를 몇 가지 살펴보려고 한다.

 

도커 이미지로 만들어 볼 가장 첫 어플이케이션은 웹 서버다. 좀 더 구체적으로 파이썬 플라스크 웹 서버를 도커 이미지로 만들어 보자. 웹 서버를 도커 이미지로 관리하면 서버 코드를 업데이트하는 과정을 Dockerfile과 docker-compose를 이용해서 자동화할 수 있고, 드문 일이지만 서버를 이전하는 경우 이미지만 가지고 가면 되기 때문에 매우 편리하다.

 


 

1. 베이스 이미지 Base image 생성

필자는 이미지 생성을 위한 베이스 이미지를 만들어 놓는다. 파이썬 플라스크 웹 서버의 경우 파이썬, 파이썬 패키지 설치를 위한 pip, 그리고 가상 실행 환경을 위한 venv를 미리 설치해 놓는다.

 

최초의 이미지인 ubuntu 20.04를 쉘 모드로 실행시킨다. 만약 ubuntu 20.04 이미지를 가지고 있지 않다면 이미지가 자동으로 다운로드 될 것이다.

$> docker run -it ubuntu:20.04 /bin/bash

 

컨테이너가 실행되고 컨테이너의 쉘 환경으로 들어오면 apt 패키지 저장소를 업데이트하고 파이썬(python3), pip(python3-pip), 그리고 파이썬 가상 실행 환경(python3-venv)을 설치한다.

#> apt-get update
#> apt-get install -y python3 python3-pip python3-venv

 

파이썬 실행에 필요한 기본적인 패키지들의 설치가 끝나면 컨테이너를 빠져나온다.

#> exit

 

파이썬 실행에 필요한 패키지들을 설치한 도커 컨테이너를 docker ps -a 명령을 이용해서 검색한다. 그리고 해당 컨테이너를 이미지로 만든다. 이미지의 이름을 ubuntu_20.04::py3-pip로 지정하였다.

$> docker commit <타겟 컨테이너 ID> ubuntu_20.04::py3-pip

 

이제 이 이미지를 베이스 이미지로 파이썬 플라스크 서버 실행 환경과 서버 코드를 설치하는 Dockerfile을 작성하자.

 

2. Dockerfile

Dockerfile을 이용해서 이미지를 생성하기 전에 먼저 서버의 소스 코드를 Dockerfile을 작성할 디렉토리에 복사해두어야 한다. 여기 예에서는 현재 디렉토리 아래의 flask_server라는 디렉토리 안에 파이썬 플라스크 서버 코드가 들어 있다고 가정한다. 먼저 FROM 명령어를 이용해서 베이스 이미지를 지정하고 MAINTAINER 명령어를 이용해서 이미지 관리자를 설정한다.

 

FROM ubuntu_20.04:py3-pip

MAINTAINER sgkim08@gmail.com

 

다음으로 플라스크 서버 코드를 컨테이너 안으로 복사한다. 컨테이너의 쉘은 bash를 사용하였고 서버 코드는 root 사용자의 home 디렉토리인 /root 아래에 복사하였다.

 

WORKDIR /root

COPY flask_server /root/flask_server

 

이제 파이썬 가상 실행 환경을 설치하고 플라스크 서버 실행에 필요한 파이썬 패키지들을 설치하자.

 

WORKDIR /root/flask_server

RUN python3 -m venv venv

RUN ["/bin/bash", "-c", "source venv/bin/activate"]

RUN pip3 install wheel

RUN pip3 install -r flask_pkg_requirements.txt

 

만약 위 Dockerfile을 이용해서 의도한대로 image가 생성되지 않는다면 아래 내용을 참고한다. PATH를 설정하지 않으면 virtual env(venv)아래에 파이썬 패키지들이 설치되지 않는 경우가 있다.

ENV PATH /root/flask_server:$PATH
WORKDIR /root/flask_server
RUN python3 -m venv venv
ENV PATH /root/flask_server/venv/bin:$PATH

RUN ["/bin/bash", "-c", "source venv/bin/activate"]
RUN pip3 install wheel
RUN pip3 install -r flask_pkg_requirements.txt

 

파이썬 패키지들은 -r 옵션을 사용하여 패키지들의 이름과 버전을 기술한 파일(flask_pkg_requirements.txt)을 이용해서 설치하는 것이 편리하다. flask_pkg_requirements.txt 파일 내용의 예는 아래와 같다. 이와 같은 파일을 텍스트 에디터를 이용해서 작성하여 파이썬 플라스크 서버 디렉토리 안에 넣어 놓으면 된다.

 

▶ flask_pkg_requirements.txt 파일 예

Flask==2.0.2
Flask-Mail==0.9.1
Pillow==8.1.1
PyJWT==2.3.0
PyMySQL==1.0.2
bcrypt==3.2.0
itsdangerous==2.0.1
gunicorn==20.1.0

 

마지막으로 이미지가 컨테이너로 실행되었을 때 ①파이썬 가상 실행환경을 실행하고 ②파이썬 서버 스크립트를 실행시킬 bash 스크립트를 지정한다. 쉘 스크립트의 예는 아래와 같다. 예에서 파이썬 서버 스크립트 파일의 이름은 run.py 그리고 파이썬 플라스크 객체의 이름을 app으로 지정하였고 WSGI 프로그램인 gunicorn을 이용하여 8000번 포트에서 실행하였다. 이와 같은 쉘 스크립트를 텍스트 에디터를 이용해서 작성하여 파이썬 플라스크 서버 디렉토리 안에 넣어 놓는다.

★ chmod 명령을 이용해서 파일의 소유자가 쉘 스크립트를 실행할 수 있도록 권한을 변경해두어야 한다(예, 744).

 

▶ run 파일 예

#!/bin/bash
source venv/bin/activate
gunicorn -w 3 -b :8000 run:app

 

마지막으로 이미지가 컨테이너로 실행될 때 run 스크립트가 실행되도록 ENTRYPOINT 명령을 이용해서 지정한다.

ENTRYPOINT ["/bin/bash", "-c", "run"]

 

Dockerfile 전체 내용을 정리하면 아래와 같다.

FROM ubuntu_20.04:py3-pip
MAINTAINER sgkim08@gmail.com

WORKDIR /root
COPY flask_server /root/flask_server
ENV PATH /root/flask_server:$PATH

WORKDIR /root/flask_server
RUN python3 -m venv venv
ENV PATH /root/flask_server/venv/bin:$PATH
RUN ["/bin/bash", "-c", "source venv/bin/activate"]
RUN pip3 install wheel
RUN pip3 install -r flask_pkg_requirements.txt

ENTRYPOINT ["/bin/bash", "-c", "run"]

 

이제 docker build 명령을 이용해서 이미지를 생성할 수 있다.

$> docker build -t ubuntu_20.04:flask-server .

-t: 이름과 태그(tag)를 지정한다.

build 명령어 맨 마지막의 . 을 꼭 붙여야 한다. 현재 디렉토리에 이미지 생성에 필요한 Dockerfile과 COPY 명령어의 source 파일들이 있다는 의미이다.

 

Dockerfile을 이용해서 이미지를 생성하면 그 과정이 명령어 내용과 함께 화면에 표시된다.

 

3. docker-compose

이미지가 생성되면 docker images 명령을 이용해서 생성된 이미지를 확인할 수 있다.

$> docker images

 

이미지 실행을 위한 docker-compose.yml 스크립트를 작성해 보자. 예를 들면 아래와 같이 작성할 수 있다.

version: "3.3"
services:
 web:
  image: ubuntu_20.04:flask-server
  container_name: "flask-server"
  network_mode: "host"

 

이미지를 실행할 때 호스트와 네트워크를 공유하도록 network_mode를 "host"로 설정하였다. 이는 호스트에 설치되어 있는 데이터베이스를 컨테이너 내부의 웹 서버가 접속할 수 있게끔 하기 위함이다. 컨테이너 안에 데이터베이스를 설치하고 운영하면 컨테이너가 중지되면 데이터베이스 내용까지 사라질 수 있기 때문에 데이터베이스는 호스트에 설치하거나 별도의 컨테이너를 사용한다면 주기적으로 백업해 주어야한다.

 

이제 docker-compose up 명령를 이용해서 웹 서버 컨테이너를 실행시키면 Dockerfile의 run 쉘 스크립트를 통해 웹 서버가 실행된다.

$> docker-compose up