Дјанго у дивљини: савети за преживљавање распоређивања

Пре него што примените своју Дјанго веб апликацију у стварном свету, морате да се уверите да је ваш пројекат спреман за производњу. Боље започети њихову примену раније. Штеди вама и вашем тиму пуно времена и главобоље. Ево неколико тачака које сам научио током пута:

  1. Користите пипенв (или рекуирементс.ткт + венв). Урежите Пипефиле и Пипефиле.лоцк (или рекуирементс.ткт). Дај име свом венв.
  2. Имајте скрипту за брзи почетак.
  3. Напишите тестове. Користите Дјанго тест оквири Хипотеза.
  4. Користите окружењеи диренв за управљање поставкама и аутоматско учитавање променљивих околине.
  5. Уверите се да су сви програмери извршили миграцију. Повремене миграције сквоша. Ресетујте их ако је потребно. Архитектујте свој пројекат за углађеније миграције. Прочитајте о миграцијама.
  6. Користите континуирану интеграцију. Заштитите своју главну грану.
  7. Прођите кроз званичну Дјангову листу примене.
  8. Не управљајте својим сервером, али ако морате, користите одговарајућу структуру директоријума и Супервисорд, Гуницорн и НГИНКС.

Ова листа је органски расла док сам пролазио кроз издање наше прве Дјанго апликације и није коначна. Али мислим да су ово неке од најважнијих тачака којих морате бити свесни.

Прочитајте и расправу о свакој од тачака.

Управљајте зависностима и виртуелним окружењима на прави начин

Ви и ваш тим треба да се договорите о начину управљања зависностима и виртуелним окружењима. Препоручујем или употребу пипенв, што је нови начин управљања вашим виртуелним окружењима и зависностима, или коришћење старог доброг приступа стварању венв-а и праћењу зависности помоћу requirements.txtдатотеке.

Коришћење requirements.txtприступа склоно је људским грешкама, јер програмери обично заборављају на ажурирање листе пакета. Ово није проблем са пипенв-ом, јер аутоматски ажурира Пипефиле. Недостатак пипенв-а је тај што није постојао довољно дуго. Иако га службено препоручује Питхон Софтваре Фоундатион, можда ћете имати проблема са покретањем на неким машинама. Лично и даље користим стари приступ, али користићу пипенв за следећи пројекат.

Коришћење венв и рекуирементс.ткт

Ако користите Питхон ≥ 3,6 (требали бисте), можете једноставно да га направите помоћу python -m venv ENV. Обавезно именујте своје виртуелно окружење (уместо да га користите .). Понекад морате да избришете своје виртуелно окружење и направите га наново. То олакшава. Такође, требали бисте додати ENVдиректоријум у свој. gitignoreфајл (ја преферирам обл име уместо венв , .енв , ... јер се истиче када Је ли фасциклу пројекта).

Да би управљао зависностима, сваки програмер покреће се pip freeze > requirements.txt кад год инсталира нови пакет и додаје га и предаје у репо. Користиће их pip install -r requirements.txtкад год повуку из удаљеног спремишта.

Користећи пипенв

Ако користите пипенв , потребно је само да додате Пипфиле и Пипфиле.лоцк у свој репо.

Имајте скрипту за брзи почетак

Ово помаже да ваши програмери проведу што мање времена радећи на стварима које нису директно повезане са њиховим послом.

Ово не само да штеди време и новац, већ и осигурава да сви раде у сличним окружењима (исте верзије Питхона и пипа, на пример).

Дакле, покушајте да аутоматизујете што више задатака за подешавање.

Штавише, постојање скрипте за изградњу у једном кораку је најважније за други корак Јоела Теста.

Ево мале скрипте коју користим и која мојим програмерима штеди неколико кључних потеза:

#!/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

Напишите тестове

