この記事はウェブクルー Advent Calendar 2019の16日目の記事です。
昨日は@Hideto-Kiyoshima-wcさんのScalaのOption/Either/Try超入門でした。
はじめに
株式会社ウェブクルーに新卒で入社して、2年目の@yagiyuuuuです。
現在、Nginx + uWSGI + Python(Django)のアプリ環境をDockerで作成して、開発をしています。
これから、Djangoでアプリ開発をする人の助けになればと思い、この記事を書きました。
Docker for Windowsのインストール
コントロールパネルを開いて、
「プログラムと機能」→「Windowsの機能を有効化または無効化」→「Hyper-V」にチェックが入っているか確認します。
チェックが入っていなかった場合は、チェックを入れてPCを再起動させて有効化させます。
次に「Docker Desktop for Windows」のインストールをする。
インストールはここからできます。
Djangoを動かす環境構築
ディレクトリ構成
Infrastrcuture作成
Alpineにpython + uWSGI、Nginxをインストールします。
docker-compose.yml作成
Nginxとpython + uWSGIのコンテナを作成します。
今回はログをdjango-sample配下に出力するようにしていますが、お好きなところにログを吐き出すように設定してください。
version: '2'
services:
nginx:
build: "./Infrastructure/nginx/"
volumes:
- ./logs/nginx:/var/log/nginx
ports:
- "80:80"
networks:
django-sample-network:
ipv4_address: 172.23.0.4
python:
build: "./Infrastructure/python/"
volumes:
- ./Application/django-sample:/home/work/django-sample
- ./logs/django:/home/work/django
- ./logs/uwsgi:/home/work/uwsgi
ports:
- "8000:8000"
networks:
django-sample-network:
ipv4_address: 172.23.0.5
networks:
django-sample-network:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.23.0.0/24
Dockerfile作成
Nginx
FROM nginx:1.13.1-alpine
COPY work/nginx.conf /etc/nginx
RUN apk --no-cache add tzdata && \
cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
apk del tzdata
CMD ["nginx", "-g", "daemon off;"]
uWSGI
FROM python:3.7
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo
RUN mkdir /home/work
RUN mkdir /home/work/django
RUN mkdir /home/work/uwsgi
COPY work/ /home/work
WORKDIR /home/work
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
CMD ["uwsgi", "--ini", "/home/work/uwsgi.ini"]
Nginxの設定
worker_processes auto;
error_log /var/log/nginx/error_app.log;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access_app.log main;
sendfile on;
tcp_nopush on;
keepalive_timeout 120;
proxy_read_timeout 120;
proxy_send_timeout 120;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80 default_server;
server_name _;
fastcgi_read_timeout 60s;
client_max_body_size 1m;
location ~ ^/app/ {
add_header Cache-Control no-cache;
include uwsgi_params;
uwsgi_pass 172.23.0.5:8000;
uwsgi_read_timeout 60s;
}
}
}
uWSGI + Djangoの設定
[uwsgi]
chdir=/home/work/django-sample
module=django-sample.wsgi
master=True
vacuum=True
max-requests=5000
socket=:8000
py-autoreload=1
logto=/home/work/uwsgi/django-app.log
buffer-size=10240
log-format=%(addr) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size)`` "%(referer)" "%(uagent)"
django==2.2
uwsgi==2.0.17.1
requirements.txt
にインストールしたいモジュールを記載します。
.envファイル作成
COMPOSE_FILE=docker-compose.yml
Application作成
ここではアプリを作成することに焦点を当てていますので、
Djangoアプリの詳細に関しては、公式サイトなどをみていただきたいです。
また、__init__.py
と__pycache__
にはコードを書きませんが、作成をしてください。
作成されていないとアプリが動かなくなってしまいます。
プロジェクト作成
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django-sample.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
"""
Django settings for django-sample project.
Generated by 'django-admin startproject' using Django 2.0.3.
For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""
import os
import json
import traceback
# ログ出力で仕様するハンドラを指定する
LOG_HANDLER = ["app"]
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'ekf!&30u3&idt-qr3250(t+j#%@(vyxr02c-7fj!a81$!)#q=('
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
# 接続を許可するサーバのIPやドメインを設定する
# 何も設定していない場合は、ローカルホスト(localhost)からの接続のみ可能な状態
ALLOWED_HOSTS = ["localhost"]
# Application definition
# 「app」を追加。これを追加しないとtemplatetagsに定義したカスタムタグが認識されない
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app',
]
ROOT_URLCONF = 'django-sample.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'django-sample.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/
#LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'ja'
#TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Tokyo'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/
STATIC_URL = ''
LOGGING = {
'version': 1,
'formatters': {
'app': {
'format': '%(asctime)s [%(levelname)s] %(pathname)s:%(lineno)d %(message)s'
}
},
'handlers': {
'app': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler',
'filename': '/home/work/django/app.log',
'formatter': 'app',
'when': 'D', # 単位 Dは日
'interval': 1, # 何日おきか指定
'backupCount': 30, # バックアップ世代数
}
},
'loggers': {
'django': {
'handlers': ['app'],
'level': 'DEBUG',
'propagate': True,
},
'django.server': {
'handlers': ['app'],
'level': 'DEBUG',
'propagate': True,
},
'app': {
'handlers': LOG_HANDLER,
'level': 'DEBUG',
'propagate': True,
},
},
}
# セッションエンジンの設定
# cookieを用いたセッションを使用する
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'
# ログイン状態の有効期限(秒)
# ここに指定した有効期限(秒)を超えるまでログイン状態を保つ事ができる
# セッション自体の有効期限はSESSION_COOKIE_AGE
# 8h * 60m * 60s
LOGIN_LIMIT = 28800
# セッションの有効期間(秒)
# 利用者毎にセッション有効期間を変えたい場合は、request.session.set_expiry(value)を用いる
SESSION_COOKIE_AGE = 1800
"""django-sample URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.urls import path, include
urlpatterns = [
path('app/', include("app.urls")),
]
"""
WSGI config for django-sample project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django-sample.settings")
application = get_wsgi_application()
アプリ作成
djnago-sample
プロジェクト内にアプリを作成します。
from django.urls import path
from app.views.login import view as login_view
urlpatterns = [
path("", login_view.top, name="login_top")
]
from django.http import HttpResponse
from django.http.request import HttpRequest
from django.template import loader
def top(request: HttpRequest):
template = loader.get_template("login/index.html")
return HttpResponse(template.render({}, request))
画面表示させるテンプレート作成
Hello Django!!
コンテナを立ち上げる
docker-compose.yml
がある階層で以下コマンドを叩く
コンテナのビルド、起動
$ docker-compose up --build -d
-d
をつけることでバックグラウンドで起動できる
コンテナを確認する
$ docker-compose ps
コンテナを削除する
$ docker-compose down
作成したアプリにアクセスする
コンテナを起動したら、http://localhost/app/
にアクセスすると
Hello Django!!
が表示される
終わりに
Djangoアプリを作成していく上で、自分好みの環境にしていってください!!
明日の記事は@yuko-tsutsuiさんです。
よろしくお願いします。