Create Nginx + uWSGI + Python (Django) environment with docker

This article is the 16th day article of WebCrew Advent Calendar 2019. Yesterday was @ Hideto-Kiyoshima-wc's Scala's Option / Either / Try Super Introduction.

Introduction

I'm @yagiyuuuu for the second year since I joined WebCrew Inc. as a new graduate. Currently, I am developing an application environment of Nginx + uWSGI + Python (Django) by creating it with Docker. I've written this article in the hope that it will help people who develop apps with Django.

Install Docker for Windows

Open the control panel, Make sure that "Programs and Features"-> "Turn Windows features on or off"-> "Hyper-V" is checked. If it is not checked, check it and restart your PC to activate it. Next, install "Docker Desktop for Windows". You can install it from here (https://docs.docker.com/docker-for-windows/install/).

Build an environment to run Django

Directory structure

Below, run the Django app with the configuration. image.png

Infrastructure creation

Install python + uWSGI, Nginx on Alpine.

Create docker-compose.yml

Create a container for Nginx and python + uWSGI. This time, the log is output under django-sample, but please set it to spit out the log wherever you like.

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

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

Nginx settings

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

uWSGI + Django settings

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

Describe the module you want to install in requirements.txt.

Create .env file

django-sample/.env


COMPOSE_FILE=docker-compose.yml

Application creation

Since we are focusing on creating apps here, For more information on the Django app, check out the official website. Also, do not write code in __init__.py and __pycache__, but create them. If it is not created, the app will not work.

Project creation

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

#Specify the handler used for log output
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

#Set the IP and domain of the server that allows connection
#Localhost if nothing is set(localhost)Only possible to connect from
ALLOWED_HOSTS = ["localhost"]

# Application definition
#Added "app". If you do not add this, the custom tags defined in template tags will not be recognized.
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',        #Unit D is day
            'interval': 1,      #Specify every few days
            'backupCount': 30,  #Number of backup generations
        }
    },
    'loggers': {
        'django': {
            'handlers': ['app'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'django.server': {
            'handlers': ['app'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'app': {
            'handlers': LOG_HANDLER,
            'level': 'DEBUG',
            'propagate': True,
        },
    },
}

#Session engine settings
#Use a session with cookies
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'

#Login status expiration date (seconds)
#You can stay logged in until the expiration date (seconds) specified here is exceeded.
#The expiration date of the session itself is SESSION_COOKIE_AGE
# 8h * 60m * 60s
LOGIN_LIMIT = 28800

#Session lifetime(Seconds)
#If you want to change the session validity period for each user, request.session.set_expiry(value)Use
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()

App creation

Create an app in your django sample project.

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

Creating a template to display on the screen

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


Hello Django!!

Launch the container

Type the following command in the hierarchy where docker-compose.yml is located

Build and start container

$ docker-compose up --build -d

Can be started in the background by adding -d

Check the container

$ docker-compose ps

Delete the container

$ docker-compose down

Access the created app

After starting the container, go to http: // localhost / app / Hello Django !! is displayed

At the end

Create your own environment for creating Django apps! !!

Tomorrow's article is @ yuko-tsutsui. Thank you.

Recommended Posts

Create Nginx + uWSGI + Python (Django) environment with docker
Create a django environment with docker-compose (MariaDB + Nginx + uWSGI)
Build Django + NGINX + PostgreSQL development environment with Docker
[Python] Build a Django development environment with Docker
Prepare python3 environment with Docker
Build Mysql + Python environment with docker
Build a Django development environment with Docker! (Docker-compose / Django / postgreSQL / nginx)
Create a simple Python development environment with VSCode & Docker Desktop
Create a Todo app with Django ① Build an environment with Docker
Build Jupyter Lab (Python) environment with Docker
[Python] Create a virtual environment with Anaconda
Python execution server construction (Python + uWSGI + Django + Nginx)
Launch environment with LineBot + Heroku + Docker + Python
Build NGINX + NGINX Unit + MySQL environment with Docker
Create a development environment for Go + MySQL + nginx with Docker (docker-compose)
Create a C ++ and Python execution environment with WSL2 + Docker + VSCode
Create a simple Python development environment with VS Code and Docker
Build Python + django + nginx + MySQL environment using docekr
Django 1.11 started with Python3.6
Prepare the execution environment of Python3 with Docker
Make Django's environment Docker (Docker + Django + Gunicorn + nginx) Part 2
Non-blocking with Python + uWSGI
Create a virtual environment with conda in Python
Create a python3 build environment with Sublime Text3
Hello World with nginx + uwsgi + python on EC2
Use python with docker
Python environment with docker-compose
Create a Python environment
WebSocket with Python + uWSGI
Quickly build a Python Django environment with IntelliJ
Create a Python3.4 + Nginx + uWSGI + Flask Web application execution environment with haste using pyenv on Ubuntu 12.04
Build PyPy and Python execution environment with Docker
Virtual environment with Python 3.6
[Docker] Create a jupyterLab (python) environment in 3 minutes!
Make Django's environment Docker (Docker + Django + Gunicorn + nginx) Part 3
Python local development environment construction template [Flask / Django / Jupyter with Docker + VS Code]
Virtual environment construction with Docker + Flask (Python) + Jupyter notebook
Japanese can be used with Python in Docker environment
Create a python development environment with vagrant + ansible + fabric
Launch a Python web application with Nginx + Gunicorn with Docker
How to build a Django (python) environment on docker
Deploy an existing app with docker + pyenv-virtualenv + uwsgi + django
Web application made with Python3.4 + Django (Part.1 Environment construction)
Create a Layer for AWS Lambda Python with Docker
A memo about building a Django (Python) application with Docker
Build a development environment with Poetry Django Docker Pycharm
Do Django with CodeStar (Python3.6.8, Django2.2.9)
Create an environment with virtualenv
Minimal website environment with django
Install Python environment with Anaconda
Create an API with Django
Manage python environment with virtualenv
Create a web application execution environment of Python3.4 + Nginx + uWSGI + Flask with haste using venv on Ubuntu 14.04 LTS
Do Django with CodeStar (Python3.8, Django2.1.15)
Create 3d gif with python3
API with Flask + uWSGI + Nginx
Python3 + Django ~ Mac ~ with Apache
Create ToDo List [Python Django]
Getting Started with Python Django (1)
Create a homepage with django
Getting Started with Python Django (4)