Python 웹 애플리케이션을 Docker로 실행

마지막: Emby를 Docker로 운영하기
이것은 이제 Docker를 사용할 수있게되고 싶은 필자의 시행 착오의 궤적입니다.

Python 웹 애플리케이션을 Docker로



지난번에는 미디어 스트리밍 서비스의 Emby를 컨테이너로 마이그레이션했습니다.


이번에는 파이썬 웹 애플리케이션을 배포할 수 있는 Docker 이미지를 만들고,
Web Socket을 사용하는 애플리케이션과 Django 애플리케이션을 Docker로 마이그레이션합니다.
그런 다음 정적 콘텐츠도 컨테이너로 이동하여 VM 서버를 닫습니다.


정적 콘텐츠



VM 서버에 있던 것을 Docker 호스트로 이동해, 컨테이너 기동시에 배달 디렉토리에 바인드 했습니다.

docker-compose.yml
    deploy:
        image: nginx
        restart: always
        ports:
            - 80:80
            - 443:443
        volumes:
            - /home/fclef/docker/server/deploy/nginx/conf:/etc/nginx/conf.d
+           - /home/fclef/docker/server/deploy/content/html:/usr/share/nginx/html

파이썬 애플리케이션의 Docker 운영



Web Socket 사용 어플리케이션도 Python제(bottle)이므로, Python제 어플리케이션을 간단하게 전개할 수 있는 컨테이너를 목표로 합니다.

컨테이너 설계



난 자주 파이썬으로 웹 응용 프로그램을 만듭니다.
그러므로, 어플리케이션마다 이미지에 굳어 버리는 것보다는,
어떤 Python 애플리케이션에서도 움직일 수 있는 토대를 이미지화하고,
구체적인 어플리케이션 자체는 git의 정보를 컨테이너 기동시에 건네주어, 컨테이너내에서 클론, 전개시킵니다.


Dockerfile



내가 파이썬으로 무언가를 만들 때마다 Pipenv를 사용합니다.
또, 웹 어플리케이션의 경우는 소켓화해 nginx로 전달하므로,
이미지 시점에 Pipenv, nginx를 설치합니다.

Dockerfile
FROM python:3.8-slim-buster

# 依存パッケージのインストール
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get install -y git make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libs
qlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev nginx

# Pyenvのインストール
RUN git clone https://github.com/yyuu/pyenv.git /.pyenv
ENV PYENV_ROOT /.pyenv
ENV PATH $PYENV_ROOT/bin:$PATH
RUN pyenv init - | bash
# Pipenvのインストール
RUN pip install pipenv
ENV PIPENV_VENV_IN_PROJECT 1
ENV PIPENV_YES true

RUN mkdir /app # アプリケーション配備ディレクトリ
RUN mkdir /script # 各種スクリプト配置ディレクトリ

COPY up.sh /script # 起動スクリプト

# 起動スクリプト内でgitプロジェクトをappにクローンするので移動しておく
WORKDIR /app
# Webアプリケーションの配信はメインWebサーバを介するリバースプロキシなので、80ポートだけ空けておく
EXPOSE 80
RUN chmod +x /script/up.sh
ENTRYPOINT [ "/script/up.sh" ] # コンテナ起動時、起動スクリプトup.shを実行する

컨테이너 시작 스크립트



응용 프로그램의 git 정보는 컨테이너가 시작될 때 환경 변수로 전달됩니다.
내 환경에서는 왠지 ssh에서 git을 복제 할 수 없기 때문에 https로 복제한다고 가정합니다.
복제되면 프로젝트 루트 디렉토리에 있는 Pipfile을 구문 분석하여 필요한 Python 버전을 결정합니다.
일부 Python 라이브러리에는 종속 프로그램이 설치되어 있어야 하는 경우가 있으므로
이것들을 설치하기 위한 스크립트(dependencies.sh)를 컨테이너 기동시에 바인드 해 두어, 여기에서 호출합니다.
파이썬 웹 애플리케이션의 소켓화는 gunicorn을 사용하므로 gunicorn도 설치해 둡니다.

