Django savvaļā: padomi izdzīvošanas izdzīvošanai

Pirms Django tīmekļa lietotnes izvietošanas reālajā pasaulē jums jāpārliecinās, vai jūsu projekts ir gatavs ražošanai. Labāk sākt tos ieviest agrāk. Tas ietaupa jums un jūsu komandai daudz laika un galvassāpes. Šeit ir daži punkti, kurus es uzzināju ceļā:

  1. Izmantojiet pipenv (vai prasības.txt + venv). Izpildiet Pipefile un Pipefile.lock (vai prasības.txt). Nosauciet savu venv.
  2. Ir ātrās palaišanas skripts.
  3. Rakstiet testus. Izmantojiet Django testa sistēmuun hipotēze.
  4. Izmantojiet vidiun direnv, lai pārvaldītu iestatījumus un automātiski ielādētu vides mainīgos.
  5. Pārliecinieties, ka visi izstrādātāji veic migrāciju. Skvoša migrācija laiku pa laikam. Ja nepieciešams, atiestatiet tos. Arhitektējiet savu projektu vienmērīgākām migrācijām. Lasiet par migrācijām.
  6. Izmantojiet nepārtrauktu integrāciju. Aizsargājiet savu galveno zaru.
  7. Izskatiet Django oficiālo izvietošanas kontrolsarakstu.
  8. Nepārvaldiet savu serveri, bet, ja jums tas ir nepieciešams, izmantojiet pareizu direktoriju struktūru un izmantojiet Supervisord, Gunicorn un NGINX.

Šis saraksts organiski pieauga, kad es izlaidu mūsu pirmo Django lietotni, un tas nav pilnīgs. Bet es domāju, ka šie ir daži no vissvarīgākajiem punktiem, kas jums jāzina.

Lasiet līdzi, lai apspriestu katru no punktiem.

Pareizi pārvaldiet savas atkarības un virtuālo vidi

Jums un jūsu komandai vajadzētu vienoties par veidu, kā pārvaldīt savas atkarības un virtuālo vidi. Es iesaku vai nu izmantot pipenv, kas ir jauns veids, kā pārvaldīt gan jūsu virtuālo vidi, gan atkarības, vai izmantot veco labo pieeju, veidojot venv un izsekojot jūsu atkarības ar requirements.txtfailu.

Izmantojot requirements.txtpieeju, ir nosliece uz cilvēka kļūdas, jo izstrādātāji mēdz aizmirst par atjaunināšanu zāļu sarakstu. Šī nav problēma ar pipenv, jo tā automātiski atjaunina Pipefile. Pipenv trūkums ir tas, ka tas nav bijis pietiekami ilgi. Pat ja to oficiāli iesaka Python programmatūras fonds, jums var rasties problēmas, lai to palaistu dažās mašīnās. Personīgi es joprojām izmantoju veco pieeju, bet savam nākamajam projektam izmantošu pipenv .

Izmantojot venv un prasības.txt

Ja izmantojat Python ≥ 3.6 (jums vajadzētu būt), varat to vienkārši izveidot ar python -m venv ENV. Noteikti nosauciet virtuālo vidi (nevis izmantojiet .). Dažreiz jums ir jāizdzēš virtuālā vide un jāizveido tā no jauna. Tas atvieglo. Turklāt jums vajadzētu pievienot ENVdirektoriju savam. gitignorefails (Es gribētu ENV vārdu nevis venv , .env , ... jo tas izceļas, kad es ls projekta mapi).

Lai pārvaldītu atkarības, katrs izstrādātājs palaiž pip freeze > requirements.txt ikreiz, kad instalē jaunu pakotni, pievieno un nodod to repo. Viņi izmantos pip install -r requirements.txtikreiz, kad izvelk no attālās krātuves.

Izmantojot pipenv

Ja izmantojat pipenv , jums repo ir vienkārši jāpievieno Pipfile un Pipfile.lock.

Ir ātrās palaišanas skripts

