Help us understand the problem. What is going on with this article?

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環境欲張りセット

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした