部署方式:
1.升级python
CentOS 7 中默认安装了 Python,版本比较低(2.7.5),为了使用新版 3.x,需要对旧版本进行升级。
由于很多基本的命令、软件包都依赖旧版本,比如:yum。所以,在更新 Python 时,建议不要删除旧版本(新旧版本可以共存)
查看 Python 版本号
当 Linux 上安装 Python 后(默认安装),只需要输入简单的命令,就可以查看 Python 的版本号:
# python -V
Python 2.7.5
使用 wget 将安装包都下载到 /Downloads/
[root@localhost Downloads]# ll
总用量 40932
drwxr-x---. 18 root root 4096 9月 26 12:22 Python-2.7
-rw-r--r--. 1 root root 14026384 9月 26 12:22 Python-2.7.tgz
drwxr-xr-x. 19 root root 4096 9月 26 14:13 Python-3.7.0
-rw-r--r--. 1 root root 22745726 9月 26 12:21 Python-3.7.0.tgz
-rw-r--r--. 1 root root 41313 9月 26 12:22 python-iniparse-0.4-18-omv4002.noarch.rpm
-rw-r--r--. 1 root root 39780 9月 26 12:22 python-sqlite-1.1.7-1.2.0.99_4.el4.at.x86_64.rpm
drwxr-xr-x. 5 1000 1000 4096 9月 26 14:56 sqlite-autoconf-3300100
-rw-r--r--. 1 root root 2848951 9月 26 12:22 sqlite-autoconf-3300100.tar.gz
drwxrwxr-x. 20 30001 30001 4096 6月 20 2020 uwsgi-2.0.19.1
-rw-r--r--. 1 root root 811149 9月 26 12:22 uwsgi-2.0.19.1.tar.gz
-rw-r--r--. 1 root root 1298856 9月 26 12:22 yum-3.4.3-168.el7.centos.noarch.rpm
-rw-r--r--. 1 root root 28348 9月 26 12:22 yum-metadata-parser-1.1.4-10.el7.x86_64.rpm
-rw-r--r--. 1 root root 35216 9月 26 12:22 yum-plugin-fastestmirror-1.1.31-54.el7_8.noarch.rpm
[root@localhost Downloads]#
1、环境准备:先安装准备环境
yum install gcc gcc-c++ automake pcre pcre-devel zlip zlib-devel openssl openssl-devel
解压
# tar -zxvf Python-3.7.0.tgz
安装配置
进入解压缩后的目录,安装配置:
# cd Python-3.7.0/
# ./configure make && make install
验证
安装成功以后,就可以查看 Python 的版本了:
# python -V
Python 2.7.5
# python3 -V
Python 3.7.0
一个是旧版本 2.x,另外一个是新版本 3.x。
注意:在 /usr/local/bin/ 下有一个 python3 的链接,指向 bin 目录下的 python 3.7。
设置 3.x 为默认版本
查看 Python 的路径,在 /usr/bin 下面。可以看到 python 链接的是 python 2.7,所以,执行 python 就相当于执行 python 2.7。
将原来 python 的软链接重命名:
# mv /usr/bin/python /usr/bin/python.bak
将 python 链接至 python3:
# ln -s /usr/local/bin/python3 /usr/bin/python
这时,再查看 Python 的版本:
# python -V
Python 3.7.0
输出的是 3.x,说明已经使用的是 python3了。
配置 yum
升级 Python 之后,由于将默认的 python 指向了 python3,yum 不能正常使用,需要编辑 yum 的配置文件:
# vi /usr/bin/yum
同时修改:
# vi /usr/libexec/urlgrabber-ext-down
将 #!/usr/bin/python 改为 #!/usr/bin/python2.7,保存退出即可。
2.升级 sqlite3 解决Django.core.exceptions.ImproperlyConfigured: SQLite 3.9.0 or later is required (found 3.7.17)。
CentOS 自带 3.7.17 Django,不支持。它必须高于 3.9.0。如果你想用SQLite3作为数据库,是没有办法升级的。如果是我,我不会用SQLite3,而是用mysql
升级很简单:
1.下载SQLite3最新包
https://www.sqlite.org/download.html wget https://www.sqlite.org/2021/sqlite-autoconf-3350500.tar.gz
2.编译安装 tar xf https://www.sqlite.org/2021/sqlite-autoconf-3350500.tar.gz cd sqlite-autoconf-3350500 ./configure --prefix=/usr/local/ && make && make install
3.改变原来的SQLite3命令
首先检查SQLite3在哪个目录中有可执行文件
[root@localhost Downloads]# whereis sqlite3 sqlite3: /usr/bin/sqlite3 /usr/local/bin/sqlite3 /usr/share/man/man1/sqlite3.1.gz [root@localhost Downloads]# sqlite3 -V
发现/usr/bin/SQLite3是旧的,3.7.17。如果您不确定,请执行它
/usr/bin/sqlite3 –version
然后替换旧版本
mv /usr/bin/sqlite3 /usr/bin/sqlite3_3.7.17 ln -s /usr/local/bin/sqlite3 /usr/bin/sqlite3
4.更改库路径
很多小伙伴去上面测试了一下。他们发现在执行python manage.py runserver 8080时还是报同样的错误,原因是django读取了旧库,可以自行验证
(python36) [root@george servermonitor]# python Python 3.6.8 (default, Nov 16 2020, 16:55:22) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import sqlite3 > >>> sqlite3.sqlite_version > '3.7.17' >>> .exit
修改库变量
export LD_LIBRARY_PATH="/usr/local/lib/"
永久修改
修改~/.bashrc或~/.bash_profile或系统级别的/etc/profile 1. 在其中添加例如
export LD_LIBRARY_PATH="/usr/local/lib/"
2. source .bashrc (Source命令也称为“点命令”,也就是一个点符号(.)。source命令通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录)
测试
python manage.py runserver 8080
3.安装 uwsgi
Django的主要部署平台是WSGI,它也是Python的标准web服务器和应用。
uWSGI是实现了WSGI协议的WSGI服务器。
uWSGI 是一个快速的、自我驱动的、对开发者和系统管理员友好的应用容器服务器,完全由 C 编写。
uWSGI的官网地址:https://uwsgi-docs.readthedocs.io/en/latest/index.html
根据血和泪的经验教训,请确保安装的是最新版本的uwsgi,否则可能出现各种坑。
所以不建议使用:pip3 install uwsgi
(不一定是最新版)
不建议使用:pip install https://projects.unbit.it/downloads/uwsgi-lts.tar.gz
(也不一定是最新版)
而是建议到https://uwsgi-docs.readthedocs.io/en/latest/Download.html页面,下载Stable/LTS
版本的源文件。
为什么要最新版?因为现在的官方教程和相关技术文章全是以新版编写的,很多参数名,用法有较大改变。用旧版,你可能连跑都跑不起来。
这里使用进行安装
pip3 install uwsgi
安装完毕后,尝试运行一下uwsgi:
root@kube mylab]# uwsgi *** Starting uWSGI 2.0.19.1 (64bit) on [Fri Jan 15 15:14:13 2021] *** compiled with version: 4.8.5 20150623 (Red Hat 4.8.5-39) on 13 January 2021 07:53:36 os: Linux-3.10.0-1062.9.1.el7.x86_64 #1 SMP Fri Dec 6 15:49:49 UTC 2019 nodename: kube.master machine: x86_64 ....
uwsgi --python -version
测试 uwsgi
在项目目录执行
uwsgi --http 192.168.2.2:8000 --file network/wsgi.py --static-map=/static=/opt/project_network/network/network/static
配置uwsgi
在项目目录下 mkdir script 文件
[root@localhost script]# pwd
/opt/project_network/script
[root@localhost script]# cat uwsgi.ini [uwsgi] #项目根目录 chdir = /opt/project_network/network/ # 指定wsgi模块下的application对象,就是调用 mylab.wsgi 文件中的 application 对象 module = network.wsgi:application #wsgi-file = /opt/project_network/network/network/wsgi.py #//对本机8000端口提供服务 #http-socket = 192.168.2.2:8888 socket = /opt/project_network/script/network.sock #//主进程 master = true # 以上4个是核心配置项 #vhost = true //多站模式 #no-site = true //多站模式时不设置入口模块和文件 #workers = 2 //子进程数 #reload-mercy = 10 #vacuum = true //退出、重启时清理文件 max-requests = 1000 limit-as = 512 buffer-size = 30000 pidfile = /opt/project_network/script/uwsgi9090.pid # //pid文件,用于下脚本启动、停止该进程 #日志文件 daemonize = /opt/project_network/script/uwsgi.log #不记录正常信息,只记录错误信息 #disable-logging = true [root@localhost script]#
相关命令:
[root@localhost script]# uwsgi --ini uwsgi.ini #启动 [uWSGI] getting INI configuration from uwsgi.ini [root@localhost script]# uwsgi --stop uwsgi9090.pid #停止 [root@localhost script]#
相关问题: 出现了 getway 502 报错 ,最终原因是 一定要确认前面的 python3 sqlite3 成功替换,nginx 调用出问题,可以根据uwsgi.log 排查
4.安装 nginx
下载 nginx repo 文件
[root@localhost script]# cat /etc/yum.repos.d/nginx.repo [nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true [nginx-mainline] name=nginx mainline repo baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/ gpgcheck=1 enabled=0 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true [root@localhost script]#
yum update yum install nginx -y
[root@localhost script]# cat /etc/nginx/conf.d/network.conf server { #如果要使用 https 请参考nginx 添加证书的博客 listen 80; #区别于 uwsgi 端口,不然会造成端口冲突 #listen [::]:8090; #监听 ipv6 端口 error_log /opt/project_network/script/nginx_error.log; access_log /opt/project_network/script/nginx_access.log main; charset utf-8; gzip on; server_name 192.168.2.2; #当访问此名称时 ,nginx 会进行server_name 进行匹配 error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location / { #匹配 / 目录 include uwsgi_params; #导入 uwsgi_params 文件 uwsgi_pass unix:/opt/project_network/script/network.sock; #使用 uwsgi_pass 参数将数据传递给 uwagi 应用服务器,使用 uwsgi.ini 中定义的 sock 文件 } location /static/ { #匹配static 静态文件的 ,进行别名处理 alias /opt/project_network/network/network/static_all/; index index.html index.htm; } } [root@localhost script]#
查看 sock
[root@localhost script]# netstat -ap --unix |grep uwsgi #netstat -ap --unix #显示处于监控状态的unix socket,-a显示所有state状态的链接,因为默认不显示处于listening状态的。-p显示与socket有关的pid/programe name unix 2 [ ACC ] STREAM LISTENING 18516 1158/uwsgi /opt/project_network/script/network.sock unix 3 [ ] STREAM CONNECTED 18532 1158/uwsgi unix 3 [ ] STREAM CONNECTED 18529 1158/uwsgi unix 3 [ ] STREAM CONNECTED 18530 1158/uwsgi unix 3 [ ] STREAM CONNECTED 18531 1158/uwsgi [root@localhost script]#
重要生产操作:
# Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ #静态资源的访问 # STATIC_URL 引用位于 STATIC_ROOT 中的静态文件时要使用的 URL。 STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR,'static_all') #这个配置定义了静态文件应用在启用 FileSystemFinder 查找器时将穿越的额外位置,例如,如果你使用 collectstatic 或 findstatic 管理命令或使用静态文件服务视图。 STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static') ]
[root@localhost network]# python manage.py collectstatic #会将 admin 文件 和 STATICFILES_DIRS 定义的目录合并为 static_all 中 , 因此 nginx 中的
alias /opt/project_network/network/network/static_all/; 这里不是 static 结尾
collectstatic
¶
django-admin collectstatic
¶
将静止文件收集到STATIC_ROOT
中。
项目目录结构
[root@localhost opt]# tree -L 3 . └── project_network ├── network │ ├── db.sqlite3 │ ├── __init__.py │ ├── logs │ ├── manage.py │ ├── network │ ├── __pycache__ │ └── requirement.txt └── script ├── network.sock ├── nginx_access.log ├── nginx_error.log ├── uwsgi9090.pid ├── uwsgi.ini └── uwsgi.log 6 directories, 10 files [root@localhost opt]#
uwsgi 标准配置 https://www.techatbloomberg.com/blog/configuring-uwsgi-production-deployment/
[uwsgi] strict = true master = true enable-threads = true vacuum = true ; Delete sockets during shutdown single-interpreter = true die-on-term = true ; Shutdown when receiving SIGTERM (default is respawn) need-app = true disable-logging = true ; Disable built-in logging log-4xx = true ; but log 4xx's anyway log-5xx = true ; and 5xx's harakiri = 60 ; forcefully kill workers after 60 seconds py-callos-afterfork = true ; allow workers to trap signals max-requests = 1000 ; Restart workers after this many requests max-worker-lifetime = 3600 ; Restart workers after this many seconds reload-on-rss = 2048 ; Restart workers after this much resident memory worker-reload-mercy = 60 ; How long to wait before forcefully killing workers cheaper-algo = busyness processes = 128 ; Maximum number of workers allowed cheaper = 8 ; Minimum number of workers allowed cheaper-initial = 16 ; Workers created at startup cheaper-overload = 1 ; Length of a cycle in seconds cheaper-step = 16 ; How many workers to spawn at a time cheaper-busyness-multiplier = 30 ; How many cycles to wait before killing workers cheaper-busyness-min = 20 ; Below this threshold, kill workers (if stable for multiplier cycles) cheaper-busyness-max = 70 ; Above this threshold, spawn new workers cheaper-busyness-backlog-alert = 16 ; Spawn emergency workers if more than this many requests are waiting in the queue cheaper-busyness-backlog-step = 2 ; How many emergency workers to create if there are too many requests in the queue
下面告警需要关闭 selinux
getenforce
setenforce 0 关闭 setenforce 1 开启
2021/09/26 21:30:57 [crit] 1463#1463: *19 connect() to unix:/opt/project_network/script/network.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.2.254, server: 192.168.2.2, request: "GET / HTTP/1.1", upstream: "uwsgi://unix:/opt/project_network/script/network.sock:", host: "192.168.2.2" 2021/09/26 21:30:57 [crit] 1463#1463: *19 connect() to unix:/opt/project_network/script/network.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.2.254, server: 192.168.2.2, request: "GET / HTTP/1.1", upstream: "uwsgi://unix:/opt/project_network/script/network.sock:", host: "192.168.2.2"
附件:
inux使用netstat命令监控unix domain socket(unix socket,.sock文件)状态
UNIX Domain Socket IPC
socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。
UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。
使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。
UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。