Django+uwsgi+asgi+nginx部署项目
- Uwsgi
- uwsgi.ini 中 http 与socket 区别:
- 文件目录位置
- 启动uwsig
- 启动 websokcet的ASGI
- 启动配置
- 踩坑
- nginx 配置
Uwsgi
uWSGI 配置文件中 Magic variables的含义 前缀为百分号:
%v vassals 目录 (pwd)
%V uWSGI 版本
%H 主机名
%o 在命令行中指定的原始配置文件名
%O 与 %o 相同,但指的是第一个非模板配置文件(版本 1.9.18)
%p 配置文件的绝对路径
%P 与 %p 相同,但参考第一个非模板配置文件(版本 1.9.18)
%s 配置文件的文件名
%S 与 %s 相同,但指的是第一个非模板配置文件(版本 1.9.18)
%d 包含配置文件的目录的绝对路径
%D 与 %d 相同,但指的是第一个非模板配置文件(版本 1.9.18)
%e 配置文件的扩展名
%E 与 %e 相同,但指的是第一个非模板配置文件(版本 1.9.18)
%n 没有扩展名的文件名
%N 与 %n 相同,但参考第一个非模板配置文件(版本 1.9.18)
%C 包含配置文件的目录的名称(版本 1.3+)
%C 与 %c 相同,但指的是第一个非模板配置文件(版本 1.9.18)
%t unix 时间(以秒为单位,在实例启动时收集)(版本 1.9.20-dev+)
%T unix 时间(以微秒为单位,在实例启动时收集)(版本 1.9.20-dev+)
%x 当前部分标识符,例如。config.ini:section(版本 1.9-dev+)
%X 与 %x 相同,但参考第一个非模板配置文件(版本 1.9.18)
%i 文件的 inode 编号(版本 2.0.1)
%I 与 %i 相同,但指的是第一个非模板配置文件
%0..%9 包含配置文件的目录完整路径的特定组件(版本 1.3+)
%[ ANSI 转义符“\033”(用于打印颜色)
%k 检测到的 CPU 内核(版本 1.9.20-dev+)
%u 运行进程的用户的 uid(2.0 版)
%U 运行进程的用户的用户名(如果可用,否则回退到 uid)(版本 2.0)
%G 运行该进程的用户的 gid(版本 2.0)
%G 运行进程的用户的组名(如果可用,否则回退到 gid)(版本 2.0)
%j 完整配置路径的 djb33x 哈希的十六进制表示
%J 与 %j 相同,但指的是第一个非模板配置文件
先放上配置页面 uwsgi.ini文件:
[uwsgi]
#项目目录
chdir = %d../vs12_service_api
#指定IP端口,如果
;http = :8007
socket = 0.0.0.0:8008
#指定项目的application
module = vs12_service_api.wsgi:application
#进程
#启动个worker进程数量
processes = 3
#每个worker进程中创建线程数量
threads = 3
#设置用于uwsgi包解析的内部缓存区大小单位字节。默认是4k。
buffer-size = 65535
#set cpu affinity 这个地方不太懂 以前老项目这么设置的我也拿过来用了
cpu-affinity = 1
run_dir = %(chdir)/../run
#指定pid文件
pidfile = %(run_dir)/uwsgi.pid
#指定log文件
logto = %(run_dir)/uwsgi.log
#设置最大log文件大小
log-maxsize = 100000000
# 在每个worker而不是master中加载应用。默认为false,表示先加载应用,再fork出worker,这样做可以让work尽量共用内存,只有当写时才copy
# 由于先加载再fork,但有些东西是不支持fork的,比如socket连接,所以lazy-apps=false时,不要在加载应用时自动创建数据库连接等
lazy-apps = true
uwsgi.ini 中 http 与socket 区别:
先说最简单的 http 这个是作为一个独立的服务器启动 ,然后由NGINX
作为一个比如18008端口的中介用来转发,如上面配置,浏览器或着postman, 还是能直接访问这个8007端口的 socket
是在内存中遵循socket协议和NGINX内存交换,不可以直接用浏览器或者postman直接访问
http与socket在nginx中的设置也是不一样的,文章中的nginx设置只是配置的socket的,如果是http则需要另外配置
文件目录位置
uwsgi.ini 可以放到项目中的 manage.py 文件的同级别目录下,也可以像我一样放在项目的外面,项目结构如下图,图可见 我的uwsgi.ini 放在的项目同级别文件deploy中了,所以再配置中 指定项目目录时要 通过 ”%d…/ “ 找到对应的项目
启动uwsig
uwsgi --ini deploy/uwsgi.ini #启动命令
[uWSGI] getting INI configuration from deploy/uwsgi.ini
可以通过 ini文件中配置的log文件 查看运行状态:
sudo tail -n 10 -f run/uwsgi.log
[pid: 31725|app: 0|req: 1/1] 192.168.99.134 () {46 vars in 862 bytes} [Fri Sep 10 16:23:27 2021] GET /v1/system/equipment/group => generated 7868 bytes in 314 msecs (HTTP/1.1 200) 5 headers in 177 bytes (1 switches on core 0)
/home/zhao/.virtualenvwrapper/vs12Env/lib/python3.7/site-packages/pymysql/cursors.py:170: Warning: (3135, "'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release.")
result = self._query(query)
/home/zhao/.virtualenvwrapper/vs12Env/lib/python3.7/site-packages/pymysql/cursors.py:170: Warning: (3135, "'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION_BY_ZERO' sql modes should be used with strict mode. They will be merged with strict mode in a future release.")
result = self._query(query)
station {'uuid': '3525f36db2c14df2a68efef29eaa2647', 'station_id': 1, 'station_name': '本地测试卫通站', 'station_code': '007', 'manager': None, 'station_type': 1, 'frequency_range': 14, 'longitude': 117.0645, 'latitude': 36.95, 'antenna_power': 40, 'antenna_aperture': 2, 'station_status': 1, 'satellite_id': 101541, 'station_ip': '192.168.99.15', 'station_port': 8007, 'inet_mask': '255.255.255.0 ', 'inet_gateway': '8010'}
[pid: 31724|app: 0|req: 1/2] 192.168.99.134 () {46 vars in 838 bytes} [Fri Sep 10 16:23:29 2021] GET /v1/station/station/info => generated 489 bytes in 223 msecs (HTTP/1.1 200) 5 headers in 150 bytes (1 switches on core 0)
[pid: 31723|app: 0|req: 1/3] 192.168.99.134 () {46 vars in 840 bytes} [Fri Sep 10 16:23:29 2021] GET /v1/system/equipment/topo => generated 518483 bytes in 262 msecs (HTTP/1.1 200) 5 headers in 179 bytes (1 switches on core 0)
[pid: 31724|app: 0|req: 2/4] 192.168.99.134 () {42 vars in 810 bytes} [Fri Sep 10 16:23:30 2021] GET /v1/system/equipment/topo?id=6 => generated 123720 bytes in 35 msecs (HTTP/1.1 200) 5 headers in 179 bytes (1 switches on core 1)
启动 websokcet的ASGI
因为本次websocket是用的django channles库,默认用的是asgi ,所以使用官方推荐的asgi服务器daphne来启动
需要用的库,django是2.2.2 如果是其他版本可能库的版本有所区别:
pip install channels==2.4.0
pip install channels-redis==2.3.2
pip install asgiref==3.2.1
pip install daphne==2.5.0
启动配置
在settings.py同级目录中添加asgi.py文件内容如下:
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "vs12_service_api.settings")
django.setup()
from channels.auth import AuthMiddlewareStack
from channels.routing import get_default_application
from channels.auth import AuthMiddlewareStack
from channels.sessions import SessionMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
import vs12_system.routing
application = ProtocolTypeRouter({
# "http": get_default_application(),
'websocket': AuthMiddlewareStack(
URLRouter(
vs12_system.routing.websocket_urlpatterns
)
),
})
settings.py文件中添加配置:
INSTALLED_APPS = [
'channels',
...
]
# 这里对应刚刚创建的asgi文件中的application
ASGI_APPLICATION = 'vs12_service_api.asgi.application'
在mange.py 同级目录下运行:
#跟settings文件中的ASGI_APPLICATION 相对应启动端口为 8009
#启动
daphne vs12_service_api.asgi:application -b 0.0.0.0 -p 8009 #启动命令
[WARNING] DJANGO_SETTINGS_MODULE=vs12_service_api.settings
Will use settings/local.py
2021-09-10 16:12:54,313 INFO Starting server at tcp:port=8009:interface=0.0.0.0
2021-09-10 16:12:54,314 INFO HTTP/2 support not enabled (install the http2 and tls Twisted extras)
2021-09-10 16:12:54,314 INFO Configuring endpoint tcp:port=8009:interface=0.0.0.0
2021-09-10 16:12:54,316 INFO Listening on TCP address 0.0.0.0:8009
具体 websocket 开发可以参考:
Django使用Channels实现WebSocket消息通知功能
踩坑
如果出现 ***AttributeError: module ‘asyncio.coroutines’ has no attribute ‘_is_coroutine’***这个错误有可能是 asgiref 的版本不对 ,安装 3.2.1版本
pip install asgiref==3.2.1
nginx 配置
server{
#监听8007端口
listen 18007;
#因为webocket的 url开始是equipment所以监听 以 /equipment开头的url
location /equipment {
proxy_pass http://127.0.0.1:8007;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
location /v1 {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#端口要和uwsgi里配置的一样
uwsgi_pass uwsgi://127.0.0.1:8008;
include uwsgi_params;
}
location / {
root /srv/vs12prj/vs12prj/src/dist;
try_files $uri $uri/ /index.html;
}
}