aoishiの備忘録

備忘録

DockerでDjangoの開発環境を作成する(Quickstart: Compose and DjangoのMySQL版)

はじめに

Dockerの公式ページにDocker Composeを使った簡単なDjango/PostgreSQLの環境構築のチュートリアルがあります。

docs.docker.com

普段からMySQLを使うことが多いので、PostgreSQLの代わりにMySQLを使ってチュートリアルをやってみました。

環境

  • OS: Fedora 26
  • Docker: Docker version 1.13.1, build b5e3294/1.13.1
  • Docker Compose: docker-compose version 1.16.1, build 6d1ac219
  • MySQL設定
    • データベース名: django
    • データベース文字コード: utf8mb4
    • データベースコレーション: utf8mb4_general_ci
    • ユーザ名: django
    • ユーザ接続元ホスト: %
    • パスワード: P@ssw0rd_django
    • ポート: 3306

元ネタと違う点

  • データベースをPostgreSQLからMySQLに変更しています。
  • Python実行環境のイメージをデフォルトからalpineに変更しています。

手順

プロジェクト用ディレクトリの作成と移動

適当なプロジェクト用ディレクトリを作成します。

$ mkdir -p ~/working/docker_test/django_mysql
$ cd ~/working/docker_test/django_mysql

各種ファイル作成

Dockerfile

$ cat <<EOF > Dockerfile
FROM python:3-alpine
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/
RUN pip install -r requirements.txt
ADD . /code/
EOF

requirements.txt

$ cat <<EOF > requirements.txt
Django>=1.8,<2.0
PyMySQL
EOF

DB初期化用SQLファイル

$ mkdir sql
$ cat <<EOF > sql/001_setup_application_database.sql
CREATE DATABASE IF NOT EXISTS django CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER IF NOT EXISTS 'django'@'%' IDENTIFIED BY 'P@ssw0rd_django';
GRANT ALL PRIVILEGES ON django.* TO 'django'@'%';
EOF

docker-compose.yml

dbコンテナの起動前にDjango開発サーバが起動してしまうことがあったため、webコンテナのcommandにsleepを追加しています。

$ cat <<EOF > docker-compose.yml
version: '3'

services:

  # https://hub.docker.com/r/mysql/mysql-server/
  db:
    image: mysql/mysql-server:5.7
    environment:
      - MYSQL_ROOT_PASSWORD=P@ssw0rd
      - MYSQL_ROOT_HOST=%
    volumes:
      - ./db-datadir:/var/lib/mysql
      - ./sql:/docker-entrypoint-initdb.d
    ports:
      - "3306:3306"

  web:
    build: .
    command: sh -c "sleep 3; ./manage.py runserver 0.0.0.0:8000"
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
EOF

DBの初期化

dbコンテナをバックグランドで起動して、MySQLのデータベースを初期構築します。

このとき、コンテナ側の/var/lib/mysqlにホスト側の./db-datadirがマッピングされ、db-datadirが空であれば初期化されてMySQLデータディレクトリ相当のファイルが生成されます。

$ docker-compose up -d db

$ ls -al db-datadir

元ネタのチュートリアルでは、この段階ではdbコンテナは起動しておらず、次のDjangoプロジェクト作成時にwebコンテナと一緒に起動させています。

しかし、今回はMySQLを利用して初回起動後にデータベースやユーザを作成したりMySQLの起動に時間がかかることもあり、webとdbを一緒に初回起動してしまうとDjangoからMySQLへの接続に失敗してしまうことがあったため、先にdbコンテナだけ起動させています。

Djangoプロジェクトの作成

webコンテナを起動して、Djangoプロジェクトを作成します。

$ sudo docker-compose run web django-admin.py startproject mysite .

私の環境ではsudoをつけないとwebコンテナビルド時にエラーで失敗してしまいました。 下記が発生したエラーの内容です。

Building web
ERROR: Error processing tar file(exit status 1): time="2017-11-04T17:24:03+09:00" level=info msg="SUSE:secrets :: enabled"
unexpected EOF

権限の変更

コンテナ側で作成されたMySQLのデータディレクトリやDjangoプロジェクトのファイルはrootユーザで作成されるため、所有者をホスト側のユーザに変更します。

$ sudo chown -R $USER:$USER mysite manage.py

MySQLのデータディレクトリにマッピングするdb-datadirも含めて所有者を変更してしまうと、DjangoからMySQL接続する際に下記のエラーが発生しますので注意してください。

django.db.utils.InternalError: (1018, "Can't read dir of './django/' (errno: 13 - Permission denied)")

settings.py の編集

webコンテナ内のDjangoプロジェクトからdbコンテナ内のMySQLに接続するために、settings.pyのDATABASESを書き換えます。

$ vi mysite/settings.py

---
import pymysql
pymysql.install_as_MySQLdb()
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django',
        'USER': 'django',
        'PASSWORD': 'P@ssw0rd_django',
        'HOST': 'db',
        'PORT': 3306,
        'OPTIONS': {
            'charset': 'utf8mb4',
        },
    }
}
---

DBマイグレーション

Djangoのデフォルトアプリケーションのテーブルを作成します。 デフォルト以外のアプリケーションが追加されていないのであれば、makemigrationsは不要です。

$ docker-compose run web ./manage.py makemigrations
$ docker-compose run web ./manage.py migrate

管理者ユーザの作成

Django管理サイトにログインするためのスーパーユーザを作成します。

$ docker-compose run web ./manage.py createsuperuser --username admin --email admin@localhost

[自動化する場合]
$ docker-compose run web ./manage.py shell -c "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@localhost', 'admin')"

Django開発サーバの起動

webコンテナをdocker-composeで起動し、Djangoの開発サーバを起動します。

$ docker-compose up -d

ブラウザで動作確認

下記URLにアクセスして、作成したスーパーユーザで管理サイトにログインできることを確認します。

http://localhost:8000/admin

その他参考手順

バックグラウンドで起動したコンテナの出力を確認

フォアグラウンドで起動した際に出力されるログを表示させます。

[すべてのコンテナ]
$ docker-compose logs -tf

[webのみ]
$ docker-compose logs -tf web

[dbのみ]
$ docker-compose logs -tf db

DBを作成し直す場合の手順

$ docker-compose down
$ sudo rm -rf db-datadir
$ docker-compose up -d db
$ docker-compose run web ./manage.py makemigrations
$ docker-compose run web ./manage.py migrate
$ docker-compose run web ./manage.py shell -c "from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@localhost', 'admin')"
$ docker-compose up -d

Dockerコンテナ、イメージ削除一括方法

$ docker container rm $(docker container ls -q)
$ docker image rm $(docker image ls -q)

まとめ

Dockerの公式ページのDjangoチュートリアルMySQL版をやってみました。

次は、ApahceかNginxでプロキシサーバを追加し、uWSGIでDjangoを起動させてよりプロダクション環境に近い構成を作ってみたいと思います。

参考

今回利用したDockerImage