django 部署_狂野的Django:部署生存的技巧

django 部署

by Ali Alavi

通过Ali Alavi

狂野的Django:部署生存的技巧 (Django in the wild: tips for deployment survival)

Before deploying your Django web app in the real world, you need to make sure your project is production-ready. Better to start implementing them earlier. It saves you and your team a lot of time and headache. Here are some points I learned along the way:

在现实世界中部署Django Web应用程序之前,您需要确保您的项目已准备就绪。 最好尽早开始实施它们。 它为您和您的团队节省了很多时间和头痛。 这是我在学习过程中学到的几点:

  1. Use pipenv (or requirements.txt + venv). Commit Pipefile and Pipefile.lock (or requirements.txt). Name your venv.

    使用pipenv(或requirements.txt + venv)。 提交Pipefile和Pipefile.lock(或requirements.txt)。 命名您的venv。
  2. Have a quickstart script.

    有一个快速入门脚本。
  3. Write tests. Use the Django test framework and Hypothesis.

    编写测试。 使用Django测试框架 假设

  4. Use environ and direnv to manage your settings and automatically load your environment variables.

    使用环境 direnv来管理您的设置并自动加载环境变量。

  5. Make sure all developers commit their migrations. Squash migrations from time to time. Reset them if necessary. Architect your project for smoother migrations. Read about migrations.

    确保所有开发人员都提交其迁移。 壁球迁移有时会发生。 如有必要,请重置它们。 设计您的项目,以实现更平滑的迁移。 了解有关迁移的信息。
  6. Use continuous integration. Protect your master branch.

    使用持续集成。 保护您的主分支。
  7. Go through Django’s official deployment checklist.

    通过Django的官方部署清单。

  8. Don’t manage your own server, but if you must, use a proper directory structure, and use Supervisord, Gunicorn and NGINX.

    不要管理自己的服务器,但如果需要,请使用适当的目录结构,并使用Supervisord,Gunicorn和NGINX。

This list grew organically as I was going through the release our first Django app, and is not exhaustive. But I think these are some of the most important points you need to be aware of.

在我发布第一个Django应用程序时,该列表自然增长,但并不详尽。 但是我认为这些是您需要意识到的一些最重要的方面。

Read along for a discussion on each of the points.

请继续阅读以获取有关每个要点的讨论。

正确管理依赖项和虚拟环境 (Manage your dependencies and virtual environments the right way)

You and your team should agree on a way to manage your dependencies and virtual environments. I recommend either using pipenv, which is the new way of managing both your virtual environments and dependencies, or using the good old approach of creating a venv and tracking your dependencies with a requirements.txt file.

您和您的团队应就管理依赖关系和虚拟环境的方法达成共识。 我建议您使用pipenv ,这是管理虚拟环境和依赖关系的新方法,或者建议使用旧的良好方法来创建venv并使用requirements.txt文件跟踪依赖关系。

Using the requirements.txt approach is prone to human error, since developers tend to forget about updating the package list. This is not an issue with pipenv, since it automatically updates Pipefile. The drawback of pipenv is that it hasn’t been around long enough. Even though it is officially recommended by the Python Software Foundation, you might have issues getting it to run on some machines. Personally, I still use the old approach, but I will use pipenv for my next project.

由于开发人员往往会忘记更新软件包列表,因此使用requirements.txt方法容易出错。 这不是pipenv的问题因为它会自动更新Pipefile。 pipenv的缺点是还不够长。 即使Python Software Foundation 正式建议使用它,也可能在使它在某些计算机上运行时遇到问题。 就个人而言,我仍然使用旧方法,但是我将在下一个项目中使用pipenv

使用venv和requirements.txt (Using venv and requirements.txt)

If you are using Python ≥ 3.6 (you should be), you can simply create one with python -m venv ENV . Make sure you name your virtual environment (instead of using . ). Sometimes you need to delete your virtual environment and create it anew. It makes it easier. Also, you should add ENV directory to your .gitignore file (I prefer the ENV name instead of venv, .env, … since it stands out when I ls the project folder).

如果使用的python -m venv ENV (应该是),则可以简单地使用python -m venv ENV创建一个。 确保命名虚拟环境(而不是使用. )。 有时您需要删除虚拟环境并重新创建它。 这使其更容易。 另外,您应该将ENV目录添加到。 gitignore文件(我更喜欢ENV名称,而不是VENV,.ENV,......因为它代表了当我LS项目文件夹)。

To manage the dependencies, every developer runs pip freeze > requirements.txt whenever they install a new package, and add and commit it to the repo. They will use pip install -r requirements.txt whenever they pull from the remote repository.

为了管理依赖关系,每位开发人员在安装新软件包时都运行pip freeze > requirements.txt ,并将其添加并提交到仓库中。 每当他们从远程存储库中提取时,他们将使用pip install -r requirements.txt

