[PYTHON] Déployez Django + React à partir de zéro vers GKE (1) Développement backend - Nginx + Django

Déployez Django + React à partir de zéro vers GKE (1) Développement backend - Nginx + Django

Chose que tu veux faire

Je voulais développer une application avec la configuration Djagno + React et la déployer sur Google Kubernetes Engine, mais je ne pensais pas qu'il y avait un tutoriel cohérent, alors je l'ai écrit.

Cependant, ** je pense qu'il y a des points qui ne sont pas encore parfaits **, mais je pense que si vous avez un peu d'expérience, vous pouvez l'utiliser immédiatement.

Mise en garde

Il s'agit d'un enregistrement d'un ingénieur amateur inexpérimenté qui lutte avec le déploiement pour créer un portefeuille. S'il y a des lacunes, veuillez les signaler. ..

Viser la figure

environnement

$ node --version
v12.14.1

$ npm --version
6.13.7

$ python --version
Python 3.7.4

$ docker --version
Docker version 19.03.8

OS windows10 pro

Commencer localement

Créer un annuaire

#Créer un dossier de projet
$ mkdir gke-django-tutorial
$ cd gke-django-tutorial

#Créer un annuaire
$\gke-django-tutorial\mkdir backend
$\gke-django-tutorial\mkdir frontend

Développement backend (édition Django)

Le pod backend fournit l'API Rest avec Django-rest-framework. Organisons l'intérieur du pod backend.

Rôle Image du conteneur
Serveur proxy Nginx: 1.17.4-alpine
Application Python3.7 - Framework Rest de Django
cloud_sql_proxy gcr.io/cloudsql-docker/gce-proxy

Créez un répertoire dans le backend.

#Déplacer vers le répertoire backend
$\gke-django-tutorial\cd backend

#Créer un répertoire django
$\gke-django-tutorial\backend\mkdir web-back

#Créer un répertoire Nginx
$\gke-django-tutorial\backend\mkdir nginx

Démarrer un projet avec Django

Nous allons créer un environnement virtuel pour Python et développer un serveur API avec le framework Rest Django. Créez-le dans le répertoire backend \ web-back \.

# web-retour répertoire
$\gke-django-tutorial\backend\cd web-back

#Créer un environnement virtuel pour Python
$\gke-django-tutorial\backend\web-back\python -m venv venv

#Activer l'environnement virtuel
$\gke-django-tutorial\backend\web-back\venv\Scripts\activate

#Installer des packages Python
(venv)$\gke-django-tutorial\backend\web-back\python -m install --upgrade pip setuptools
(venv)$\gke-django-tutorial\backend\web-back\python -m install django djangorestframework python-dotenv

#Démarrer un projet Django
(venv)$\gke-django-tutorial\backend\web-back\django-admin startproject config .

En faisant django-admin startprject config . sous le répertoire web-back Un dossier de projet Django appelé config a été créé.

Vérifions si le serveur local démarre.

(venv)$\gke-django-tutorial\backend\web-back\python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
April 27, 2020 - 11:22:06
Django version 3.0.5, using settings 'config.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.

Depuis le démarrage du serveur de développement, vous pouvez voir l'écran de L'installation a fonctionné avec succès! En accédant à http: // localhost: 8000 /.

settings.py

Modifiez config / settings.py pour inclure les paramètres de base. Les informations confidentielles dans settings.py doivent être écrites dans le fichier .env afin qu'elles ne soient pas divulguées. Modifions-le pour utiliser les informations décrites dans .env en utilisant le paquet python-dotenv.

# .Créer un fichier env
(venv)$\gke-django-tutorial\backend\web-back\type nul > .env
# config/settings.py

import os
from dotenv import load_dotenv  #ajouter à

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
PROJECT_DIR = os.path.basename(BASE_DIR)  #ajouter à

# .Chargement env
load_dotenv(os.path.join(BASE_DIR, '.env'))  #ajouter à

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv('SECRET_KEY')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv('DEBUG')

ALLOWED_HOSTS = ["*"]  #Changement


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'config.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],  #Changement
        '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 = 'config.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.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/3.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/3.0/topics/i18n/

LANGUAGE_CODE = 'ja'  #Changement

TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'

#Où faire référence aux fichiers statiques dans l'environnement de développement
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')] #ajouter à

#Où référencer les fichiers statiques en production
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') #ajouter à

#Chemin du fichier multimédia
MEDIA_URL = '/media/' #ajouter à

.env