Tas palīdz pārliecināties, ka izstrādātāji tērē pēc iespējas mazāk laika darbam ar lietām, kas nav tieši saistītas ar viņu darbu.

Tas ne tikai ietaupa laiku un naudu, bet arī pārliecinās, ka viņi visi strādā līdzīgā vidē (piemēram, tās pašas Python un pip versijas).

Tātad, mēģiniet automatizēt pēc iespējas vairāk iestatīšanas uzdevumu.

Turklāt Joel Testa otrais solis ir tas, ka ir vienpakāpes veidošanas skripts.

Šeit ir neliels skripts, kuru izmantoju, un tas ļauj maniem izstrādātājiem ietaupīt daudz taustiņu:

#!/bin/bash python3.6 -m venv ENV source ENV/bin/activate pip install --upgrade pip pip install -r requirements.txt source .envrc python ./manage.py migrate python ./manage.py loaddata example-django/fixtures/quickstart.json python ./manage.py runserver

Rakstiet testus

Visi zina, ka testu rakstīšana ir laba prakse. Bet daudzi to ignorē, viņuprāt, ātrākai attīstībai. NEDRĪKST. Pārbaudes ir absolūti nepieciešamas, lai rakstītu ražošanā izmantoto programmatūru, it īpaši, ja strādājat komandā. Vienīgais veids, kā jūs varat zināt, ka jaunākais atjauninājums kaut ko nesabojāja, ir labi uzrakstīti testi. Jums arī ir nepieciešami nepārtraukta produkta integrācijas un piegādes testi.

Django ir pienācīgs testu ietvars. Varat arī izmantot uz īpašumu balstītas testēšanas ietvarus, piemēram, Hipotēze, kas palīdz rakstīt īsākus, matemātiski stingrus koda testus. Daudzos gadījumos uz īpašumu balstītu testu rakstīšana ir ātrāka. Praksē jūs varat izmantot abus šos ietvarus visaptverošu, viegli lasāmu un rakstāmu testu rakstīšanai.

Iestatījumiem izmantojiet vides mainīgos

Jūsu failā settings.py tiek glabāti visi svarīgākie projekta iestatījumi: datu bāzes URL, ceļi uz multivides un statiskām mapēm utt. Jūsu izstrādes mašīnā un ražošanas serverī tām būs dažādas vērtības. Labākais veids, kā to novērst, ir vides mainīgo izmantošana. Vispirms ir jāatjaunina iestatījumi.py, lai lasītu no vides mainīgajiem, izmantojot vidi :

import environ import os root = environ.Path(__file__) - 2 # two folders back (/a/b/ - 2 = /) env = environ.Env(DEBUG=(bool, False),) # set default values and casting GOOGLE_ANALYTICS_ID=env('GOOGLE_ANALYTICS_ID') SITE_DOMAIN = env('SITE_DOMAIN') SITE_ROOT = root() DEBUG = env('DEBUG') # False if not in os.environ DATABASES = { 'default': env.db(), # Raises ImproperlyConfigured exception if DATABASE_URL not in os.environ } public_root = root.path('./public/') MEDIA_ROOT = public_root('media') MEDIA_URL = '/media/' STATIC_ROOT = public_root('static') STATIC_URL = '/static/' AWS_ACCESS_KEY_ID = env('AWS_ACCESS_KEY_ID') AWS_SECRET_ACCESS_KEY = env('AWS_SECRET_ACCESS_KEY') ..

Lai izvairītos no manuālu envvaru ielādēšanas, savās izstrādes mašīnās iestatiet direnv un saglabājiet envvarus .envrcfailā jūsu projekta direktorijā. Tagad, kad nonākat cdprojektu mapē, vides mainīgie tiek automātiski ielādēti. Pievienojiet .envrcsavam krātuvei (ja visi izstrādātāji izmanto vienus un tos pašus iestatījumus) un pārliecinieties, vai palaižat, direnv allowja .envrcfailā ir izmaiņas .

