Launch a Python web application with Nginx + Gunicorn with Docker

Constitution

--Web server - nginx --WSGI server (AP server) - Gunicorn --Web application framework - Django --Since WSGI is used here, other frameworks may be used as long as they are WSGI compliant. --No Django-specific settings occur in this article --Web server and WSGI server run in Docker container --Use UNIX domain sockets for communication between the web server and WSGI server

Arrangement of terms

What is a WSGI server?

--WSGI stands for Web Server Gateway Interface, a protocol for communication between a web server and Python's AP server. --Frameworks such as Django, Flask, and Bottle also comply with this protocol. --The AP server that conforms to the above WSGI is called a WSGI server, and Gunicorn is one of them. --WSGI servers other than gunicorn have uWSGI

What is a UNIX domain socket?

--Communication method to search for a communication partner through the path of the file system --A file is created in that path and each process accesses the file ――It seems that you are just sharing a file, but the created file is a special file called a socket file and there is no actual situation. --Communication interface

Build

Gunicorn

--First, try running the WSGI server alone

Project creation

--Install Django

$ pip install Django==3.0.2

--Create a project in your work environment

$ django-admin.py startproject django_project .

--Here, create a project with the name django_project --If you check with the tree command, it will be as follows

$ tree
.
├── django_project
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── manage.py

Start Gunicorn container

--Create a Dockerfile

FROM python:3.8.0-alpine

WORKDIR /usr/src/app

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

RUN pip install --upgrade pip
COPY ./requirements.txt /usr/src/app/requirements.txt
RUN pip install -r requirements.txt

--requirements.txt is as follows

requirements.txt


Django==3.0.2
gunicorn==20.0.4

--Build

$ docker build -t gunicorn:tmp .

--The description of docker-compose.yaml is as follows --I will add nginx information later

version: '3.7'

services:
  gunicorn:
    image: gunicorn:tmp 
    container_name: gunicorn
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/usr/src/app/
    ports:
      - 8000:8000

-- python manage.py runserver 0.0.0.0:8000 command starts a simple test server --Here, port 8000 is forwarded to check the operation. --Start with $ docker-compose up -d, access localhost: 8000, and if the Django screen is displayed, it's OK.

スクリーンショット 2020-01-12 20.57.11.png

Settings to use UNIX domain sockets with Nginx

--Use the official Docker image, but create a conf file that describes the UNIX domain socket settings and mount it at startup --Description the following contents with the name gunicorn.conf

gunicorn.conf


upstream gunicorn-django {
    server unix:///var/run/gunicorn/gunicorn.sock;
}

server {
    listen 80;
    server_name localhost;

    location / {
        try_files $uri @gunicorn;
    }

    location @gunicorn {
        proxy_pass http://gunicorn-django;
    }
}

--```upstream gunicorn-django {…}` `` contents are UNIX domain socket settings --Communicate with gunicorn via the socket file in the path described --In other words, it is necessary to set to call this socket file from the gunicorn side as well. --After that, you can specify gunicorn-django specified by upstream in proxy_pass of location. --The description of docker-compose.yaml of Nginx is as follows

version: '3.7'

services:
  nginx:
    image: nginx:1.17.7
    container_name: nginx
    ports:
      - "80:80"
    volumes:
      - ./gunicorn.conf:/etc/nginx/conf.d/default.conf