# .env
SECRET_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
DEBUG = False

Ajouter une application

Créons une application todo.

(venv)$\gke-django-tutorial\backend\web-back\python manage.py startapp todo

Ajoutez todo et rest_framework à ʻINSTALLED_APPS dans config / settings.py`.

# config/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # 3rd party
    'rest_framework',

    # Local
    'todo.apps.TodoConfig',
]

#ajouter à
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ]
}

rest_framework.permissions.AllowAny sert à libérer le paramètre par défaut'DEFAULT_PERMISSION_CLASSES' défini implicitement par django-rest-framework.

todo/models.py

Créez un modèle d'application «todo».

# todo/models.py
from django.db import models


class Todo(models.Model):
    title = models.CharField(max_length=200)
    body = models.TextField()

    def __str__(self):
        return self.title

Ajoutez le modèle créé à todo / admin.py.

# todo/admin.py
from django.contrib import admin
from .models import Todo


admin.site.register(Todo)

Émigrer.

(venv)$\gke-django-tutorial\backend\web-back\python manage.py makemigrations
Migrations for 'todo':
  todo\migrations\0001_initial.py
    - Create model Todo

(venv)$\gke-django-tutorial\backend\web-back\python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, todo
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying sessions.0001_initial... OK
  Applying todo.0001_initial... OK

createsuperuser

Créez un utilisateur administrateur.

(venv)$\gke-django-tutorial\backend\web-back\python manage.py createsuperuser
Nom d'utilisateur(leave blank to use '[YOUR_NAME]'): [USER_NAME]
adresse mail: [email protected]
Password:
Password (again):
Superuser created successfully.

Lorsque vous démarrez le serveur de développement et accédez à http: // localhost: 8000 / admin /, l'écran de connexion au site d'administration de Django s'affiche. Saisissez le nom d'utilisateur et le mot de passe définis pour vous connecter.

Si vous pouvez vous connecter, vous pouvez voir le tableau de l'application créée Todo. Ajoutons quelques éléments.

URLs

Ajoutez une route à l'applicateur de todo dans config / urls.py.

# config/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('todo.urls'))  #ajouter à
]

todo/urls.py

Créez todo / urls.py.

(venv)$\gke-django-tutorial\backend\web-back\type nul > todo\urls.py
# todo/urls.py
from django.urls import path, include
from .views import ListTodo, DetailTodo

urlpatterns = [
    path('<int:pk>/', DetailTodo.as_view()),
    path('', ListTodo.as_view())
]

todo/selializers.py

Créez un sérialiseur pour convertir facilement l'instance de modèle au format json.

(venv)$\gke-django-tutorial\backend\type nul > todo\serializers.py
# todo/serializers.py
from rest_framework import serializers
from .models import Todo


class TodoSerializer(serizers.ModelSerializer):
    class Meta:
        model = Todo
        fields = ('id', 'title', 'body')

ʻId at fields = ('id', 'title', 'text') ʻest automatiquement ajouté par Django si vous ne spécifiez pas PrimaryKey dans le modèle.

todo/views.py

Lors de la création de views.py avec Django rest framework, il hérite ~~ APIView de rest_framework.generics.

# todo/views.py

from django.shortcuts import render
from rest_framework import generics
from .models import Todo
from .serializers import TodoSerializer


class ListTodo(generics.ListAPIView):
    queryset = Todo.objects.all()
    serializer_class = TodoSerializer


class DetailTodo(generics.RetrieveAPIView):
    queryset = Todo.objects.all()
    serializer_class = TodoSerializer

Je n'ai pas configuré le routeur, etc., mais pour le moment, je suis prêt à fournir les éléments de l'application Todo en tant qu'API Rest. Vous pouvez vérifier la vue API en accédant à http: // localhost: 8000 / api / sur le serveur de développement.

Jusqu'à présent, nous nous sommes développés dans l'environnement local, ce qui est courant à Django.

CORS

Comment Django (localhost: 8000) interagit avec React ( localhost: 3000) pour json Il est nécessaire de définir CORS (Cross-Origin Resource Sharing).

Installons django-cors-headers.

(venv)$\gke-django-tutorial\backend\web-back\python -m pip install django-cors-headers

Mettez à jour config / settings.py.

# config/settings.py

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # 3rd party
    'rest_framework',
    'corsheaders',

    # Local
    'todos.apps.TodosConfig',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMidddleware',  #ajouter à
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

##################
# rest_framework #
##################

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ]
}

CORS_ORIGIN_WHITELIST = (
    'http://localhost:3000',
)

local_settings.py

En supposant que config / settings.py sera utilisé dans l'environnement de production, créez config / local_settings.py et conservez-le pour le développement local. En séparant settings.py afin que CloudSQL soit utilisé lors du déploiement de GKE et sqlite3 soit utilisé localement, il n'est pas nécessaire de réécrire les valeurs des paramètres.

#Créer un fichier
(venv)$\gke-django-tutorial\backend\web-back\type nul > config/local_settings.py
# config/local_settings.py
from .settings import *

DEBUG = True

ALLOWED_HOSTS = ['*']

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

Démarrez le serveur de développement en utilisant config / local_settings.py.

(venv)$\gke-django-tutorial\backend\web-back\python manage.py runserver --settings config.local_settings

Tests

Écrivez un test.

# todos/test.py

from django.test import TestCase
from .models import Todo


class TodoModelTest(TestCase):

    @classmethod
    def setUpTestData(cls):
        Todo.objects.create(title="first todo", body="a body here")

    def test_title_content(self):
        todo = Todo.objects.get(id=1)
        excepted_object_name = f'{todo.title}'
        self.assertEqual(excepted_object_name, 'first todo')

    def test_body_content(self):
        todo = Todo.objects.get(id=1)
        excepted_object_name = f'{todo.body}'
        self.assertEqual(excepted_object_name, 'a body here')
(venv)$\gke-django-tutorial\backend\web-back\python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 0.007s

OK
Destroying test database for alias 'default'...

Cela semble avoir fonctionné.

Fichier statique

Regroupez les fichiers statiques afin que le css de la fonction d'administrateur soit reflété après le déploiement. Le répertoire qui regroupe les fichiers statiques pour la distribution est staticfiles /, et le répertoire de fichiers statiques qui est ajouté pour le développement est static /.

#Répertoire de livraison de fichiers statiques
(venv)$\gke-django-tutorial\backend\web-back\mkdir staticfiles

#Répertoire de développement de fichiers statiques
(venv)$\gke-django-tutorial\backend\web-back\mkdir static

#Agrégation de fichiers statiques
(venv)$\gke-django-tutorial\backend\web-back\python manage.py collectstatic

Vous pouvez voir que le CSS admin etc. est également ajouté sous le répertoire staticfiles /.

Ajouter un package Python

Utilisez Cloud SQL Postgres lors du déploiement sur GKE. Vous avez besoin de psycopig2 pour utiliser Postgres de Django. Utilisez également gunicorn pour lancer l'application.

Installez les packages requis en plus et rassemblez les packages Python installés dans l'environnement virtuel dans requirements.txt.

#Installation du package
(venv)$\gke-django-tutorial\backend\web-back\python -m pip install wheel gunicorn psycopg2-binary

# requirements.Mettre à jour txt
(venv)$\gke-django-tutorial\backend\web-back\python -m pip freeze > requirements.txt

Une fois exécuté, requirements.txt sera créé sous backend /.

asgiref==3.2.7
Django==3.0.5
django-cors-headers==3.2.1
djangorestframework==3.11.0
gunicorn==20.0.4
psycopg2-binary==2.8.5
python-dotenv==0.13.0
pytz==2019.3
sqlparse==0.3.1

Créer un Dockerfile

Créez un Dockerfile pour créer une image de conteneur côté Django.

#Créer un Dockerfile
(venv)$\gke-django-tutorial\backend\web-back\type nul > Dockerfile

# .Création de docker ignore
(venv)$\gke-django-tutorial\backend\web-back\type nul > .dockerignore
# backend/web-back/Dockerfile

# set base image
FROM python:3.7

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# set work directory
WORKDIR /code

# install dependencies
COPY requirements.txt ./
RUN python3 -m pip install --upgrade pip setuptools
RUN pip install -r requirements.txt

# Copy project
COPY . ./

# Expose application port
EXPOSE 8000

Créez également un .dockerignore pour séparer les fichiers que vous ne souhaitez pas placer dans le conteneur.

.dockerignore


venv/
.env
Dockerfile
config/local_settings.py

Vous êtes maintenant prêt à créer une image Docker pour Django.

Développement backend (édition Nginx)

Placez le conteneur Nginx en tant que serveur proxy inverse dans le backend-Pod. Nginx utilise le fichier de configuration dans / etc / nginx / conf.d / pour définir la fonctionnalité de proxy inverse.

De plus, à la fin du développement du backend, je voudrais le démarrer avec docker-compose, donc créez également un fichier pour docker-compose.

#Créer un fichier pour Nginx
$\gke-django-tutorial\backened\nginx\type nul > Dockerfile
$\gke-django-tutorial\backened\nginx\type nul > Dockerfile.dev
$\gke-django-tutorial\backened\nginx\type nul > default.conf
$\gke-django-tutorial\backened\nginx\type nul > default.dev.conf

default.conf a défini le proxy inverse comme Conteneur Nginx: 80Django: 8000.

La directive location = / healthz est le chemin de vérification de l'état dont vous aurez besoin après le déploiement sur GKE. La directive location / static / est le chemin d'accès aux fichiers statiques. Sans cela, le CSS de l'écran administrateur ne sera pas appliqué. Lors du déploiement sur GKE, les fichiers statiques seront fournis à partir de Cloud Storage, supprimez-les donc.

La directive server est localhost: 8000 lors du déploiement sur GKE et web-back: 8000 lors du démarrage avec docker-compose. En effet, lorsque vous démarrez avec docker-compose, il est nécessaire de résoudre le nom par nom de service. Lors du déploiement sur GKE, il se trouve dans le même pod, de sorte que le nom peut être résolu avec localhost: 8000.

; default.dev.conf
upstream django {
    server web-back:8000;
}

; default.Pour conf
; upstream django {
    ; server localhost:8000;
; }

server {

    listen 80;

    location = /healthz {
        return 200;
    }

    location / {
        proxy_pass http://django;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
    }

;Supprimé lors du déploiement de GKE
    location /static/ {
        alias /code/staticfiles/;
    }
}

Le Dockerfile reflète les paramètres en copiant le fichier de paramètres Nginx dans le conteneur Nginx.

# backend\nginx\Dockerfile.dev
FROM nginx:1.17.4-alpine

RUN rm /etc/nginx/conf.d/default.conf
COPY default.dev.conf /etc/nginx/conf.d

# backend\nginx\Dockerfile.Pour dev
# COPY default.conf /etc/nginx/conf.d

Développement backend (édition docker-compose)

Je voudrais utiliser docker-compose pour lancer un conteneur avec une configuration Nginx + Django.

# docker-compose.Créer yml
$\gke-django-tutorial\backend\type nul > docker-compose.yml
version: "3.7"

services:
  web-back:
    container_name: python-backend
    env_file: ./web-back/.env
    build: ./web-back/.
    volumes:
      - ./web-back:/code/
      - static_volume:/code/staticfiles # <-- bind the static volume
    stdin_open: true
    tty: true
    command: gunicorn --bind :8000 config.wsgi:application
    networks:
      - backend_network
    environment:
      - CHOKIDAR_USEPOLLING=true
      - DJANGO_SETTINGS_MODULE=config.local_settings
  server:
    container_name: nginx
    build:
      context: ./nginx/.
      dockerfile: Dockerfile.dev
    volumes:
      - static_volume:/code/staticfiles # <-- bind the static volume
    ports:
      - "8080:80"
    depends_on:
      - web-back
    networks:
      - backend_network
networks:
  backend_network:
    driver: bridge
volumes:
  static_volume:
# docker-compose.Commencez avec yml
$\gke-django-tutorial\backend\docker-compose up --build

http: // localhost: 8080 Conteneur Nginx: 80 Django: 8000 Il est transféré par port.

Allez sur http: // localhost: 8080 / admin / et vérifiez si le CSS est reflété.

L'environnement est prêt pour le développement backend en commençant par docker-compose dans l'environnement local.

⇒ Accédez à (2) Développement Frontend: Nginx + React

Recommended Posts

Déployez Django + React à partir de zéro vers GKE (1) Développement backend - Nginx + Django
Déployer Django + React de zéro sur GKE: Table des matières
Déployer Django + React à partir de zéro vers GKE (3) Créer un projet GCP
Déployez Django + React à partir de zéro vers GKE (4) Créez un cluster et un conteneur PUSH
De 0 à la construction de l'environnement de développement Django à l'exploitation de base
Django memo n ° 1 à partir de zéro
Django à partir de zéro (partie: 2)
Django à partir de zéro (partie: 1)
Déployer le projet django sur heroku
Déployer le didacticiel Django sur IIS ①
Déploiement de Django (Ubuntu 14.04 LTS + Nginx + uWSGI + Supervisor)
Présentation de Docker Engine à Linux From Scratch