PyCharm 2016 の Docker サポートの使い勝手が良いです。
Docker で開発環境を作るのは初めてだったのですが、
- ローカル ( mac ) は Docker Toolbox を使って開発環境を作る。PyCharm のデバッガでステップ実行できるようにする。
- ソースコード、およびログディレクトリは Docker イメージの中に入れず、ホストのディレクトリをマウントして使う
- 公開サーバを見越して uwsgi, nginx の設定も作っておく
という所までできたので、手順を書きます。
コード置いてあります。 https://github.com/ytyng/docker-django-skeleton
こちらを参考にしました。https://github.com/dockerfiles/django-uwsgi-nginx
必要アプリのインストール
- PyCharm v2016.2〜
- Docker Toolbox
インストーラに従ってインストールしておきます。
プロジェクトディレクトリを作成し、PyCharm で開く
$ mkdir docker-django-skeleton
$ open -a PyCharm docker-django-skeleton
PyCharm用の Bash プラグインのインストール
メニューバーの PyCharm → Preferences → 検索: Plugins → Plugins の検索で「BashSupport」を検索 → 該当したものをインストールしておきます。
PyCharmの再起動を求められるので、案内通り再起動します。
Docker 用のファイルを作る
プロジェクトルートに Dockerfile そのまま置くと煩雑になってしまうので、docker ディレクトリを作って関連ファイルを入れます。
docker/Dockerfile
FROM ubuntu:16.04
MAINTAINER ytyng
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
python3-dev \
python3-setuptools \
libjpeg-dev \
nginx \
supervisor \
&& rm -rf /var/lib/apt/lists/*
# ipython, gnureadline が必要なら
# lib32ncurses5-dev
RUN ln -s /usr/lib/x86_64-linux-gnu/libjpeg.so /usr/lib/libjpeg.so
# RUN easy_install3 pip # aptで入れた方が安定
COPY requirements/base.txt /tmp/requirements/base.txt
RUN pip3 install -r /tmp/requirements/base.txt
# setup all the configfiles
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
COPY nginx-app.conf /etc/nginx/sites-available/default
COPY supervisor-app.conf /etc/supervisor/conf.d/
RUN mkdir -p /etc/nginx/certs
# COPY certs /etc/nginx/certs/
RUN mkdir -p /var/run/django/
# set locale
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
EXPOSE 80
#EXPOSE 443
↑ libjpeg などインストールしてるのは Pillow 用
docker/requirements/base.txt
Django==1.10.1
pytz
uwsgi
# MySQL使う場合
PyMySQL
↑ 今回のサンプルは、DBは SQLite3 なので PyMySQL 不要ですがサンプルとして書いてます。
docker/nginx-app.conf
server {
listen 80;
# listen 443 ssl;
server_name docker-django-skeleton.example.com;
charset utf-8;
# ssl_certificate /etc/nginx/certs/xxx.crt;
# ssl_certificate_key /etc/nginx/certs/xxx.key;
location /static/ {
alias /var/django/docker-django-skeleton/staticfiles/;
break;
}
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:3031;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
docker/supervisor-app.conf
[program:app-uwsgi]
command = /usr/local/bin/uwsgi --ini /var/django/docker-django-skeleton/conf/uwsgi.ini
[program:nginx-app]
command = /usr/sbin/nginx
Docker 用の設定ファイルの作成
環境変数など設定する Bash スクリプトを用意しておきます。
mac で実行した場合と公開サーバで起動した場合に読み込まれる設定を変えるようにしています。
docker/_settings.sh
#!/usr/bin/env bash
APP_NAME=docker-django-skeleton
DJANGO_APP_NAME=docker_django_skeleton
PROJECT_DIR=$(cd $(dirname ${BASH_SOURCE:-$0})/..;pwd)
if [ $(which docker-machine) ]; then
# mac
eval "$(docker-machine env default)"
DOCKER_COMMAND=docker
DOCKER_MACHINE_COMMAND=docker-machine
LOG_DIR=/tmp/log/${APP_NAME}
export UWSGI_PROCESSES=1
export UWSGI_THREADS=1
export DJANGO_SETTINGS_MODULE=${DJANGO_APP_NAME}.settings.local
else
# ubuntu
DOCKER_COMMAND="sudo docker"
LOG_DIR=/var/log/${APP_NAME}
OPTIONAL_PARAMS="--link mysql:mysql"
RUN_COMMAND="supervisord -n"
export UWSGI_PROCESSES=2
export UWSGI_THREADS=2
export DJANGO_SETTINGS_MODULE=${DJANGO_APP_NAME}.settings.production
fi
Dockerイメージ作成用スクリプト
docker/docker-01-build.sh
#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh
${DOCKER_COMMAND} build -t ${APP_NAME} .
docker/docker-02-run.sh
#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh
mkdir -p -m 777 ${LOG_DIR}
${DOCKER_COMMAND} run -d -P -p 80:80 -p 443:443 \
-v ${PROJECT_DIR}:/var/django/${APP_NAME} \
-v ${LOG_DIR}:/var/log/django \
-v /etc/localtime:/etc/localtime:ro \
-e DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE} \
-e UWSGI_PROCESSES=${UWSGI_PROCESSES} \
-e UWSGI_THREADS=${UWSGI_THREADS} \
${OPTIONAL_PARAMS} \
--name ${APP_NAME} ${APP_NAME} ${RUN_COMMAND}
if [ "${DOCKER_MACHINE_COMMAND}" ]; then
docker-machine ip default
fi
${DOCKER_COMMAND} ps
docker/docker-03-bash.sh
#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh
EXISTS=$(${DOCKER_COMMAND} ps --quiet --filter name=${APP_NAME})
if [ "${EXISTS}" ]; then
${DOCKER_COMMAND} exec -it ${APP_NAME} /bin/bash $@
else
${DOCKER_COMMAND} run --rm -it \
-e DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE} \
-v ${PROJECT_DIR}:/var/django/${APP_NAME} \
--name ${APP_NAME} ${APP_NAME} /bin/bash $@
fi
docker/docker-09-rm.sh
#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh
${DOCKER_COMMAND} rm --force ${APP_NAME}
docker/manage.sh
#!/usr/bin/env bash
cd $(dirname ${BASH_SOURCE:-$0})
. _settings.sh
EXISTS=$(${DOCKER_COMMAND} ps --quiet --filter name=${APP_NAME})
if [ "${EXISTS}" ]; then
${DOCKER_COMMAND} exec -it ${APP_NAME} \
/bin/bash -c "cd /var/django/${APP_NAME}/${APP_NAME}/; ./manage.py $*"
else
${DOCKER_COMMAND} run --rm -it \
-e DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE} \
-v ${PROJECT_DIR}:/var/django/${APP_NAME} \
--name ${APP_NAME} ${APP_NAME} /bin/bash -c \
"cd /var/django/${APP_NAME}/${APP_NAME}/; ./manage.py $*"
fi
*.sh には、実行パーミッションを付与しておきます。
$ chmod +x docker-*.sh manage.sh
docker-django-skeleton
└── docker
├── Dockerfile
├── _settings.sh
├── docker-01-build.sh
├── docker-02-run.sh
├── docker-03-bash.sh
├── docker-09-rm.sh
├── manage.sh
├── nginx-app.conf
├── requirements
│ └── base.txt
└── supervisor-app.conf
Docker イメージの作成
先ほど作成した、docker-01-build.sh を PyCharm 上で右クリック → Run 'docker-01-build.sh'
Dockerイメージができます。
Django プロジェクトディレクトリの作成
既に他の件で Django が mac にインストールされている場合は、それを使って `django-admin.py startproject` すれば良いと思いますが、今回は先ほど Docker イメージにインストールした Django を使って Django プロジェクトを作成します。
プロジェクトディレクトリをまるごと Docker にマウントし、Docker内で startproject します。
$ docker run -it -v `pwd`:/var/django/docker-django-skeleton docker-django-skeleton /bin/bash
※ pwd は、docker-django-skeleton ディレクトリ。docker ディレクトリの親ディレクトリ
$ docker run -it -v `pwd`:/var/django/docker-django-skeleton docker-django-skeleton /bin/bash
root@8d2ba7a54287:/# cd /var/django/docker-django-skeleton/
root@8d2ba7a54287:/var/django/docker-django-skeleton# django-admin.py startproject docker_django_skeleton
root@8d2ba7a54287:/var/django/docker-django-skeleton# mv docker_django_skeleton docker-django-skeleton
root@8d2ba7a54287:/var/django/docker-django-skeleton#
好みの問題ですが、Django プロジェクトのディレクトリ名は アンダーバーではなく ハイフンに変更しています。
PyCharm を見てみると、docker-django-skeleton ディレクトリが作成されているのが確認できます。
settings を環境ごとに分ける
Django でよくやるプラクティスで、settings を ローカル環境と公開環境で分けるというものがあります。
docker_django_skeleton ディレクトリ内で、
1. settings ディレクトリを作成
2. settings.py は、 settings/base.py に改名
3. settings/local.py settings/production.py を作成。
settings/local.py, settings/production.py の内容は以下のようになります。
settings/local.py
from .base import * # NOQA
内容はありませんが、今回はこれで良しとします。
manage.py のインタプリタ (シェバン shebang ) を python3 にしておく
作成された manage.py を見てみると、1行目が
manage.py
#!/usr/bin/env python
となっていますが、Docker イメージ内には Python2 が残っているため不具合が起こることがあります。
#!/usr/bin/env python3
に変更しておきます。
PyCharm のインタプリタで Docker の Python を指定する
PyCharm → Preferences → 検索: interpreter
Project Interpreter が出てきます。
ここで、右上の「...」ボタンをクリックし、Add Remote を選択。
Configure Remote Python Interpreter になるので、
「Docker」を選択、Image name は docker-django-skeleton:latest を選択してください。
それと、Python interpreter path: は python となっていますが、python3 に変更します。
すると、Docker 内の Python 環境を認識します。すごい!
Djangoサポートを有効にする
Preferences で、検索: django
Language & Frameworks の Django が出て来るので選択し、Enable Django Support にチェック。
Django project root: manage.py のある、docker-django-skeleton
Settings: docker_django_skeleton/settings/local.py
OKをクリック
Project Structure を設定する
Preferences で、検索: structure
manage.py のある、docker-django-skeleton ディレクトリを選択し、Source をクリック → OK
migrate
次は、./manage.py migrate をします。
docker コンテナ内なので、./manage.py を実行するのも少し面倒ですが、docker ディレクトリの中に manage.sh を作ってあるのでこれを使います。
$ cd docker
$ ./manage.sh
Type 'manage.py help <subcommand>' for help on a specific subcommand.
Available subcommands:
[auth]
changepassword
createsuperuser
[django]
check
compilemessages
...
$ ./manage.sh migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
...
Docker の Django環境を使ってマイグレーションしてくれました。
テストサーバの起動
PyCharm の右上、Run/Debug の選択をクリックし、Edit Configurations...
Run/Debug Configurations ダイアログで、左上の + をクリック
Django server を選択
Host: には、0.0.0.0 を入力(重要)
Name: は適当に (例: runserver )
→ OK
出来た runserver 実行環境が選択されている状態で、虫(デバッグ) ボタンを押下
System check identified no issues (0 silenced).
September 26, 2016 - 09:54:15
Django version 1.10.1, using settings 'docker_django_skeleton.settings.local'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
となりますので、0.0.0.0:8000 をクリックするとブラウザが起動し、Docker マシーンにリダイレクトされてページが表示されます。
デバッガも有効な状態ですので、ブレイクポイントが使えます。すごい!
公開環境で起動する
uwsgi.ini
[uwsgi]
app = $(APP_NAME)
django_app = $(DJANGO_APP_NAME)
base = /var/django/%(app)/%(app)/
pythonpath = %(base)
chdir = %(base)
socket = 127.0.0.1:3031
module = %(django_app).wsgi:application
processes = $(UWSGI_PROCESSES)
threads = $(UWSGI_THREADS)
master = true
pidfile = /var/run/django/%(app).pid
touch-reload = %(base)/%(django_app)/wsgi.py
lazy-apps = true
thunder-lock = true
buffer-size = 32768
logto = /var/log/django/%(app)/%n.log
uwsgi の設定ファイルはこんな感じですかね。
ソースコードを公開環境のサーバに持っていって、
$ ./docker-01-build.sh
でコンテナを作り (ローカルで作ったのを Docker hub に push -> 本番で Pull でもいいですが)、
$ docker-02-run.sh
で起動すると、公開環境 (というか docker-machine がインストールされてない環境 ) では本番用設定で nginx → uwsgi → Django で起動します。
Docker コンテナを削除する時は
$ docker-09-rm.sh
で消えます。