Django

【Django】WSL2とDockerで開発環境をつくる|ベストプラクティス備忘録

PythonのフルスタックWEBフレームワーク、Djangoを使って開発を始めるまでの準備に関する備忘録です。
完全に僕の環境に特化した構成になってますので、ベストプラクティスとは限りませんことを事前にご了承ください。

内容については、新たな知識を得たり、ツールが古くなったりした場合は随時更新していく予定です。
すべての備忘録のまとめはこちらに記載されています。

今回の環境構築備忘録は、MocratというSlackBOTを開発するために構築した環境をベースにしています。

本備忘録に書かれた設定を実施した後の状態は、以下のリポジトリに保存しております。

mocrat-setup-sample

最終的なディレクトリツリーは以下のとおりです。

ubuntu@ThinkPad:~/mocrat$ tree
.
├── Makefile
├── README.md
├── db
│   └── Dockerfile
├── docker-compose.yml
└── main
    ├── Dockerfile
    ├── entrypoint.sh
    ├── mocrat
    │   ├── manage.py
    │   ├── mocrat_config
    │   │   ├── __init__.py
    │   │   ├── asgi.py
    │   │   ├── local_settings.py
    │   │   ├── production_settings.py
    │   │   ├── settings.py
    │   │   ├── urls.py
    │   │   └── wsgi.py
    │   ├── mocrat_main
    │   │   ├── __init__.py
    │   │   ├── admin.py
    │   │   ├── apps.py
    │   │   ├── migrations
    │   │   │   └── __init__.py
    │   │   ├── models.py
    │   │   ├── tests.py
    │   │   ├── urls.py
    │   │   └── views.py
    │   ├── mocrat_user
    │   │   ├── __init__.py
    │   │   ├── admin.py
    │   │   ├── apps.py
    │   │   ├── management
    │   │   │   └── commands
    │   │   │       └── custom_create_superuser.py
    │   │   ├── migrations
    │   │   │   └── __init__.py
    │   │   ├── models.py
    │   │   ├── tests.py
    │   │   └── views.py
    │   ├── static
    │   │   ├── images
    │   │   ├── js
    │   │   └── mocrat_main
    │   └── templates
    │       ├── base.html
    │       └── mocrat_main
    └── requirements.txt

16 directories, 33 files

もくじ

  1. 今回使用する環境について
  2. Dockerコンテナを設定する
  3. コンテナをビルドしてDjangoを設定する
  4. 設定ファイルを分ける
  5. カスタムユーザを作成してスーパーユーザを作成
  6. Djangoの管理サイトにログインする
  7. django-debug-toolbarのセットアップ
  8. まとめ

今回使用する環境について

まず、使用する環境について以下にまとめていきます。

今回使用している環境は以下のとおりです。

OS: WSL2-Ubuntu18.04 (Windows10 Home)
CPU: Corei7-8550U
RAM: 16GB
エディタ: VSCode
仮想化: Docker
バージョン管理: git
言語: Python
データベース:PosgreSQL
フレームワーク: Django
デプロイ先: Heroku(予定)

今回はWindows上のWLS2にDocker環境を構築します。

WSL2とは、従来のWSLにLinuxのフルカーネルを搭載したもので、Windows10の2004以降の標準で利用可能です。
このWSL2ですが、Lunuxのカーネルが動いているため、普通にDocker環境を構築することができます。

Windows10Homeの環境ではDocker for Windowsは動きませんが、この方法ならDocker環境を構築できます。
設定方法は以下のページに記載しておきます。

さて、WSL上にてDockerのセットアップが完了したら、mainディレクトリにDockerfileを作成します。
Dockerfileには以下の内容を書きます。

aptでpostgresql-clientをインストールしているのは、バックエンドのDBにPostgreSQLを使用するためです。
また、gosuはGO言語で書かれたsudoのようなもので、entrypointを使用してUIDとGIDを変更するためにインストールしています。

FROM python:3.7
ENV PYTHONUNBUFFERED 1

RUN apt update && apt install gosu postgresql-client -y

COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

RUN mkdir -p /usr/mocrat/app
ENV HOME=/usr/mocrat/app
WORKDIR $HOME

RUN apt update && apt upgrade -y

#コンテナ
ADD requirements.txt $HOME
RUN pip install -r requirements.txt

さて、上記でさらっと「UIDとGIDを変更する」と書きましたが、これはどういうことでしょうか。
DockerコンテナにアタッチしてDjango環境を構築する前に、コンテナ環境とホスト環境のUIDとGIDを揃える必要があります。

コンテナ側のUIDとGIDがホスト側のものと異なる場合、コンテナ側とホスト側でファイルの編集を相互に行えなくなります。

