Dockerを利用したDjangoの実行環境セットアップ方法を紹介します。
Docker構成はDjango, Nginx、MySQL, KVS(Redis)のコンテナを組み合せた環境を構築し
MySQL, KVSについてはデータを永続化させるよう対応します。
開発スタイルとしては、Docker-machinは1つで、開発環境、本番環境を構築し
docker-composeでどちらか一方が起動でき簡単に切り替えが行えるようにします。
コンテナ構成
クライアントからのアクセスを受け、NginxがリバースプロキシでバックエンドのAPPサーバへproxyし
Nginxコンテナは、APPコンテナをmountしてAPPコンテナの静的ファイルを参照できるようにします。
MySQLコンテナ、RedisコンテナはAPPコンテナにlinkさせコンテナ同士で通信する形になり、
Storageコンテナは、MySQL、Redisのデータを持ちます
ファイル構成
サンプル用のDjangoアプリケーションを含めたDockerのファイル構成が以下になります
├── app
│ ├── __init__.py
│ ├── env
│ ├── manage.py
│ ├── requirements.txt
│ ├── settings.py
│ ├── static
│ ├── todo
│ │ ├── __init__.py
│ │ ├── apps.py
│ │ ├── migrations
│ │ │ ├── 0001_initial.py
│ │ │ └── __init__.py
│ │ ├── models.py
│ │ ├── templates
│ │ │ ├── _base.html
│ │ │ └── home.html
│ │ └── views.py
│ ├── urls.py
│ └── wsgi.py
├── docker-compose-dev.yml
├── docker-compose-prod.yml
├── docker-compose.sh
├── mysql
│ ├── Dockerfile
│ └── charset.cnf
├── nginx
│ ├── Dockerfile
│ └── sites-enabled
│ └── django_project
└── storage
└── Dockerfile
各コンテナ別にディレクトリを作っていて、Dockerfileを準備してます
docker-compose-dev.ymlとdocker-compose-prod.ymlに開発、本番環境をDocker構成を定義し
docker-compose.shで切り替えを行います。
上記の全ファイルはgithubに置いてます
https://github.com/fujimisakari/django-docker
docker-compose-dev.yml
dev_app:
image: todo_app
restart: always
env_file: ./app/env
expose:
- "8000"
links:
- dev_mysql:db
- dev_redis:redis
volumes:
- ./app:/usr/src/app
command: ./manage.py runserver 0.0.0.0:8000
dev_nginx:
build: ./nginx
restart: always
ports:
- "80:80"
links:
- dev_app:app
volumes_from:
- dev_app
dev_mysql:
build: ./mysql
restart: always
ports:
- "3306:3306"
volumes_from:
- dev_storage
dev_redis:
image: redis:latest
restart: always
ports:
- "6379:6379"
volumes_from:
- dev_storage
command: redis-server --appendonly yes
dev_storage:
build: ./storage
appコンテナは、buildに時間を取るのでdocker-composeの実行前に作成するtodo_appイメージを
利用するようにしており、mysqlとredisはデータ永続化するためにstorageコンテナのvolumeを
マウントしてこちらにデータを書き込みます。
redisコマンドの「--appendonly yes」は、redisのデータを/dataに書き残すために必要なオプションになります
docker-compose-prod.yml
prod_app:
image: todo_app
restart: always
env_file: ./app/.env
expose:
- "8000"
links:
- prod_mysql:db
- prod_redis:redis
volumes:
- ./app:/usr/src/app
command: /usr/local/bin/gunicorn app.wsgi:application -w 2 -b :8000
prod_nginx:
build: ./nginx
restart: always
ports:
- "80:80"
links:
- prod_app:app
volumes_from:
- prod_app
prod_mysql:
build: ./mysql
restart: always
ports:
- "3306:3306"
volumes_from:
- prod_storage
prod_redis:
image: redis:latest
restart: always
ports:
- "6379:6379"
volumes_from:
- prod_storage
command: redis-server --appendonly yes
prod_storage:
build: ./storage
本番環境といっても開発時に利用するものなのでdocker-compose-dev.ymlとほぼ同じになるのですが、
appコンテナのwebサーバーの起動コマンドがgunicornになっています。
パフォーマンスチェックする時にuwsgiやfastcgiなど別webサーバーに簡単に変更できます
docker-compose.sh
if [ $1 ]; then
case $1 in
"dev")
echo "$ docker-compose -f docker-compose-dev.yml ${@:2}"
docker-compose -f docker-compose-dev.yml ${@:2}
;;
"prod")
echo "$ docker-compose -f docker-compose-prod.yml ${@:2}"
docker-compose -f docker-compose-prod.yml ${@:2}
;;
esac
else
echo "Please input platform to script paramater.\n ./docker-compose.sh platform [args]"
fi
開発、本番環境へdocker-composeコマンドを実行しようとすると毎回 -f コマンドで
ymlファイルを指定してする必要があり面倒なのでスクリプトでラップしました。
第一引数に環境を指定して実行します。
コンテナ起動をさせる
appイメージ作成
docker-compose up --buildですべてのコンテナをビルドして起動する準備はできますが、
appのビルドはapt-installやpip installがあり少し時間がかかるので利用するイメージを事前に
準備しこちらを利用するようにします。
$ cd ./app
$ docker build .
$ docker tag <ビルドで生成されたコンテナID> todo_app
hostsファイル更新
docker-machineのIPアドレスを毎回入力したくないので。
以下を追記
$ sudo vim /etc/hosts
192.168.99.100 docker-machine
Dockerコンテナ起動(開発環境を起動させる場合)
# 起動(-dを付けるとデーモンにもできる)
$ ./docker-compose.sh dev up --build
$ docker exec -it <devのAppのコンテナ識別子> ./manage.py migrate
$ ./docker-compose.sh dev stop
$ ./docker-compose.sh dev up
http://docker-machine でアクセスできるようになる
ホストからDockerへよく利用するコマンド
./manage.py の実行
$ docker exec -it <コンテナ識別子> ./manage.py <command>
MySQLへの接続
$ mysql -u root -h docker-machine todo
MySQLのQuery確認
$ docker exec -it <コンテナ識別子> tail -f /tmp/sql.log
$ docker exec -it <コンテナ識別子> tail -f /tmp/slow_sql.log
感想
開発の利用用途だけで言うと、ローカルの開発環境の方が効率が良いと思うのですが
Dockerを利用するとプログラム以外の技術もチャレンジしやすくなり幅広く経験できると思います。
まだDocker開発環境に切り替えて数週間ですが以下のメリット、デメリットを感じました。
メリット
簡単に異なるアプリケーション環境をいくつも作ることができるので
パフォーマンスチェックやインフラの構成変更などやろうとするモチベーションが上がる。
また、テストはこれまで専用のfixutreデータが入った環境が必要だったのですが
Dockerで簡単に環境が用意できるのでDBの切り替えなども必要もなく
カジュアルにテストできるのはうれしいですね。
デメリット
アプリケーション操作しようとすると何でもdocker 〜コマンドになるので
ホストにvirtualenvで開発環境を構築する方が操作が簡単です。
あと、Docker上にpythonのサードパーティモジュールがあるので
Pythonファイルを開いたときpylint等のコードチェッカーでimportエラー発生します。
そのため、結局ローカルにも環境を用意しました。