Сви знају да је писање тестова добра пракса. Али многи то превиде, ради бржег развоја, сматрају они. НЕМОЈ. Тестови су апсолутна потреба када је у питању писање софтвера који се користи у производњи, посебно када радите у тиму. Једини начин на који можете знати да најновије ажурирање није нешто покварило је да имате добро написане тестове. Такође, апсолутно су вам потребни тестови за континуирану интеграцију и испоруку вашег производа.

Дјанго има пристојан тест оквир. Такође можете да користите оквире за тестирање засноване на својствима, као што је Хипотеза, који вам помажу да напишете краће, математички ригорозне тестове за свој код. У многим случајевима писање тестова заснованих на својствима је брже. У пракси ћете можда на крају користити оба ова оквира за писање свеобухватних тестова који се лако читају и пишу.

За подешавања користите променљиве окружења

У вашој датотеци сеттингс.пи чувате сва важна подешавања пројекта: УРЛ базе података, путање до медија и статичких директоријума итд. Они ће имати различите вредности на вашој развојној машини и вашем производном серверу. Најбољи начин да се ово реши је употреба променљивих околине. Први корак је ажурирање вашег сеттингс.пи за читање из променљивих околине, користећи енвиронмент :

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

Да бисте избегли ручно учитавање енвварс-а, поставите диренв на својим развојним машинама и спремите енвварс у .envrcдатотеку у директоријуму вашег пројекта. Сада, кад год уђете cdу директоријум пројеката, променљиве окружења се аутоматски учитавају. Додајте .envrcу своје спремиште (ако сви програмери користе исте поставке) и обавезно покрените direnv allowкад год се .envrcдатотека промени .

Не користите direnvна производном серверу. Уместо тога, креирајте датотеку под називом .сервер.енврц , додајте је у .gitignoreи тамо поставите производна подешавања. Сада креирајте скрипту runinenv.shза аутоматско извор варијабли окружења .server.envrc, активирајте виртуелно окружење и покрените предвиђену наредбу. Видећете како се користи у следећем одељку. Ево како runinenv.shтреба изгледати (веза до ГитХуб-а).

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

Правилно се носите са својим миграцијама

Дјанго миграције су сјајне, али рад са њима, посебно у тиму, далеко је од без муке.

Прво, требали бисте бити сигурни да сви програмери урезују датотеке миграције. Да, можда ћете (имати) сукобе, посебно ако радите са великим тимом, али то је боље него да имате неусаглашену шему.

Генерално, бављење миграцијама није тако лако. Морате знати шта радите и морате следити неке најбоље праксе како бисте осигурали несметан ток посла.

Једна ствар коју сам претпоставио је да обично помаже ако повремено згњечите миграције (нпр. Недељно). Ово помаже у смањењу броја датотека и величине графикона зависности, што заузврат доводи до бржег времена израде и обично мање (или лакшег руковања) сукоба.

Понекад је лакше ресетовати миграције и изнова их изводити, а понекад је потребно ручно поправити неусаглашене миграције или их спојити. Генерално, бављење миграцијама је тема која заслужује властити пост, а има неколико добрих читања о овој теми:

  • Дјанго миграције и како управљати сукобима
  • Како ресетовати миграције

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

Обратите пажњу на то како овде користимо runinenv.sh(редови 14, 24 и 34). Такође обратите пажњу на ред 14, где кажемо гуницорн- у да пошаље 3 радника. Овај број зависи од броја језгара које има ваш сервер. Препоручени број радника је: 2 * број_бојева + 1.

Такође вам је потребан обрнути прокси да бисте сервер апликација повезали са спољним светом. Само користите НГИНКС, јер има широку базу корисника и врло је једноставан за конфигурисање (овај код можете пронаћи и на ГитХуб-у):

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

Спремите датотеку за конфигурацију у /etc/nginx/sites-availableи креирајте симболичку везу до ње /etc/nginx/sites-enabled.

Надам се да вам је овај пост био користан. Обавестите ме шта мислите о томе и покажите схов ако желите.