使用pipenv (Using pipenv)

If using pipenv, you just need to add Pipfile and Pipfile.lock to your repo.

如果使用pipenv ,则只需将Pipfile和Pipfile.lock添加到您的仓库中。

有一个快速入门脚本 (Have a quickstart script)

This helps make sure your developers spend as little time as possible working on things not directly related to their job.

这有助于确保您的开发人员将尽可能少的时间花在与他们的工作没有直接关系的事情上。

Not only does this save time and money, but also makes sure that they are all working on similar environments (same versions of Python and pip, for example).

这不仅可以节省时间和金钱,还可以确保它们都在相似的环境(例如,相同版本的Python和pip)上工作。

So, try to automate as many setup tasks as possible.

因此,尝试自动执行尽可能多的设置任务。

Moreover, having a single step build script is very much what Joel Test’s 2nd step is about.

而且,只有一个步骤的构建脚本与Joel Test的第二步差不多。

Here is a small script I use, which saves my developers quite a few key strokes:

这是我使用的一个小脚本,为我的开发人员节省了很多按键:

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

编写测试 (Write tests)

Everyone knows writing tests is a good practice. But many overlook it, for the sake of, they think, faster development. DON’T. Tests are an absolute necessity when it comes to writing software used in production, especially when you work in a team. The only way you can know that the latest update did not break something is to have well-written tests. Also, you absolutely need tests for continuous integration and delivery of your product.

每个人都知道编写测试是一种好习惯。 但是他们认为,为了更快的发展,许多人忽略了它。 别。 在编写生产中使用的软件时,尤其是在团队中工作时,测试是绝对必要的。 您可以知道最新更新没有破坏某些东西的唯一方法是进行精心编写的测试。 另外,您绝对需要测试才能持续集成和交付产品。

Django has a decent test framework. You can also use property-based testing frameworks such as Hypothesis, which help you write shorter, mathematically rigorous tests for your code. For many cases, writing property-based tests is faster. In practice, you might end up using both these frameworks for writing comprehensive, easy-to-read-and-write tests.

Django有一个不错的测试框架 。 您还可以使用基于属性的测试框架,例如Hypothesis ,它可以帮助您为代码编写较短的,数学上严格的测试。 在许多情况下,编写基于属性的测试更快。 实际上,您可能最终会同时使用这两个框架来编写全面的,易于阅读和编写的测试。

使用环境变量进行设置 (Use environment variables for settings)

Your settings.py file is where you store all important project settings: your database URL, paths to media and static folders, and so on. These will have different values on your development machine and your production server. The best way to address this is to use environment variables. The first step is to update your settings.py to read from the environment variables, using environ:

您的settings.py文件是存储所有重要项目设置的位置:数据库URL,媒体和静态文件夹的路径等。 这些将在您的开发计算机和生产服务器上具有不同的值。 解决此问题的最佳方法是使用环境变量。 第一步是使用environ更新您的settings.py以读取环境变量

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

..

To avoid loading your envvars manually, set up direnv on your development machines, and store the envvars in a .envrc file in your project directory. Now, whenever you cd into your projects folder, the environment variables are automatically loaded. Add .envrc to your repository (if all developers use the same settings), and make sure you run direnv allow whenever there is a change in .envrc file.

为避免手动加载envvar ,请在开发计算机上设置direnv ,然后将.envrc存储在项目目录中的.envrc文件中。 现在,只要将cd放入项目文件夹,环境变量就会自动加载。 将.envrc添加到您的存储库(如果所有开发人员都使用相同的设置),并确保每当.envrc文件发生更改时,您就运行direnv allow

Don’t use direnv on your production server. Instead, create a file called .server.envrc, add it to the .gitignore, and put the production settings there. Now, create a script,runinenv.sh, to automatically source the environment variables from .server.envrc, activate the virtual environment, and run the provided command. You will see how it is used in the next section. Here is how runinenv.sh should look (link to GitHub).

不要在生产服务器上使用direnv 。 而是创建一个名为.server.envrc的文件,将其添加到.gitignore ,然后将生产设置放在此处。 现在,创建一个脚本runinenv.sh ,以从.server.envrc自动获取环境变量,激活虚拟环境,并运行提供的命令。 您将在下一节中看到如何使用它。 这是runinenv.sh外观( 链接到GitHub )。

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

正确处理您的迁移 (Handle your migrations properly)

Django migrations are great, but working with them, especially in a team, is far from hassle-free.

Django迁移很棒,但是与它们(尤其是在团队中)一起工作并非易事。

First, you should make sure that all developers commit the migration files. Yes, you might (will) end up having conflicts, especially if you work with a large team, but it’s better than having an inconsistent schema.

首先,您应确保所有开发人员都提交迁移文件。 是的,您可能(将)最终有冲突,特别是如果您与一个大型团队一起工作时,这比拥有不一致的架构更好。