この問題の解消方法は以下にまとめてありますのでご確認ください。

Dockerコンテナを設定する

さて、これでmain側のDockerFileの設定が完了しました。

ちなみにですが、今回SlackAPIのためのDjango環境を作成するにあたって、以下のモジュールをpip installさせています。
これについてはrequirements.txtを参照してください。

  django
  gunicorn
  django-debug-toolbar
  djangorestframework
  django-allauth
  django-filter
  django-environ

さて、次にdb側のコンテナも設定しましょう。
PostgreSQLのコンテナを作成する方法は以下の記事にまとめました。

mainとdbのDockerfileを用意できたら、DockerComposeでコンテナをビルドします。

親ディレクトリにdocker-compose.ymlファイルを用意して、以下の内容を記載します。

この際、PostgreSQLの設定項目などは、.envファイルに分離して、バージョン管理から除外しております。

version: "3"
services:
  main:
    build:
      context: ./main
      dockerfile: Dockerfile
    container_name: mocrat_main
    volumes:
      - ./main:/usr/mocrat/app
    ports:
      - "8000:8000"
    tty: true
    stdin_open: true
    #これはDjanoの設定が終わったら使用する
    #command: python3 ./mocrat/manage.py runserver 0.0.0.0:8000

  db:
    build:
      context: ./db
      dockerfile: Dockerfile
    container_name: mocrat_db
    ports:
      - "5432:5432"
    env_file:
      - ./.env
    volumes:
      - ./db:/docker-entrypoint-initdb.d

.envファイルは、docker-compose.ymlと同じ階層に作成します。
内容は以下のようにしておきましょう。

DBの名前やパスワードなどは好きに変更してください。

POSTGRES_USER=postgres
POSTGRES_PASSWORD=Password
PGPASSWORD=Password
POSTGRES_DB=mocrat_db
DATABASE_HOST=localhost

コンテナをビルドしてDjangoを設定する

では、早速コンテナをビルドし、main側のコンテナのbashにログインしましょう。

以下のコマンドでOKです。
ただし、基本操作についてはmocrat-setup-sampleのMakefileにまとめてあるので、そちらを使うと便利かと。

docker-compose up -d --build
docker-compose run --rm mocrat_main bash

mocrat_main側のコンテナにアクセスできたら以下のコマンドを実行します。
django-adminのstartprojectは、引数で名前と「.」を使用することで、プロジェクト名と設定ディレクトリの名前を分けることができます。

mkdir mocrat
cd mocrat
django-admin startproject mocrat_config .

次に、アプリケーションを作成します。

python3 manage.py startapp mocrat_main

次に、静的ファイルやローカル用の設定ファイルなど、もろもろをまとめて作成していきます。
custom_create_superuser.pyとは、スーパーユーザを簡単に作成できるようにするためのカスタムコマンドです。

mkdir static
mkdir static/js
mkdir static/images
mkdir static/mocrat_main

mkdir templates
mkdir templates/mocrat_main
touch templates/base.html

touch .env
touch mocrat_config/local_settings.py
touch mocrat_config/production_settings.py
touch mocrat_main/urls.py

mkdir mocrat/mocrat_main/management
mkdir mocrat/mocrat_main/management/comands
touch mocrat/mocrat_main/management/comands/custom_create_superuser.py

さて、ここまで来たら再度Dockerコンテナをビルドしなおして、作成したDBコンテナにmocrat_mainコンテナから接続できることを確認します。

コンテナ間の通信の場合は、コンテナ名を指定してあげることで接続が可能になります。
今回はdbコンテナに接続します。

docker attach mocrat_main
PGPASSWORD=Password psql -h db -U postgres

無事にログインできればセットアップは完了です!

設定ファイルを分ける

無事にコンテナが立ち上がったらDjangoのスーパーユーザを作成して管理サイトにログインできるようにしていきます。

その前に、まず設定ファイルを確認しましょう。
Djangoの設定ファイルは、startprojectコマンドで作成したディレクトリにあるsettings.pyという名前のファイルです。

まずは、作成したアプリケーションや、インストールしているプラグインを追記して上げましょう。
基本的な設定については割愛するので、DjangoTutorialなどで確認してみてください。

この設定ファイルですが、基本的にローカル用の設定ファイルと本番環境用の設定ファイルを分離して、ローカル用の設定ファイルをバージョン管理から除外することがベストプラクティスとされてます。

そこで、共通部の設定をまとめるメインのsettings.pyとは別に、local_settings.pyとproduction_settings.pyというファイルを作成しました。