--Mount in Nginx with the name /etc/nginx/conf.d/default.conf --Nginx reads /etc/nginx/nginx.conf at startup and says include /etc/nginx/conf.d/*.conf; in that file, so `` If you mount the conf file you created under `/etc/nginx/conf.d```, it will be read together at startup.

Settings to use UNIX domain sockets with Gunicorn

--Make some changes from the state where it was started locally earlier

Container start command

WSGI settings

--You need to hit the following gunicorn command so that Gunicorn can communicate with Nginx

gunicorn django_project.wsgi

--This loads wsgi.py under django_project, which is built when you create a project called django_project this time. --Manage.py was started when starting locally, but this command is required when communicating with WSGI.

UNIX domain socket settings

--Specify the startup socket file path with `` `--bind``` to communicate with UNIX domain sockets.

gunicorn django_project.wsgi --bind=unix:/var/run/gunicorn/gunicorn.sock

--This enables UNIX domain socket communication to gunicorn

Doickerfile fix

--Changed CMD of Dockerfile based on the above contents

Dockerfile


FROM python:3.8.0-alpine

WORKDIR /usr/src/app

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

RUN pip install --upgrade pip
COPY ./requirements.txt /usr/src/app/requirements.txt
RUN pip install -r requirements.txt

RUN mkdir -p /var/run/gunicorn

CMD ["gunicorn", "django_project.wsgi", "--bind=unix:/var/run/gunicorn/gunicorn.sock"]

--Build again

$ docker build -t gunicorn:latest .

Specify a host that can access your Django project

--Specify in ʻALLOWED_HOSTS = [] in setting.py created under django_project --It should be restricted normally, but here it is set to ʻALLOWED_HOSTS = [*] to allow access from all hosts. --This file is called from wsgi.py

Create a volume to mount on UNIX domain socket communication

--Since the socket file path was specified in Nginx and Gunicorn, it is necessary to create a socket file volume. --This time, we will start with Docker, so create a Docker Volume at startup and mount it from two containers to that Volume. --The final docker-compose.yaml is as follows

docker-compose.yaml


version: '3.7'

services:
  gunicorn:
    image: gunicorn:latest
    container_name: gunicorn
    volumes:
      - .:/usr/src/app/
      - gunicorn:/var/run/gunicorn
  nginx:
    image: nginx:1.17.7
    container_name: nginx
    depends_on:
      - gunicorn
    ports:
      - "80:80"
    volumes:
      - ./gunicorn.conf:/etc/nginx/conf.d/default.conf
      - gunicorn:/var/run/gunicorn
volumes:
  gunicorn:
    driver: local

--Create a Volume called gunicorn and mount it in each container (this time, / var / run / gunicorn is specified in both containers)

Operation

--Start with the following command

$ docker-compose up -d
Starting gunicorn ... done
Starting nginx    ... done

--Try accessing localhost after startup

スクリーンショット 2020-02-08 14.44.28.png

--OK if the screen is displayed --The screen displayed is the same as when Gunicorn was first run alone, but this time it is displayed via nginx.

Source code

--The set of files created this time is here

reference

-Quick Start Guide: Docker Compose and Django -Introduction to uWSGI -Unix domain socket -Who runs django? (Overview for deployment) -Django ALLOWED_HOSTS settings -Run a Python web application on gunicorn (Django and Flask)

Recommended Posts

Launch a Python web application with Nginx + Gunicorn with Docker
Run a Python web application with Docker
[Python] A quick web application with Bottle!
Start a simple Python web server with Docker
Launch a web server with Python and Flask
Web application with Python + Flask ② ③
Web application with Python + Flask ④
A memo about building a Django (Python) application with Docker
Deploy a Django application with Docker
Build a web application with Django
Application development with Docker + Python + Flask
Deploy a Django application on EC2 with Nginx + Gunicorn + Supervisor
If you know Python, you can make a web application with Django
Daemonize a Python web app with Supervisor
Create Python + uWSGI + Nginx environment with Docker
Launch environment with LineBot + Heroku + Docker + Python
Let's make a web framework with Python! (1)
Create a web service with Docker + Flask
Launch Flask application with Docker on Heroku
Let's make a web framework with Python! (2)
I made a WEB application with Django
Create a Python3.4 + Nginx + uWSGI + Flask Web application execution environment with haste using pyenv on Ubuntu 12.04
[GCP] Procedure for creating a web application with Cloud Functions (Python + Flask)
[Streamlit] I hate JavaScript, so I make a web application only with Python
Implement a simple application with Python full scratch without using a web framework.
[Python] Build a Django development environment with Docker
Steps to develop a web application in Python
Create Nginx + uWSGI + Python (Django) environment with docker
Run Flask on CentOS with python3.4, Gunicorn + Nginx.
Create a Python console application easily with Click
Extract data from a web page with Python
Use python with docker
Put Docker in Windows Home and run a simple web server with Python
[ES Lab] I tried to develop a WEB application with Python and Flask ②
Create a web application execution environment of Python3.4 + Nginx + uWSGI + Flask with haste using venv on Ubuntu 14.04 LTS
(Python) Try to develop a web application using Django
Parse and visualize JSON (Web application ⑤ with Python + Flask)
Web application made with Python3.4 + Django (Part.1 Environment construction)
Build a machine learning application development environment with Python
Create a Layer for AWS Lambda Python with Docker
Launch Django on a Docker container with docker-compose up
Web scraping with python + JupyterLab
Web application creation with Django
Prepare python3 environment with Docker
Web API with Python + Falcon
Make a fortune with Python
Web scraping beginner with python
Create a directory with python
Python server settings (nginx + Gunicorn)
Streamline web search with python
Rails application building with Docker
[With image diagram] Nginx + gunicorn + Flask converted to Docker [Part 2]
Create a web application that recognizes numbers with a neural network
Build a Django development environment with Docker! (Docker-compose / Django / postgreSQL / nginx)
How to convert an array to a dictionary with Python [Application]
Create a simple Python development environment with VSCode & Docker Desktop
Web application with Python3.3.1 + Bottle (1) --Change template engine to jinja2
[With image diagram] Nginx + gunicorn + Flask converted to Docker [Part 1]
Display a web page with FastAPI + uvicorn + Nginx (SSL / HTTPS)
I created an environment for Masonite, a Python web framework similar to Laravel, with Docker!
[Python] What is a with statement?