Nelietojiet to direnvsavā ražošanas serverī. Tā vietā izveidojiet failu ar nosaukumu .server.envrc , pievienojiet to mapei.gitignore un tur ievietojiet ražošanas iestatījumus. Tagad izveidojiet skriptu, runinenv.shlai automātiski iegūtu vides mainīgos .server.envrc, aktivizētu virtuālo vidi un palaistu norādīto komandu. Kā to lieto, jūs redzēsiet nākamajā sadaļā. Lūk, kā runinenv.shvajadzētu izskatīties (saite uz GitHub).

#!/bin/bash WORKING_DIR=/home/myuser/example.com/example-django cd ${WORKING_DIR} source .server.envrc source ENV/bin/activate exec [email protected]

Rīkojieties pareizi ar migrāciju

Django migrācijas ir lieliskas, taču sadarbība ar tām, it īpaši komandā, nebūt nav apgrūtināta.

Pirmkārt, jums jāpārliecinās, vai visi izstrādātāji veic migrācijas failus. Jā, jūs varētu (vai arī) nonākt konfliktos, it īpaši, ja strādājat ar lielu komandu, bet tas ir labāk nekā pretrunīga shēma.

Kopumā tikt galā ar migrāciju nav tik vienkārši. Lai nodrošinātu vienmērīgu darbplūsmu, jums jāzina, ko darāt, un jāievēro daži paraugprakses piemēri.

Viena lieta, ko es sapratu, ir tā, ka tas parasti palīdz, ja jūs laiku pa laikam saspiežat migrācijas (piemēram, katru nedēļu). Tas palīdz samazināt failu skaitu un atkarības diagrammas lielumu, kas savukārt noved pie ātrāka būvēšanas laika un parasti mazāk (vai vieglāk apstrādājamu) konfliktu.

Dažreiz ir vieglāk atiestatīt migrācijas un padarīt tās no jauna, un dažreiz konfliktējošās migrācijas ir jānovērš manuāli vai jāapvieno. Kopumā migrāciju risināšana ir tēma, kas ir pelnījusi savu ziņojumu, un par šo tēmu ir daži labi lasāmi raksti:

  • Django migrācijas un kā pārvaldīt konfliktus
  • Kā atiestatīt migrācijas

Moreover, how your project’s migrations end up depends on your project architecture, your models, and so on. This is especially important when your code-base grows, when you have multiple apps, or when you have complicated relations between models.

I highly recommend you to read this great post about scaling Django apps, which covers the topic pretty well. It also has a tiny, useful migration script.

Use Continuous Integration

The idea behind CI is simple: run tests as soon as new code is pushed.

Use a solution which integrates well with your version controlling platform. I ended up using CircleCI. CI is especially helpful when you work with multiple developers, since you can be sure their code passes all the tests before they send a pull request. Again, as you can see, it’s very important to have well covered tests in place. Moreover, make sure your master branch is protected.

Deployment checklist

Django’s official website provides a handy deployment checklist. It helps you ensure your project’s security and performance. Make sure you follow through those guidelines.

If you must manage your own server…

There are many good reasons to not manage your own server. Docker gives you more portability and security, and serverless architectures, such as AWS Lambda, can provide you with even more benefits for less money.

But there are cases where you need more control over your server (if you need more flexibility, if you have services cannot work with containerized apps — such as security monitoring agents, and so on).

Use a proper directory structure

The first thing to do is to use a proper folder structure. If all you want to serve on your server is the Django app, you can simple clone your repository and use that as your main directory. But that’s rarely the case: usually you also need to have some static pages (home page, contacts, …). They should be separate from your Django code base.

A good way to go about it is to create a parent repository, which has different parts of your project as submodules. Your Django developers work on a django repository, your designers work on the homepage repository, … and you integrate all of them in a repository:

example.com/ example-django/ homepage/

Use Supervisord, NGINX, and Gunicorn