今回はproduction_settings.pyは編集せず、local_settings.pyのみ書き換えていきます。

まず、メインのsettings.pyに以下のコードを追記します。
これによって、DEBUGがTrueになっている時は、local_settingsの内容を読み込むようになります。

# SECURITY_KEYをコメントアウトする
# SECRET_KEY = ''

"""
以下の3つは設定を分けたいので、削除しておく

INSTALLED_APPS
MIDDLEWARE
DATABASES
"""

#Add settings
AUTH_USER_MODEL = 'mocrat_user.User'

# Logging
#TODO:本番環境用のロギングを実装する

#Divide local settings
if DEBUG:
    try:
        from .local_settings import *
    except ImportError:
        pass
else:
    try:
        from production_settings import *
    except ImportError:
        pass

次に、local_settings.pyに以下の内容を追記します。
結構色々追記していてわかりづらいですがご容赦ください。

セキュリティキーは、Githubなどで公開したくないので、ローカル用の設定ファイルに書き込みます。

また、ロギングやプラグインのための設定も追記してありますので、使用しない場合は削除してください。

DEBUG = True

ALLOWED_HOSTS = ['*']

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '適当なセキュリティキー'

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    #plugins
    # 'django.contrib.admindocs',
    # 'django.contrib.sites',
    # 'django_filters',
    # 'allauth',
    # 'allauth.account',
    # 'allauth.socialaccount',
    # 'rest_framework',
    'debug_toolbar',
    #custom apps
    'mocrat_main',
    'mocrat_user',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    #plugins
    'debug_toolbar.middleware.DebugToolbarMiddleware',
]

# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'mocrat_db',
        'USER': 'postgres',
        'PASSWORD': 'Password',
        'HOST': 'db',
        'PORT': '5432',
    }
}

#Debug tool bar
def show_toolbar(request):
    return True

DEBUG_TOOLBAR_CONFIG = {
    'SHOW_TOOLBAR_CALLBACK': show_toolbar,
}

INTERNAL_IPS = ['127.0.0.1']

#Logging
#TODO:ロギングのベストプラクティスを検討する
#https://qiita.com/okoppe8/items/b56499fc04e6c2193b9d
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'local': {
            'format': '%(asctime)s [%(levelname)s] %(pathname)s:%(lineno)d %(message)s'
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'local',
        },
    },
    'loggers': {
        # 自作したログ出力
        '': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
        # Djangoのエラー・警告・開発WEBサーバのアクセスログ
        'django': {
            'handlers': ['console'],
            'level': 'INFO',
            'propagate': False,
        },
        # 実行SQL
        'django.db.backends': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False,
        },
    }
}

さて、これでもろもろの設定が完了しました。

カスタムユーザを作成してスーパーユーザを作成

Djangoのベストプラクティスとしては、デフォルトではなくカスタムユーザを作成して使用することが推奨されています。

カスタムユーザを作成してスーパーユーザを作成するまでの流れは以下にまとめてあります。

Djangoの管理サイトにログインする

では、Djangoの設定もユーザの作成も完了したので、管理サイトにログインしましょう。

Dockerコンテナを設定するで設定したDockerfileには、コンテナ起動時にWEBサーバを立ち上げるコマンドがすでに埋め込まれています。

しかし、このままhttp://localhost:8000/adminにアクセスしても、管理サイトは開きません。
WSL上のDockerにlocalhostでアクセスする場合は、以下の設定を実施する必要があります。

とはいえ、localhostForwarding=Trueという設定を書き込むだけなので非常に簡単です。
WSL2はこんなシンプルな設定でホストからコンテナにlocalhost接続できるようになるんですね。めっちゃ簡単!

django-debug-toolbarのセットアップ

そして、デバッグに必須なdjango-debug-toolbarをセットアップしましょう。

しかし、コンテナを立ち上げた際にすでにインストールは完了しているため、後は簡単な設定のみです。
詳しいやり方は以下を参照してください。

まとめ

今回は、今後のDjango開発の際の環境構築が楽になるように、試行錯誤した結果についてまとめていく備忘録です。
またアップデートがあれば適宜追記・編集していこうと思います。

環境構築にあたっては、Udemyのプログラミング初心者でも安心、Python/Django入門講座『現場で使えるDjangoの教科書』『自走プログラマー』などの書籍を参考にしました。

特に、『現場で使えるDjangoの教科書』『自走プログラマー』は、独学では中々得られない開発現場のノウハウやベストプラクティスについて大いに参考になりました。

一通りチュートリアルなどを終えて、中級レベルにステップアップしたい方におすすめの本です。

COMMENT

メールアドレスが公開されることはありません。