Créer un environnement de Nginx + uWSGI + Python (Django) avec docker

Cet article est l'article du 16e jour du Web Crew Advent Calendar 2019. Hier, c'était @ Hideto-Kiyoshima-wc Scala's Option / Either / Try Super Introduction.

introduction

Je suis @yagiyuuuu pour la deuxième année depuis que j'ai rejoint Web Crew Co., Ltd. en tant que nouveau diplômé. Actuellement, je développe un environnement d'application de Nginx + uWSGI + Python (Django) en le créant avec Docker. J'ai écrit cet article dans l'espoir qu'il aidera les personnes qui développent des applications avec Django.

Installez Docker pour Windows

Ouvrez le panneau de contrôle, Assurez-vous que "Programmes et fonctionnalités" -> "Activer ou désactiver les fonctionnalités Windows" -> "Hyper-V" est coché. S'il n'est pas coché, vérifiez-le et redémarrez le PC pour l'activer. Ensuite, installez "Docker Desktop pour Windows". Vous pouvez l'installer à partir d'ici (https://docs.docker.com/docker-for-windows/install/).

Créer un environnement pour exécuter Django

Structure du répertoire

Ci-dessous, exécutez l'application Django avec la configuration. image.png

Création d'infrastructures

Installez python + uWSGI, Nginx sur Alpine.

Créer docker-compose.yml

Créez un conteneur pour Nginx et python + uWSGI. Cette fois, le journal est sorti sous django-sample, mais veuillez le configurer pour qu'il crache le journal où vous le souhaitez.

django-sample/docker-compose.yml


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

Créer Dockerfile

Nginx

django-sample/Infrastructure/nginx/Dockerfile


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

django-sample/Infrastructure/python/Dockerfile


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"]

Paramètres Nginx

django-sample/Infrastructure/nginx/work/nginx.conf


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;
        }
    }
}

Paramètres uWSGI + Django

django-sample/Infrastructure/python/work/uwsgi.ini


[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-sample/Infrastructure/python/work/requirements.txt


django==2.2
uwsgi==2.0.17.1

Décrivez le module que vous souhaitez installer dans requirements.txt.

Créer un fichier .env

django-sample/.env


COMPOSE_FILE=docker-compose.yml

Création d'applications

Puisque nous nous concentrons sur la création d'applications ici, Pour plus d'informations sur l'application Django, veuillez consulter le site officiel. Aussi, n'écrivez pas de code dans «__init __. Py» et «pycache», mais créez-les. S'il n'est pas créé, l'application ne fonctionnera pas.

Création de projet

django-sample/Application/django-sample/manage.py


#!/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-sample/Application/django-sample/django-sample/settings.py


"""
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

#Spécifiez le gestionnaire utilisé pour la sortie du journal
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

#Définissez l'adresse IP et le domaine du serveur qui autorise la connexion
#Hôte local si rien n'est défini(localhost)Connexion possible uniquement depuis
ALLOWED_HOSTS = ["localhost"]

# Application definition
#Ajout de "app". Si vous ne l'ajoutez pas, les balises personnalisées définies dans les balises de modèle ne seront pas reconnues.
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',        #L'unité D est le jour
            'interval': 1,      #Précisez tous les quelques jours
            'backupCount': 30,  #Nombre de générations de sauvegarde
        }
    },
    'loggers': {
        'django': {
            'handlers': ['app'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'django.server': {
            'handlers': ['app'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'app': {
            'handlers': LOG_HANDLER,
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

#Paramètres du moteur de session
#Utiliser une session avec des cookies
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'

#Date d'expiration de l'état de connexion (secondes)
#Vous pouvez rester connecté jusqu'à ce que la date d'expiration (secondes) spécifiée ici soit dépassée.
#La date d'expiration de la session elle-même est SESSION_COOKIE_AGE
# 8h * 60m * 60s
LOGIN_LIMIT = 28800

#Durée de vie de la session(Secondes)
#Si vous souhaitez modifier la période de validité de la session pour chaque utilisateur, demandez.session.set_expiry(value)Utilisation
SESSION_COOKIE_AGE = 1800

django-sample/Application/django-sample/django-sample/urls.py


"""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")),
]

django-sample/Application/django-sample/django-sample/wsgi.py