In general, dealing with migrations is not that easy. You need to know what you are doing, and you need to follow some best practices to ensure a smooth workflow.

通常,处理迁移并不是那么容易。 您需要知道自己在做什么,并且需要遵循一些最佳实践以确保工作流程顺畅。

One thing that I figured is that it usually helps if you squash the migrations from time to time (e.g. on a weekly basis). This helps with reducing the number of files and the size of the dependency graph, which in turn leads to faster build time, and usually fewer (or easier to handle) conflicts.

我想到的一件事是,如果您不时压缩迁移(例如每周一次),通常会有所帮助。 这有助于减少文件数量和依赖关系图的大小,从而缩短构建时间,并且通常减少冲突(或更易于处理)。

Sometimes it’s easier to reset your migrations and make them anew, and sometimes you need to manually fix the conflicting migrations or merge them together. In general, dealing with migrations is a topic which deserves its own post, and there are some good reads on this topic:

有时候重置迁移并重新进行迁移比较容易,有时您需要手动修复冲突的迁移或将它们合并在一起。 总的来说,处理迁移是一个值得发表的话题,对此话题有一些不错的阅读:

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.

我强烈建议您阅读这篇有关扩展Django应用程序的出色文章 ,其中涵盖了该主题。 它还有一个很小的,有用的迁移脚本。

使用持续集成 (Use Continuous Integration)

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

CI背后的想法很简单:在推送新代码后立即运行测试。

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.

使用与您的版本控制平台良好集成的解决方案。 我最终使用CircleCI 。 当您与多个开发人员一起工作时,CI特别有用,因为您可以确保他们的代码在发送拉取请求之前通过所有测试。 再次,正如您所看到的,适当地进行覆盖测试非常重要。 此外,请确保您的master分支受到保护。

部署清单 (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.

Django的官方网站提供了一个方便的部署清单 。 它可以帮助您确保项目的安全性和性能。 确保遵循这些准则。

如果您必须管理自己的服务器… (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.

不管理自己的服务器有许多充分的理由。 Docker为您提供了更多的可移植性和安全性,并且无服务器架构(例如AWS Lambda)可以以更少的钱为您提供更多的好处。

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.

首先要做的是使用适当的文件夹结构。 如果您要在服务器上提供的只是Django应用程序,则可以简单地克隆存储库并将其用作主目录。 但是这种情况很少见:通常您还需要一些静态页面(主页,联系人等)。 它们应与您的Django代码库分开。

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:

解决此问题的一个好方法是创建一个父存储库,该存储库将项目的不同部分作为子模块。 您的Django开发人员在django资源库中工作,设计师在主页资源库中工作,…,然后将所有这些集成到资源库中:

example.com/
   example-django/
   homepage/

使用Supervisord,NGINX和Gunicorn (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.

当然, manage runserver可以运行,但仅用于快速测试。 对于任何严重的问题,您需要使用适当的应用程序服务器。 独角兽是要走的路。

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 .

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需要一个配置文件,在其中我们告诉我们如何运行我们的流程。 而且它不仅限于我们的应用服务器。 如果我们还有其他长期运行的进程(例如celery),则应在/etc/supervisor/supervisord.conf定义它们。 这是一个示例( 也在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

Note how we use runinenv.sh here (lines 14, 24 and 34). Also, pay attention to line 14, where we tell gunicorn to dispatch 3 workers. This number depends on the number of cores your server has. The recommended number of workers is: 2*number_of_cores + 1.

注意这里我们如何使用runinenv.sh (第14、24和34行)。 另外,请注意第14行,我们告诉Gunicorn派遣3名工人。 此数字取决于服务器具有的核心数。 建议的工作人员数量为:2 * number_of_cores + 1。

You also need a reverse proxy to connect your application server to the outside world. Just use NGINX, since it has a wide user base, and it’s very easy to configure (you can also find this code on GitHub):

您还需要反向代理才能将您的应用程序服务器连接到外界。 只需使用NGINX ,因为它拥有广泛的用户基础,并且配置非常容易( 您也可以在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 http://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 https://www.example.com$request_uri;
    
}

server {
    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    
if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
    
listen 80 default_server;
    listen [::]:80 default_server;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

Store the configuration file in /etc/nginx/sites-available, and create a symbolic link to it in /etc/nginx/sites-enabled.

将配置文件存储在/etc/nginx/sites-available ,并在/etc/nginx/sites-enabled创建指向该文件的符号链接。

I hope you’ve found this post helpful. Please let me know what you think about it, and show it some ❤ if you will.

希望这篇文章对您有所帮助。 请让我知道您的想法,如果可以,请向其显示❤。

翻译自: https://www.freecodecamp.org/news/django-in-the-wild-tips-for-deployment-survival-9b491081c2e4/

django 部署

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值