up.sh
#!/bin/bash

# 環境変数からgit情報を取得する
gitCloneUrl=${GIT_CLONE_URL}
gitUserName=${GIT_USER_NAME}
gitPassword=${GIT_PASSWORD}
gitCloneTarget=`echo ${gitCloneUrl} | sed -r "s#^(https?://)(.*)#\1${gitUserName}:${gitPassword}@\2#g
"`

# プロジェクト名を取得する
projectName=`echo ${gitCloneUrl} | sed -r "s#.*/(\w+)\.git#\1#g"`
echo "■ ■ ■ PROJECT NAME <${projectName}> ■ ■ ■"

git clone ${gitCloneTarget}

# Pipfileからpythonバージョンを取得する
cd ${projectName}
pythonVersion=`grep python_version Pipfile | sed -r 's/python_version = "(.+)"/\1/g'`
echo "■ ■ ■ PYTHON VERSION <${pythonVersion}> ■ ■ ■"

# インストールするPythonライブラリの中に他プログラムに依存するものがある場合は、ここでインストールしておく。
if [ -f /script/dependencies.sh ]; then
    source /script/dependencies.sh
fi

pipenv --python ${pythonVersion}
pipenv install
pipenv install gunicorn

curPath=`pwd`
export APP_ROOT=${curPath}

chmod +x /script/run.sh
service nginx start
/script/run.sh # アプリケーション起動スクリプト
while true; do sleep 1000; done

컨테이너 시작



예를 들어 Django 애플리케이션을 시작하는 구성을 보여 드리겠습니다.

docker-compose.yml 발췌
django:
    image: pipenv-gunicorn
    restart: always
    environment:
        GIT_CLONE_URL: https://xxxxxxxx/user/project.git
        GIT_USER_NAME: user
        GIT_PASSWORD: password
    volumes:
        - /home/fclef/docker/server/app/dependencies.sh:/script/dependencies.sh
        - /home/fclef/docker/server/app/run.sh:/script/run.sh
        - /home/fclef/docker/server/app/app.conf:/etc/nginx/conf.d/nginx_gunicorn.co
nf
    depends_on:
        - deploy
        - gitlab

dependencies.sh
apt-get -y --no-install-recommends install libpq-dev

run.sh
cd /app/project

source .venv/bin/activate

python manage.py collectstatic --noinput
python manage.py makemigrations
python manage.py migrate

deactivate

/app/project/.venv/bin/gunicorn \
          --access-logfile /var/log/socket_success.log \
          --error-logfile /var/log/socket_error.log \
          --workers 1 \
          --bind unix:/run/socket.sock \
          config.wsgi:application

app.conf
server {
    listen       80;
    listen [::]:80;
    server_name xxxx.xxx.xxx;

    root /app;

    location /static {
        alias /app/project/static;
    }

    location / {
        include /etc/nginx/proxy_params;
        proxy_pass http://unix:/run/socket.sock;
    }

    location ~ ^/apple-touch-icon(.*)\.png$ {
        root /app/project/;
        rewrite ^/apple-touch-icon(.+)\.png$ /static/img/apple-touch-icon.png break;
    }
}

어플리케이션 본체는 컨테이너 기동시에 git로부터 클론,
데이터는 다른 컨테이너의 PosgreSQL에 저장되어 있으므로,
이 컨테이너는 여러 번 다시 작성해도 정상적으로 프로덕션 서비스를 배포할 수 있습니다.

기본적으로 위의 이미지와 시작 방법으로 대부분의 Python 응용 프로그램을 실행할 수 있습니다.
git 클론에서 배포까지의 단계가 간단하기 때문에 애플리케이션을 떠나 재사용하기 쉬운 이미지를 만들 수 있었지만,
환경 구축이 복잡한 어플리케이션의 경우는, 어플리케이션마다 이미지로 해 버리는 것이 보수성이 오를지도 모릅니다.

이상, VM 서버군을 컨테이너로 이행하는 시리즈였습니다.

좋은 웹페이지 즐겨찾기