"""
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()

Création d'applications

Créez une application dans le projet django sample.

django-sample/Application/django-sample/app/urls.py



from django.urls import path

from app.views.login import view as login_view

urlpatterns = [
    path("", login_view.top, name="login_top")
]

django-sample/Application/django-sample/app/views/login/view.py


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))

Créer un modèle à afficher à l'écran

django-sample/Application/django-sample/templates/login/index.html


Hello Django!!

Lancer le conteneur

Tapez la commande suivante dans la hiérarchie où se trouve docker-compose.yml

Construire et démarrer le conteneur

$ docker-compose up --build -d

Peut être démarré en arrière-plan en ajoutant -d

Vérifiez le conteneur

$ docker-compose ps

Supprimer le conteneur

$ docker-compose down

Accéder à l'application créée

Après avoir démarré le conteneur, allez sur http: // localhost / app / «Hello Django !!» s'affiche

À la fin

Veuillez créer votre propre environnement lors de la création d'applications Django! !!

L'article de demain est @ yuko-tsutsui. Je vous remercie.

Recommended Posts

Créer un environnement de Nginx + uWSGI + Python (Django) avec docker
Créer un environnement django avec docker-compose (MariaDB + Nginx + uWSGI)
[Python] Créer un environnement de développement Django avec Docker
Préparer l'environnement python3 avec Docker
Construire un environnement Mysql + Python avec docker
Créez un environnement de développement Django avec Docker! (Docker-compose / Django / postgreSQL / nginx)
Créez un environnement de développement Python simple avec VSCode et Docker Desktop
Créer une application Todo avec Django ① Créer un environnement avec Docker
Créer un environnement Jupyter Lab (Python) avec Docker
[Python] Créez un environnement virtuel avec Anaconda
Construction du serveur d'exécution Python (Python + uWSGI + Django + Nginx)
Environnement de lancement avec LineBot + Heroku + Docker + Python
Construire un environnement de NGINX + NGINX Unit + MySQL avec Docker
Django 1.11 a démarré avec Python3.6
Préparer l'environnement d'exécution de Python3 avec Docker
Conversion de l'environnement Django en Docker (Docker + Django + Gunicorn + nginx) Partie 2
Non bloquant avec Python + uWSGI
Créer un environnement virtuel avec conda avec Python
Créer un environnement de construction python3 avec Sublime Text3
Hello World avec nginx + uwsgi + python sur EC2
Utiliser python avec docker
environnement python avec docker-compose
Créer un environnement Python
WebSocket avec Python + uWSGI
Créez rapidement un environnement Python Django avec IntelliJ
Créez rapidement un environnement d'exécution d'application Web Python3.4 + Nginx + uWSGI + Flask en utilisant pyenv sur Ubuntu 12.04
Environnement virtuel avec Python 3.6
[Docker] Créez un environnement jupyterLab (python) en 3 minutes!
Conversion de l'environnement Django en Docker (Docker + Django + Gunicorn + nginx) Partie 3
Modèle de construction d'environnement de développement local Python [Flask / Django / Jupyter avec Docker + VS Code]
Construction d'environnement virtuel avec Docker + Flask (Python) + notebook Jupyter
Pour pouvoir utiliser le japonais avec Python dans l'environnement Docker
Créez un environnement de développement python avec vagrant + ansible + fabric
Lancer une application Web Python sur Nginx + Gunicorn avec Docker
Comment créer un environnement Django (python) sur Docker
Déployer une application existante avec docker + pyenv-virtualenv + uwsgi + django
Application Web réalisée avec Python3.4 + Django (Construction de l'environnement Part.1)
Créer une couche pour AWS Lambda Python dans Docker
Un mémo sur la création d'une application Django (Python) avec Docker
Créez un environnement de développement avec Poetry Django Docker Pycharm
Faites Django avec CodeStar (Python3.6.8, Django2.2.9)
Créer un environnement avec virtualenv
Environnement de site Web de configuration minimale avec django
Installer l'environnement Python avec Anaconda
Créer une API avec Django
Gérez l'environnement python avec virtualenv
Créez rapidement un environnement d'exécution d'application Web Python3.4 + Nginx + uWSGI + Flask en utilisant venv sur Ubuntu 14.04 LTS
Faites Django avec CodeStar (Python3.8, Django2.1.15)
Créer un gif 3D avec python3
API avec Flask + uWSGI + Nginx
Python3 + Django ~ Mac ~ avec Apache
Création de liste de tâches [Python Django]
Premiers pas avec Python Django (1)
Créer une page d'accueil avec django
Premiers pas avec Python Django (4)