本文主要讲述了如何一步步在生产环境上部署 django 和 vue, 操作系统默认为 CentOS
说明: 后文中出现的以下字符串均表示具体的路径或者名称, 含义如下:
DJANGO_DIR---- 表示 django 的工程根目录
DJANGO_NAME---- 表示 django 的工程名称
VUE_html_DIR---- 表示 vue 编译好的 index.HTML 路径
VUE_STATIC_DIR---- 表示 vue 编译好的静态文件夹 static 的路径
整体框架
一个常用的 web 框架图如下图所示
框架选用. jpg
我们使用 nginx + uwsgi 来驱动 django, 因为 uwsgi 性能非常高
720333-20170312154455592-1425120615.PNG
一, 安装和配置 nginx
安装
使用 yum 安装即可
yum -y install nginx
启动
service nginx start
此时到浏览器输入对应的 ip 地址, 出现下面页面即表示安装成功
1324702136-57fb16aa00d21_articlex.PNG
修改配置文件
nginx 可以新建一个配置, 放在项目目录, 暂时不修改 nginx 的默认配置, 端口号可以换一个, 然后在 / etc/nginx/conf.d / 内新建一个软链接指向该配置文件, 这样 nginx 在读取配置时会将该配置一起读进去. 这样, 访问端口号 8080 的请求便会指向我们自己的这个配置.
- server {
- listen 8080;
- server_name 132.232.50.225;
- root /data/;
- charset utf-8;
- access_log /data/access_narwhals.log;
- error_log /data/error_narwhals.log;
- client_max_body_size 75M;
- location / {
- uwsgi_pass 127.0.0.1:9090;
- include /etc/nginx/uwsgi_params;
- }
- location ^~ /admin/ {
- uwsgi_pass 127.0.0.1:9090;
- include /etc/nginx/uwsgi_params;
- }
- }
该配置中 uwsgi_pass 要指向 uwsgi 绑定的接口.(我们先假设 uwsgi 配置的是 9090 端口)
二, 安装和配置 uwsgi
安装
使用 yum 或者 pip 均可安装
- yum install uwsgi
- # 或者
- pip install uwsgi
不过这里需要注意, 如果运行 uwsgi 出现下面错误
- uwsgi: option '--http' is ambiguous; possibilities: '--http-socket' '--https-socket-modifier2' '--https-socket-modifier1' '--https-socket' '--http11-socket' '--http-socket-modifier2' '--http-socket-modifier1'
- getopt_long() error
主要是用 yum 安装的 uwsgi, 缺少 python 的 plugin, 可以安装对应的插件
- yum install uwsgi-plugin-python
- plugins = python (加在 INI 配置文件中)
配置
uwsgi 可以使用命令行启动, 也可以使用配置文件来启动, 推荐使用配置文件来启动守护进程, 配置文件内容如下
- [uwsgi]
- socket = 127.0.0.1:9090
- stats = 127.0.0.1:9293
- workers = 4
- # 项目根目录
- chdir = DJANGO_DIR
- touch-reload = DJANGO_DIR
- py-auto-reload = 1
- # 在项目跟目录和项目同名的文件夹里面的一个文件
- module= DJANGO_NAME.wsgi
- pidfile = /var/run/inner_manager.pid
- daemonize = /data/uwsgi9090.log
- # If you plan to receive big requests with lots of headers you can increase this value up to 64k (65535).
- buffer-size=65535
这里以 socket 形式运行 uwsgi, 绑定了本地的 9090 端口, 也就是上文 nginx 配置中 uwsgi_pass 指定的端口.
大概解释下几个配置的含义:
chdir---- 应用加载前 chdir 到指定目录, 一般设置为 django 的工程根目录
touch-reload---- 如果修改 / 碰了指定的文件, 那么重载 uWSGI
module---- 加载一个 WSGI 模块的路径, 如果 django 的话就指向对应的 wsgi 文件模块
buffer-size---- 设置请求的最大大小 (排除 request-body), 这一般映射到请求头的大小. 默认情况下, 它是 4k. 如果你接收到了一个更大的请求 (例如, 带有大 cookies 或者查询字符串), 那么你也许需要增加它. 它也是一个安全度量, 所以调整为你的应用需要, 而不是最大输出. 该值如果太小会报错
具体参数含义可以到官方文档查找
然后使用命令启动 uwsgi 进程, 其中 uwsgi.INI 为上面内容的配置文件
uwsgi -i uwsgi.INI
可以看下日志文件有没有报错, 或者看下 ps -ef|grep uwsgi 进程有没有跑起来. 一定要确保进程正常 run 起来才行
至此, DJANGO 已经通过 nginx+uwsgi 可以访问了
三, 配置访问 vue
其实这里访问编译好的 vue 静态文件有很多方式, 本文主要讲述通过 nginx 直接访问和通过 django 路由访问
通过 django 路由访问
其实我们也可以直接通过 http://ip:8080/ 来经由 django 的路由来访问 vue 的页面. 当然要做到这样要确保以下配置的正确
找到 DJANGO_DIR 根目录下 DJANGO_NAME 同名文件夹下 urls.py, 使用通用视图创建最简单的模板控制器, 增加一行路由
url(r'^$', TemplateView.as_view(template_name="index.html")),
这样访问 http://ip:8080 / 时会直接返回 index.HTML.
上一步使用了 Django 的模板系统, 所以需要配置一下模板使 Django 知道从哪里找到 index.HTML. 在 project 目录的 settings.py 下:
- TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [VUE_HTML_DIR],
- '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',
- ],
- },
- },
- ]
按照上述配置完成后, 结合前面配置好的 nginx 和 uwsgi, 你已经可以通过 http://ip:8080/ 来访问到对应的 vue 编译好的 VUE_HTML_DIR 目录下的 index.HTML 了, 但是这时候你可能会有其他困扰, 比如找不到 CSS 样式文件的问, 这经常是静态配置有误导致找不到静态文件的问题.
Django 通过 django.contrib.staticfiles 来管理静态文件, 首先确保 django.contrib.staticfiles 已经添加到 INSTALLED_APPS.
然后可以在 DJANGO 的配置文件 settings.py 中增加以下几个配置:
- STATIC_URL = '/static/'
- STATIC_ROOT = os.path.join(BASE_DIR, "static")
- # Add for vuejs
- STATICFILES_DIRS = [
- VUE_STATIC_DIR,
- # other static folders
- ]
STATIC_URL 对外提供 Web 访问时 static 的 URL 地址
STATIC_ROOT 设置绝对路径, 用来保存收集到的静态文件, 服务器最终也将从该路径中获取文件进行转发. 在 collectstatic 运行的时候会把 STATICFILES_DIRS 中的静态文件拷贝到这个目录中, 达到从开发环境到生产环节过程中移植静态文件的作用.
STATICFILES_DIRS 用来配置一些开发环境下生成的静态文件的地址, 即编译好的 VUE_STATIC_DIR
在 url.py 中添加路由
- url(r'^static/(?P<path>.*)$', static.serve,
- {'document_root': settings.STATIC_ROOT}, name='static'),
配置好以上配置后, 编译好的静态文件还在 VUE_STATIC_DIR 目录下, 我们最终要执行下面命令才能把 STATICFILES_DIRS 中的静态文件拷贝到 STATIC_ROOT 这个目录中, 也就是最终生产环境指定的 static 的存放目录
python manage.py collectstatic
那么为什么不直接手动把构建好的 VUE_STATIC_DIR 中的文件拷过来呢, 因为 Django 自带的 App:admin 也有一些静态文件 (CSS,JS 等), 它会一并 collect 过来, 毕竟 nginx 只认项目跟目录的静态文件, 它不知道 django 把它自己的需求文件放到哪了
这样你访问 django 的 admin 网址 http://ip:8080/admin 时, 也不会出现找不到 CSS 的问题了
当然这种方式其实是通过 django 的路由来访问静态文件的, 一般的, 生产环境不会通过 django 来转发静态文件, 而是通过其他服务器进行转发, 比如 nginx,apache 等, 所以这里我们需要再配置下 nginx 的配置文件, 在 8080 的 server 中增加如下路径的配置
- location /static/ {
- expires 30d;
- autoindex on;
- add_header Cache-Control private;
- alias VUE_STATIC_DIR;
- access_log off;
- }
这样访问静态文件便会直接通过 nginx 来访问了, 不用担心静态文件访问导致 Django 的处理速度变慢了.
通过 nginx 直接访问
如果你想直接通过 nginx 访问对应的前端 vue 文件, 可以重新配置一个 server 来访问对应的 HTML 文件, 比如上面已经使用了 8080 端口, 我们可以用默认的 80 端口来配置个 server, 其中 root 可以指向存放 index.HTML 文件的路径,/static / 路径下的 root 路径可以指向 HTML 对应的存放 CSS 和 JS 的 static 文件夹, 如果 static 就在 index.HTML 路径下, 不指认也可以. 直接修改 / etc/nginx.conf 即可, 里面已经有配置好的 80 端口的 server
配置如下所示
- server {
- listen 80 default_server;
- listen [::]:80 default_server;
- server_name _;
- root VUE_HTML_DIR;
- # Load configuration files for the default server block.
- include /etc/nginx/default.d/*.conf;
- location / {
- }
- location /static/ {
- root VUE_STATIC_DIR;
- access_log off;
- }
- error_page 404 /404.HTML;
- location = /40x.HTML {
- }
- error_page 500 502 503 504 /50x.HTML;
- location = /50x.HTML {
- }
- }
这样我们可以通过 http://ip:80/ 来访问 vue 编译好的页面, 使用 http://ip:8080/ 访问 django 配置的 CGI 请求
四, 通过 supervisor 管理进程
上面我们已经用到了 uwsgi, 后面可能还会用到 Redis,celery, 都需要开启守护进程, 其中 celery 自身还不支持守护进程. 那么如何管理这么多进程呢, 这时候可以考虑下 supervisor
安装
使用 pip 安装即可
pip install supervisor
配置
我们可以配置 Redis,celery,uwsgi 进去, 比如向下面一样
[program:Redis]
; 指定运行目录
directory=%(here)s/
; 执行命令 (Redis-server Redis 配置文件路径)
command=Redis-server /etc/Redis.conf
; 启动设置
numprocs=1 ; 进程数
autostart=true ; 当 supervisor 启动时, 程序将会自动启动
autorestart=true ; 自动重启
; 停止信号
- stopsignal=INT
- [program:celery.worker.default]
; 指定运行目录
directory=%(here)s/
; 运行目录下执行命令
- command=celery -A DjangoProject worker --loglevel info --logfile log/celery_worker.log -Q default -n %%h-%(program_name)s-%(process_num)02d
- process_name=%(process_num)02d
; 启动设置
numprocs=2 ; 进程数
autostart=true ; 当 supervisor 启动时, 程序将会自动启动
autorestart=true ; 自动重启
; 停止信号, 默认 TERM
; 中断: INT (类似于 Ctrl+C)(kill -INT pid), 退出后会将写文件或日志 (推荐)
; 终止: TERM (kill -TERM pid)
; 挂起: HUP (kill -HUP pid), 注意与 Ctrl+Z/kill -stop pid 不同
; 从容停止: QUIT (kill -QUIT pid)
- stopsignal=INT
- [program:uwsgi]
; 指定运行目录
directory=%(here)s/
; 运行目录下执行命令
command=uwsgi -i conf/uwsgi/uwsgi9090.INI
; 启动设置
numprocs=1 ; 进程数
autostart=true ; 当 supervisor 启动时, 程序将会自动启动
autorestart=true ; 自动重启
; 停止信号, 默认 TERM
; 中断: INT (类似于 Ctrl+C)(kill -INT pid), 退出后会将写文件或日志 (推荐)
; 终止: TERM (kill -TERM pid)
; 挂起: HUP (kill -HUP pid), 注意与 Ctrl+Z/kill -stop pid 不同
; 从容停止: QUIT (kill -QUIT pid)
stopsignal=INT
使用
启动 supervisor 输入如下命令, 使用具体的配置文件执行:
supervisord -c supervisord.conf
关闭 supervisord 需要通过 supervisor 的控制器:
supervisorctl -c supervisord.conf shutdown
重启 supervisord 也是通过 supervisor 的控制器:
supervisorctl -c supervisord.conf reload
一些特殊的变量
%(here)s 配置文件所在路径
(program_name)s program 的名字
%(process_num)02d 多进程时的进程号
注意: command 中如果含有 %, 需要进行转义 %%
多进程时如果不指定 process_name 会遇到如下错误
Error: Format string 'celery -A INTProject worker --loglevel info --logfile log/celery_worker.log -Q diff_task,caller_task -n %h' for 'program:celery.worker.mac.command' is badly formatted: incomplete format in section 'program:celery.worker.mac' (file: 'supervisord.conf')
中间可能遇到的坑
*8107 recv() failed (104: Connection reset by peer) while reading response header from upstream, client 错误
使用 django+uwsgi+nginx, 发现如下报错
- 2018/10/08 14:34:33 [error] 12283#0: *8107 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 9.19.161.66, server: 132.232.50.225, request: "GET /auth/info?token=ZXlKaGJHY2lPaUprWldaaGRXeDBJaXdpZEhsd0lqb2lTbGRRSW4wOjFnOVA3aDp0bVZYcmg3XzJPR3RXSHJrbXFLRVdCZEpUdXc_ZXlKMWMyVnlibUZ0WlNJNkltVjBhR0Z1Wm1GdUlpd2lhV0YwSWpveE5UTTRPVGd3TkRjekxqZzVNekk1TVgwOjFnOVA3aDpMVXRHZkFiQkhrRTNaenFnS3NuS1RvOHBOMGM_3bdf34e6de16096f9982015a2382d3c8 HTTP/1.1", upstream: "uwsgi://127.0.0.1:9090", host: "int.oa.com", referrer: "http://int.oa.com/"
- I finally found a reference to fastcgi and a 502 bad gateway error (). That lead me to look for a buffer size limit in the uwsgi configuration which exists as buffer-size. The default value is 4096. From the documentation, it says:
- If you plan to receive big requests with lots of headers you can increase this value up to 64k (65535).
意思是 uwsgi 中有一项配置是 buffer-size, 表明收到的最大请求 size, 默认是 4096, 可以将其改成 65535
- buffer-size=65535
- # 四 参考
- https://www.cnblogs.com/alex3714/p/6538374.html
来源: https://www.qcloud.com/developer/article/1369040