Sure, manage runserver works, but only for a quick test. For anything serious, you need to use a proper application server. Gunicorn is the way to go.

Keep in mind that any application server is a long-running process. And you need to make sure that it keeps running, is automatically restarted after a server failure, logs errors properly, and so on. For this purpose, we use supervisord.

Supervisord needs a configuration file, in which we tell how we want our processes to run. And it is not limited to our application server. If we have other long-running processes (e.g. celery), we should defined them in /etc/supervisor/supervisord.conf. Here is an example (also on GitHub):

[supervisord] nodaemon=true logfile=supervisord.log [supervisorctl] [inet_http_server] port = 127.0.0.1:9001 [rpcinterface:supervisor] supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [program:web-1] command=/home/myuser/example.com/example-django/runinenv.sh gunicorn example.wsgi --workers 3 --reload --log-level debug --log-file gunicorn.log --bind=0.0.0.0:8000 autostart=true autorestart=true stopsignal=QUIT stdout_logfile=/var/log/example-django/web-1.log stderr_logfile=/var/log/example-django/web-1.error.log user=myuser directory=/home/myuser/example.com/example-django [program:celery-1] command=/home/myuser/example.com/example-django/runinenv.sh celery worker --app=example --loglevel=info autostart=true autorestart=true stopsignal=QUIT stdout_logfile=/var/log/example-django/celery-1.log stderr_logfile=/var/log/example-django/celery-1.error.log user=myuser directory=/home/myuser/example.com/example-django [program:beat-1] command=/home/myuser/example.com/example-django/runinenv.sh celery beat --app=example --loglevel=info autostart=true autorestart=true stopsignal=QUIT stdout_logfile=/var/log/example-django/beat-1.log stderr_logfile=/var/log/example-django/beat-1.error.log user=myuser directory=/home/myuser/example.com/example-django [group:example-django] programs=web-1,celery-1,beat-1

Ievērojiet, kā mēs runinenv.shšeit izmantojam (14., 24. un 34. rindiņa). Pievērsiet uzmanību arī 14. rindai, kur mēs ieročus iesakām nosūtīt 3 darbiniekus. Šis skaitlis ir atkarīgs no jūsu servera serdeņu skaita. Ieteicamais strādājošo skaits ir: 2 * punktu skaits + 1.

Lai savienotu lietojumprogrammu serveri ar ārpasauli, jums ir nepieciešams arī apgriezts starpniekserveris. Vienkārši izmantojiet NGINX, jo tam ir plaša lietotāju bāze, un to ir ļoti viegli konfigurēt (šo kodu varat atrast arī vietnē GitHub):

server { server_name www.example.com; access_log /var/log/nginx/example.com.log; error_log /var/log/nginx/example.com.error.log debug; root /home/myuser/example.com/homepage; sendfile on; # if the uri is not found, look for index.html, else pass everthing to gunicorn location / { index index.html; try_files $uri $uri/ @gunicorn; } # Django media location /media { alias /home/myuser/example.com/example-django/public/media; # your Django project's media files } # Django static files location /static { alias /home/myuser/example.com/example-django/public/static; # your Django project's static files } location @gunicorn { proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; #proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_redirect off; proxy_pass //0.0.0.0:8000; } client_max_body_size 100M; listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { server_name example.com; listen 443 ssl; ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; # managed by Certbot return 301 //www.example.com$request_uri; } server { if ($host = www.example.com) { return 301 //$host$request_uri; } # managed by Certbot if ($host = example.com) { return 301 //$host$request_uri; } # managed by Certbot listen 80 default_server; listen [::]:80 default_server; server_name example.com www.example.com; return 301 //$server_name$request_uri; }

Glabājiet konfigurācijas failu mapē /etc/nginx/sites-availableun izveidojiet tajā simbolisku saiti /etc/nginx/sites-enabled.

Es ceru, ka jums šī ziņa ir noderīga. Lūdzu, dariet man zināmu, ko jūs par to domājat, un parādiet to, ja vēlaties.