docker-composeでdjango環境を作ってみる(MariaDB + Nginx + uWSGI)


はじめに

qiita初投稿です。
何か間違っているところがあったら、コメントしていただけると嬉しいです〜
2019/12/18に一部修正

  • mac mojave
  • docker-engine 19.03.5
  • compose 1.24.1
  • python3.8
  • Django 3
  • mariadb 10.1
  • nginx 1.13

Pycharm使ってます。

ディレクトリ

ディレクトリはこんな感じ

.
├── db
│   ├── data
│   └── sql
│       └── init.sql
├── docker-compose.yml
├── nginx
│   ├── conf
│   │   └── app_nginx.conf
│   ├── log
│   └── uwsgi_params
├── python
│   ├── Dockerfile
│   └── requirements.txt
├── src
│   └── project
│       ├── app
│       ├── project
│       └── manage.py
│       └── uwsgi.ini
└── static

データベース

MariaDBを使います。
dbディレクトリのなかにdataフォルダと初期化用のinit.sql作成。

CREATE DATABASE IF NOT EXISTS app CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY 'root';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'%';

FLUSH PRIVILEGES;

githubにあげる時は、.gitigonreに入れるなどしてpassword等は見えないように。

dockerfileは作らず、docker-compose.ymlの方に書きます。

Nginx

画像等の静的ファイルをリバースプロキシサーバーであるnginxに飛ばします。

app_nginx.conf

upstream django {
    ip_hash;
    server python:8001;
}

# configuration of the server
server {
    # the port your site will be served on
    listen      8000;
    # the domain name it will serve for
    server_name 127.0.0.1; # substitute your machine's IP address or FQDN
    charset     utf-8;

    # max upload size
    client_max_body_size 75M;   # adjust to taste

    location /static {
        alias /static;
    }


    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include /etc/nginx/uwsgi_params; # the uwsgi_params file you installed
    }
}

まずはアクセスがあったらnginxの8000番ポートで受け止め、静的ファイル static にアクセスがあったときはリバースプロキシサーバーであるnginxのstaticに飛ばし、他は8001ポートのアプリケーションサーバ(uWSGI)に飛ばします。

uwsgi_params

uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

paramsはコピペでオッケ

python

Dockerfile/python


# The first instruction is what image we want to base our container on
# We Use an official Python runtime as a parent image
FROM python:3.8-alpine
# The enviroment variable ensures that the python output is set straight
# to the terminal with out buffering it first
ENV PYTHONUNBUFFERED 1
ENV PYTHONIOENCODING utf-8
ENV APP_PATH  code
# Set the working directory to /code
WORKDIR /$APP_PATH
COPY ./requirements.txt /$APP_PATH
# Install any needed packages specified in requirements.txt
RUN apk add --no-cache --virtual .build-deps bash gcc musl-dev libffi-dev \
 g++ libgcc libstdc++ libxml2-dev libxslt-dev openssl-dev curl \
 && apk add --no-cache --virtual --update-cache\
 jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev \
 mariadb-dev mariadb-connector-c-dev \
 && pip install cython && pip install -U pip && pip install -r requirements.txt
 # Make alpine lighter
RUN rm -rf /var/cache/apk/* && \
    rm -rf /tmp/*

apk add しているところで改行や区切り方次第でインストールエラー多発
動いたので現状これでよしということで、、、

Django==3.0
flake8==3.7.9
ipython==7.10.1
mysqlclient==1.4.6
Pillow==6.2.1
uWSGI==2.0.18

コードチェックしてくれるflake8とpythonのインタプリタを強力にしたipythonも入れておきます。
データベース接続はいくつもドライバーがありますが、公式推奨のmysqlclientを使います。
https://docs.djangoproject.com/ja/3.0/ref/databases/#mysql-db-api-drivers

docker-compose.yml


version: '3.4'
services:
  nginx:
    image: nginx:1.13
    container_name: app_nginx
    ports:
      - "8000:8000"
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d
      - ./nginx/uwsgi_params:/etc/nginx/uwsgi_params
      - ./static:/static
      - ./nginx/log:/var/log/nginx
    depends_on:
      - python
  db:  # the same name as 'host' in DATABASES setting, otherwise Django won't find the database
    image: mariadb:10.1
    container_name: app_mariadb
    ports:
      - 3306:3306
    environment:
      MYSQL_DATABASE: app
      MYSQL_ROOT_USER: root
      MYSQL_ROOT_PASSWORD: root
      TZ: 'Asia/Tokyo'
    volumes:
      - ./db/data:/var/lib/mysql
      - ./db/sql:/docker-entrypoint-initdb.d
  python:
    build: ./python
    image: python_blog
    container_name: app_python
    command: uwsgi --ini /code/project/uwsgi.ini
    volumes:
      - ./src:/code
      - ./static:/static
    expose:
      - "8001"
    depends_on:
      - db 

サービス名のdbとdjangoのsettings.pyのdb設定のhostのdbを一致させる。


ここまでいったら
docker-compose.ymlのあるところで

$ docker-compose up -d --build

コンテナを立ち上げてみます。
nginxとpythonコンテナが立ち上がりません 嗚呼


command: uwsgi --ini /code/project/uwsgi.ini

uwsgi.iniがまだないのでdjangoプロジェクトを作り配置します。

$ docker-compose run --rm python django-admin.py startproject project

djangoプロジェクトを作成する。
pythonの部分はdocker-compose.ymlのサービス名
--rmをつけないとpythonコンテナがたくさんできてしまうのでrunさせるごとに消してく。

[uwsgi]
socket = :8001
module = project.wsgi
wsgi-file = /code/project/project/wsgi.py
logto = /code/project/project/uwsgi.log
chdir=/code/project
py-autoreload = 1

uwsgi.iniを配置して

$ docker-compose down
$ docker-compose up -d
$ docker ps -a

全コンテナが立ち上がっていると思われる

$ docker exec -it app_python /bin/bash
$ cd ./project/
$ python manage.py startapp app

python環境はalpine linuxで作っていて、alpineにbashは入っていないから /bin/sh か /bin/ash。
今回はbashを入れてるのでbash
djangoのアプリを作る

django内の設定

settings.py


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app.apps.AppConfig',  # 追加


# 変更
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'app',
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': 'db',
        'PORT': '3306',
        'OPTIONS': {
            'charset': 'utf8mb4',
        },
    }

# お好みで変更
LANGUAGE_CODE = 'ja'

TIME_ZONE = 'Asia/Tokyo'


STATIC_ROOT = './../../../static/'  # 本番環境用の配信用の大元
STATIC_URL = '/static/'  # 本番環境で使われるurl

# Custom Useer
AUTH_USER_MODEL = 'app.User'

migrateをする前に公式によるととりあえず、カスタムユーザー作れってあるから
カスタムユーザーを作る
https://docs.djangoproject.com/ja/3.0/topics/auth/customizing/#using-a-custom-user-model-when-starting-a-project

models.py

from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    pass

admin.py

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin

from .models import User

admin.site.register(User, UserAdmin)

dockerコンテナ内で

$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py createsuperuser

http://localhost:8000/
djangoが立ち上がっているはず
サーバー内エラーが起きていたらdocker-compose up し直してみる

migrateしたらdjango admin用のユーザーを作る
http://localhost:8000/admin/  djangoadminにアクセス
uwsgiを使っているのでcssが効いてないので


$ python manage.py collectstatic

django adminにもcssがきく

これで開発をできるようになるはず。。。

参考

Docker-ComposeでPython3.6+NGINX+MariaDB10+uWSGIのDjango環境欲張りセット