使用Docker在Nginx、uWSGI和Python(Django)的环境中创建容器
这篇文章是Web Crew Advent Calendar 2019第16天的文章。
昨天是@Hideto-Kiyoshima-wc先生的Scala的Option/Either/Try超入门。
首先
我是@yagiyuuuu,在株式会社ウェブクルー担任两年的新入社员。目前正在使用Docker构建Nginx + uWSGI + Python(Django)的应用环境进行开发。我希望这篇文章能对将要使用Django进行应用开发的人提供帮助。
安装Docker for Windows
打开控制面板,找到「程序和功能」->「启用或关闭Windows功能」-> 检查是否选中了「Hyper-V」。
如果没有选中,则勾选并重新启动计算机以启用它。
然后进行「Docker Desktop for Windows」的安装。
您可以从这里进行安装。
搭建Django的运行环境
目录结构
建设基础设施
我們將在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 – 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
创建应用程序
由于这里专注于创建应用程序,所以有关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()
应用程序开发
在Django-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负责。请多多关照。