DockerでDjangoの実運用環境を作ってみる

Created 2018年5月24日22:17
Updated 2018年5月24日23:34
Categories Django Python Docker 自宅サーバー

自宅サーバーのDockerクラスタにDjangoで作ったサービスを展開する際に少しハマったのでメモ。

本記事の成果物はこちらに上げてあります。

ちなみに、Docker公式のチュートリアルがありますが、こちらはDjango内蔵のWebサーバーを使っており開発環境向けです。

また、swarmクラスタに展開する場合はもう少し調整が必要です。


Dockerfile

基本的には A Production-ready Dockerfile for Your Python/Django App を参考に設定していますが、こちらはPostgreSQL向けの情報なので、MySQL向けに変更しました(主にライブラリの追加などを行っています)。

また、/vnevをpython -m venvから作るよう変更しています。

試行錯誤の過程でイメージの軽量化を諦めたので、ベストな手法とは程遠いかもしれません。

# This Dockerfile is based on https://www.caktusgroup.com/blog/2017/03/14/production-ready-dockerfile-your-python-django-app/
FROM python:3.5-alpine

# Copy in your requirements file
ADD requirements.txt /requirements.txt

# Install build deps, then run `pip install`, then remove unneeded build deps all in a single step. Correct the path to your production requirements file, if needed.
RUN set -ex \
    && apk add --no-cache \
            gcc \
            make \
            libc-dev \
            musl-dev \
            linux-headers \
            mariadb-dev \
            pcre-dev
RUN python -m venv /venv
RUN /venv/bin/pip install -U pip
RUN /bin/sh -c "/venv/bin/pip install --no-cache-dir -r /requirements.txt"

# Copy your application code to the container (make sure you create a .dockerignore file if any large files or directories should be excluded)
RUN mkdir /code/
WORKDIR /code/
ADD dockerized_project /code/
ADD start_uwsgi.sh /code/
ADD uwsgi_conf.ini /code/
RUN mkdir -p /code/dockerized_project/static

# uWSGI will listen on this port
EXPOSE 12345

# Add any custom, static environment variables needed by Django or your settings file here:
ENV DJANGO_SETTINGS_MODULE=dockerized_project.settings.production

CMD ["sh", "/code/start_uwsgi.sh"]

requirements.txt

django
django-cors-headers
mysqlclient
uwsgi

start_uwsgi.sh

Djangoのstaticファイルを収集した後に、uwsgiを起動しています。

#!/bin/sh

/venv/bin/python manage.py collectstatic --noinput
/venv/bin/uwsgi --ini uwsgi_conf.ini

uwsgi_conf.iniはDockerfileでADDしていますが、volumesでマウントして上書きしても良いと思います。

uwsgi_conf.ini

設定内容は How to use Django with uWSGI を参照しました。

[uwsgi]
socket = 0.0.0.0:12345
master = true
processes = 5
chdir = /code
module = dockerized_project.wsgi:application
pidfile = /tmp/project-master.pid
uid = 1000
gid = 2000
harakiri = 20
max-requests = 5000
vacuum = true

設定はjsonとかにも書けるらしいのですが、uwsgi起動時に--jsonパラメータが無いと言われてしまいうまく動きませんでした・・・

docker-compose.yml

コンテナの構成は Scaling Django を参考にしました。

version: "3"

services:
  uwsgi:
    build:
      context: .
    environment:
      - DJANGO_SETTINGS_MODULE=dockerized_project.settings.production
    volumes:
      - ./docker_volumes/static:/code/dockerized_project/static

  db:
    image: mysql
    command: mysqld --character-set-server=utf8 --collation-server=utf8_unicode_ci
    volumes:
      - ./docker_volumes/mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=root_password
      - MYSQL_DATABASE=db_name
      - MYSQL_USER=db_user
      - MYSQL_PASSWORD=db_password

  app:
    image: nginx
    volumes:
      - ./nginx/app.conf:/etc/nginx/nginx.conf
    ports:
      - 5000:80

  static:
    image: nginx
    volumes:
      - ./nginx/static.conf:/etc/nginx/nginx.conf
      - ./docker_volumes/static:/static

uwsgi: Djangoアプリケーションのソケット

app: ソケットにアクセスするnginx

static: 静的ファイルを提供するnginx

db: データベース

nginx/{app.conf|static.conf}

nginxのコンテナが2つあり、appとstaticというサービス名になっています。

ユーザーはappにアクセスし、そこからuwsgiとstaticにリクエストを振り分けます。

nginxイメージから取ってきたnginx.confをちょっと変更しているだけなのでコードの掲載は割愛します。

dockerized_project ディレクトリ

Djangoのstartprojectを実行したまま、ほぼデフォルトの状態です(管理画面のログイン画面を出すくらいしかできることがありません・・・)。

変更点として、settingsをディレクトリ化しproduction.pyとdevelopment.pyを追加してDBの設定を行っています。

実行

docker-compose up -d

これで、http://localhost:5000/adminにアクセスすると動作していることが確認できます。

せっかく起動しても管理画面を出すだけではつまらないので、manage.pyで管理ユーザーを作ってみましょう。

DjangoのuwsgiコンテナはPythonイメージがベースになっており、シェルはashが使えます。

docker-compose execで入ってからvenvを有効にすれば、manage.pyが実行できます。

$ docker-compose exec -it uwsgi /bin/ash
/code # source /venv/bin/activate
(venv) /code # python manage.py migrate --settings=dockerized_project.settings.production
(venv) /code # python manage.py createsuperuser --settings=dockerized_project.settings.production

もちろんmakemigrationsなども同じように実行できます。

まとめ

Djangoはローカルで試すのは簡単ですが、実際にプロダクション環境で動作させるのは結構大変ですね。

Dockerなら簡単にできると思いましたが、意外とひな形を動かすのに苦労してしまいました。

イメージの作成についてもまだまだ不十分なので、もう少し知見が欲しいところです。

コメントを投稿

コメント