基于CentOS7下部署 Python3+Nginx+uWSGI+Django+DRF+MongoDB

194 阅读4分钟

基于CentOS7下部署 Python3+Nginx+uWSGI+Django+Django REST Framework+MongoDB

分为以下几步:

  1. 服务器安装Nginx,本地浏览器能正常访问即可
  2. 服务器安装MongoDB,本地Navicate等数据库管理工具能远程连接到远程MongoDB
  3. 服务器搭建Python3环境
  4. 服务器搭建Django项目,接入DRF和MongoDB(也可本地编辑器搭建,然后通过ftp软件上传至服务器),并且本地浏览器能正常访问到,MongoDB正常持久化
  5. 接入uwsgi与第1步的Nginx,能本地通过Nginx正常访问到Django项目

安装Nginx

参考之前写过的文章:Nginx保姆式安装与入门使用 - 掘金 (juejin.cn)

安装MongoDB(version:4.2稳定版)

中文文档:MongoDB中文手册|官方文档中文版 - MongoDB-CN-Manual (mongoing.com)

安装

创建yum文件: vim /etc/yum.repos.d/mongodb-org-4.2.repo 写入下面内容

[mongodb-org-4.2]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.2/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc

执行:yum install -y mongodb-org

开启远程连接
将配置文件bindIp: 127.0.0.1 修改为 bindIp: 0.0.0.0vim /etc/mongod.conf

启动mongodb服务:service mongod start
1 设置开机自启动:systemctl enable mongod
查看服务是否启动:systemctl status mongod
其他操作:
停止mongodb服务:service mongod stop
重启mongodb服务:service mongod restart
查看mongodb服务日志:cat /var/log/mongodb/mongod.log

本地navicate远程连接mongodb服务器 34.png

安全设置(需要可通过此设置密码验证)

创建root用户

  1. 输入mongo 进入mongodb环境
  2. 切换到admin :use admin
  3. 创建root用户:db.createUser({user: 'root', pwd: 'thy123', roles: ['root']})
  4. 完成后退出mongo:quit()
  5. 再次进入mongo环境, 选择admin库,查看是否可以登录:db.auth('root','xxxxxxxxxxx') 返回1就是登录成功。

给具体库添加用户,并且授予权限

(mongodb的逻辑是:库可以添加用户,并给予这个用户特定的权限,这样就可以以这个用户的身份进行权限内的使用)

example:给admin库添加一个用户root,并赋予所有权限

use admin
db.createUser({ user: 'admin', pwd: 'xxxxxxxxx', roles: [{ role: 'root', db: 'admin' }] })

这里的role: 'root' 意思是给这个用户的角色是root角色,对应这个admin库的所有权限。和我们上面说的root用户没任何关系

这里的权限包括:

Read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。
root:只在admin数据库中可用。超级账号,超级权限

注意:这时,以上的安全设置到目前为止还没有生效,需要到配置文件中开启安全认证。

开启安全认证

vi /etc/mongod.conf 找到“#security:”项,开启并在其下方添加:

security:
 authorization: enabled

重启mongodb(没重启就不生效):service mongod restart
要建立其他的库,也相应地给他加上用户和权限

安装Python3环境(3.8.0)

一般习惯将软件安装包放在/usr/local/src下面,软件安装在/usr/local下

踩坑:【3.6是PYTHON的谎言】千万别用python3.6.0和3.6.1_Reza.的博客-CSDN博客
解决:CentOS7 下升级Python版本 - Python - E度笔记 (edbiji.com)
在执行解决方法6.1之前,如果已经安装了python3.6并且没有覆盖掉python2,则先删除python3和pip3的软连接,然后根据解决方法里面的步骤执行。(注意,如果3.6安装了uwsgi并且创建了软连接,同样需要删除,不然依然用的pip3.6下载的uwsgi)

yum install zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel xz xz-devel libffi-devel
rm -rf /usr/bin/python3
rm -rf /usr/bin/pip3
rm -rf /usr/bin/uwsgi 根据安装的3.8 下载uwsgi然后重新创建软连接

并且之前下载的包也得重新下载pip3 install -r requirements.txt,因为现在是3.8,之前下的包在3.6里面

Shell脚本安装

root用户下 新建install_python3.sh文件:vim install_python3.sh,将下面的内容复制到文件中

#!/bin/bash

# 安装依赖包
yum -y groupinstall "Development tools"
yum -y install zlib-devel bzip2 bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz xz-devel libffi-devel
# 将软件包下载到/usr/local/src下
cd /usr/local/src
# 淘宝镜像下载python3.8.0版本
wget http://npm.taobao.org/mirrors/python/3.8.0/Python-3.8.0.tgz
# 解压
tar -xzf Python-3.8.0.tgz
# 进入解压包
cd Python-3.8.0
# 生成makefile文件,放在/usr/local/python3目录下
mkdir /usr/local/python3
./configure --prefix=/usr/local/python3
# 编译
make
# 安装
make install
# 创建软连接
ln -s /usr/local/python3/bin/python3 /usr/bin/python3
ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3

给脚本授予权限:chmod 755 install_python3.sh
执行脚本安装:./install_python3.sh
通过python3 -V命令查看是否安装成功

正常安装

centos自带的有python2环境,一般下载其他版本会创建软连接而不会覆盖自带的python2环境,因为可能导致依赖python2的部分错误从而引发一些问题。

默认root用户,如果不是所有命令前加sudo
0.安装依赖包
yum -y groupinstall "Development tools"
yum -y install zlib-devel bzip2 bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz xz-devel libffi-devel
1.将软件包下载到/usr/local/src下,安装到/usr/local下。进入对应目录
cd /usr/local/src
2.官网速度可能比较慢,通过淘宝镜像下载python对应版本压缩包
官方下载:wget https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tar.xz
淘宝镜像下载(推荐):wget http://npm.taobao.org/mirrors/python/3.8.0/Python-3.8.0.tgz
3.解压淘宝镜像下载的文件 (解压后会出现一个 Python-3.8.0 文件夹):
tar -xzf Python-3.8.0.tgz
4.进入解压包:
cd Python-3.8.0
5.生成makefile文件,放在/usr/local/python3目录下:
mkdir /usr/local/python3
./configure --prefix=/usr/local/python3
6.编译:
make
7.安装:
make install
8.创建新版本python的软链接
(1) 利用命令 python3 调用新版本python,与自带的python不冲突
ln -s /usr/local/python3/bin/python3 /usr/bin/python3
(2) 利用命令 pip3 调用新版本pip,与自带的pip不冲突
ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3
此时系统中存在两个python版本:
命令 python 对应的仍是默认2.7版本, 命令 python3 则对应新安装的3.8版本
可以通过 python3 -V, pip3 -V查看下载的python和pip对应版本

服务器上部署Django+DRF

web项目代码习惯放在/home/web下面,将django项目放在/home/web/django目录下

安装Django

注意:Django4.0版本要求python版本最低为3.8
不过服务器上pip3 install Django的时候好像默认下载的是3.2版本
官网详情:FAQ:安装 | Django 文档 | Django (djangoproject.com)

  1. 创建虚拟环境(可跳过,直接安装在全局)
    创建虚拟环境( /build是你生成的虚拟环境所在目录)
    python3 -m venv /build/.virtualenvs/djangodev
    进入该目录
    cd /build
    进入该虚拟环境
    source /build/.virtualenvs/djangodev/bin/activate

  2. 通过pip下载安装Django
    pip3 install Django

  3. 创建一个Django项目
    创建/home/web/django目录:mkdir -p /home/web/django
    进入到创建的目录:cd /home/web/django
    初始化一个叫djangoProject的Django项目:django-admin startproject djangoProject \

    注意:如果报错 django-admin:command not found,解决方法有两个:
    (1) 创建软链接(推荐):先通过find命令找到django-admin执行位置find / -name django-admin,根据找到的位置创建软链接:ln -s 找到的执行位置 /usr/bin/django-admin
    如果按照我之前的步骤,应该执行的是ln -s /usr/local/python3/bin/django-admin /usr/bin/django-admin
    (2) 用django-admin的绝对路径执行命令

    在当前目录下执行django-admin startproject djangoProject后,生成的目录结构如下:

      djangoProject 
        ├── manage.py (启动整个django项目的入口)
        └── djangoProject (存放项目相关的文件)
            ├── __init__.py 
            ├── settings.py (存放整个项目的配置信息)
            ├── urls.py (存放整个项目的url)
            ├── asgi.py ()
            └── wsgi.py (用uwsgi时会用到)
    
  4. 运行demo
    python3 manage.py runserver命令默认是以127.0.0.1:8000运行
    可以通过下面两种方式指明运行ip与port
    python3 manage.py runserver 8080 (指明8080端口运行)
    python3 manage.py runserver 0:8080 (0是0.0.0.0的缩写,可被本地浏览器访问)
    执行python3 manage.py runserver 0:8080后,通过本地浏览器输入服务器IP:8080访问后展示页面如下 1653130564(1).png

    可能遇到的错误:
    (1) django.core.exceptions.ImproperlyConfigured: SQLite 3.9.0 or later is required (found 3.7.17) 这是由于初始化的django项目默认用的sqlite数据库,报错是版本过低。
    解决办法:
    [1]更新sqlite版本: blog.csdn.net/weixin_5046…
    [2]修改settings文件中DATABASES.default.ENGINE(推荐)( 注意:必须要设置default,即便ENGINE设为None):
    方法一:DATABASES.default.ENGINE设置为None(推荐) 6DP2DU$@)M24)NEAWTPWT{7.png 方法二:修改settings文件中DATABASES.default.ENGINE为其他数据库

     假设修改setting文件为'ENGINE': 'django.db.backends.mysql',并且配置了数据库相关信息
     则pip3 install pymysql,然后在djangoProject/djangoProject/__init__.py中加入
         import pymysql
         pymysql.install_as_MySQLdb()
     再执行python manage.py migrate
     然后执行python manage.py runserver可正常运行
    

    (2) Invalid HTTP_HOST header: 'xxx.xxx.xxx.xxx:8000'. You may need to add 'xxx.xxx.xxx.xxx' to ALLOWED_HOSTS. 解决办法:据查阅,这是由于django防止HTTP主机头部攻击的措施导致,修改settings.py文件,将ALLOWED_HOSTS = []改为ALLOWED_HOSTS = ['*'] 即可(亦或者添加相关ip和127.0.0.1)。再次运行即可成功访问。

Django接入DRF(django rest framwork)

官方文档

  1. 安装:pip3 install djangorestframework
  2. 在项目settings.py文件的 INSTALLED_APPS 中添加'rest_framework'
    INSTALLED_APPS = [
        ...
        'rest_framework',
    ]
    
  3. 如果打算使用可浏览的API,还需要添加REST框架的登录和注销视图。将以下内容添加到djangoProject/djangoProject/urls.py
    from django.urls import include
    from rest_framework import routers
    
    router = routers.DefaultRouter()
    
    urlpatterns = [
        ...
        path('api-auth/', include('rest_framework.urls')) #URL 路径可以是想要的任何路径
    ]
    

启动django项目:python3 manage.py runserver 0:8000
本地浏览器正常访问页面 1

接入MongoDB

通过pymongo操作MongoDB\

  1. 下载pymongo:pip3 install pymongo

  2. 在djangoProject/settings.py中的DATABSES中加入mongodb相关配置 sdcvd.png

  3. 然后在djangoProject/__init__.py中初始化mongodb连接

    import pymongo
    from settings import DATABASES
    
    # 开启了密码验证用uri连接
    # uri = "mongodb://%s:%s@%s:%d/%s?authMechanism=SCRAM-SHA-1" % (USERNAME,PASSWORD,HOST,PORT,DATABASE)
    # my_mongodb_client = pymongo.MongoClient(DATABASES['mongo']['URI'])
    
    # 无验证连接
    my_mongodb_client = pymongo.MongoClient(
        host=DATABASES['mongo']['HOST'],
        port=DATABASES['mongo']['PORT'],
    )#连接django服务器
    
    # 选择对应数据库,必须提前在mongodb创建该数据库,集合可以不用提前创建
    mongodb_db = my_mongodb_client[DATABASES['mongo']['DATABASE']]
    
    post_data = {
        'name': 'thy1',
        'item': 'book1',
        'qty': 18,
    }
    result = mongodb_db.get_collection('user').insert_one(post_data)
    
    print(mongodb_db.list_collection_names())
    
  4. 测试:
    单独运行__init__.py文件,应该打印结果['user']
    }}JC0$ZR(5ORQF5~G`7C4J9.png\

  5. 如果以项目运行,需要将djangoProject/__init__.py中的from settings import DATABASES改为from .settings import DATABASES并且注释掉打印相关信息

    import pymongo
    from .settings import DATABASES
    
    # 开启了密码验证用uri连接
    # uri = "mongodb://%s:%s@%s:%d/%s?authMechanism=SCRAM-SHA-1" % (USERNAME,PASSWORD,HOST,PORT,DATABASE)
    # my_mongodb_client = pymongo.MongoClient(DATABASES['mongo']['URI'])
    
    # 无验证连接
    my_mongodb_client = pymongo.MongoClient(
        host=DATABASES['mongo']['HOST'],
        port=DATABASES['mongo']['PORT'],
    )#连接django服务器
    
    # 选择对应数据库,必须提前在mongodb创建该数据库,集合可以不用提前创建
    mongodb_db = my_mongodb_client[DATABASES['mongo']['DATABASE']]
    
    # 在其他文件中引用mongodb_db即可
    

接入uwsgi+Nginx

接入uwsgi

注意: 我在windows10环境下安装有问题,建议部署在Linux环境时再使用uwsgi

Django官网托管uwsgi地址:如何用 uWSGI 托管 Django | Django 文档 | Django (djangoproject.com)
uWSGI官网配置选项地址:uWSGI选项 — uWSGI 2.0 文档 (uwsgi-docs-zh.readthedocs.io)

  1. vim编辑uwgsi.ini文件(执行vim uwsgi.ini命令编辑uwsgi.ini文件,将下面内容复制到文件中后,按ESC进入命令模式然后按ZZ保存退出)

    [uwsgi]
    # 项目根目录的绝对路径,在加载前切换到当前目录,指定运行目录
    chdir=/home/web/django/djangoProject
    # 加载一个WSGI模块,这里加载djangoProject/wsgi.py找个模块
    module=djangoProject.wsgi
    
    # http访问
    http-socket=0.0.0.0:8000
    
    # 设置socket的监听队列大小(默认100)
    listen=128
    # 设置生成2个worker进程
    workers=2
    # 设置每个work进程的线程数
    threads=4
    # 启动主进程,来管理其他进程,其他的uwsgi进程都是这个master进程的子进程,kill此进程,相当于重启所有uwsgi进程
    master=true
    # 允许用内嵌的语言启动线程(允许在app程序中产生一个子线程) 多线程需要,例如apscheduler
    enable-threads=true
    
    # 使进程在后台运行,并将日志打到指定文件    
    daemonize=%(chdir)/uwsgi.log
    # 指定pid文件
    pidfile = %(chdir)/uwsgi.pid
    

    查漏补缺:uwgsi中http、http-socket和socket区别

    • http: 自己会产生一个http进程(可以认为与nginx同一层)负责路由http请求给worker, http进程和worker之间使用的是uwsgi协议

    • http-socket: 不会产生http进程, 一般用于在前端webserver不支持uwsgi而仅支持http时使用, 他产生的worker使用的是http协议

    • 如果前端webserver支持uwsgi, 则直接使用socket即可(tcp or unix)

      因此,如果想直接将uwsgi用作服务器,例如像nginx那样直接暴露在公网那么就使用http; 如果有单独的服务器(例如nginx),由服务器将请求转发给uwsgi处理,并且使用http协议,那么此时使用http-socket。

      http和http-socket对应的nginx配置:
      server{
          listen 80;
          location / {
              proxy_pass http://127.0.0.1:5000/ // 必须用http://
          }
      }
      
    • socket:按照uwsgi文档给出的解释是bind to the specified UNIX/TCP socket using default protocol.也就是说指定UNIX/TCP socket作为默认的协议。

      UNIX/TCP socket其实是两类socket。UNIX socket是进程间的通信(Inter Process Communication),但只在同一台机器上;TCP/IP sockets允许进程通过网络通信。

      在uwsgi中如果配置如下则是使用UNIX socket:
      [uwsgi]
      socket = /tmp/uwsgi.sock
      
      如果配置如下则是使用TCP/IP socket:
      [uwsgi]
      socket = 127.0.0.1:8000 
      
      在nginx也是对应的配置(引):
      uWSGI socket(unix socket):
          location / {
              uwsgi_pass unix:///tmp/uwsgi.sock;
              include uwsgi_params;
          }
      
      TCP sockets:
          location / {
              uwsgi_pass 127.0.0.1:8000;
              include uwsgi_params;
          }
      
      
      但是官方文档将两种形式写在一起了,没懂:
      [uwsgi]
      socket = /tmp/uwsgi.sock
      socket = 127.0.0.1:8000
      workers = 3
      master = true
      注:uwsgi-socket是socket的别名引
      
  2. 安装uwsgi:pip3 install uwsgi

  3. 启动uwsgi:uwsgi uwsgi.ini
    如果报错uwsgi: command not found...
    解决方法:
    (1)通过find命令找到uwsgi执行位置 find / -name uwsgi
    (2)创建软连接:ln -s 显示的路径 /usr/bin/uwsgi
    (3)重新执行uwsgi uwsgi.ini正常启动 或者 uwsgi -version正常显示版本信息即可

ENMDXSNEG8M$R_56IWS0R)1.png

但是当用本地浏览器访问时会发现这样的页面,通过F12查看可知是静态文件请求不到(至少现在uwsgi+django是已经接通了)

1654229287(1).png

下面通过Nginx解决这个问题。

接入Nginx

  1. Django静态文件收集
    (1) 编辑djangProject/settings.py文件,在BASE_DIR = Path(\_\_file\_\_).resolve().parent.parent下面加入STATIC_ROOT = os.path.join(BASE_DIR, "static/"),记得导入os包:import os 效果如下:

    1654230383(1).jpg
    (2) 然后执行python3 manage.py collectstatic,在/home/web/django/djangoProject下会多出一个static文件,里面包含了当前项目用到的所有静态文件

    1654230580(1).png

  2. 配置Nginx

    (1) 修改nginx.conf配置文件vim /usr/local/nginx/conf/nginx.conf
    (2) 在http中添加include /usr/local/nginx/conf/conf.d/*.conf;

    }UEIPACGZCCGDOTCU4CO7.png

    (3) 为当前django项目创建对应nginx配置文件
    mkdir /usr/local/nginx/conf/conf.d
    vim /usr/local/nginx/conf/conf.d/djangoProject.conf,在文件中添加以下内容

     upstream django {
         # 本地8000端口
         server 127.0.0.1:8000; # for a web port socket (we'll use this first)
     }
    
     server {
         # the port your site will be served on
         listen      8001; #以为django项目是8000端口,所以监听8001端口
         # the domain name it will serve for
         server_name _; # substitute your machine's IP address or FQDN
         charset     utf-8;
    
         # max upload size
         client_max_body_size 75M;   # adjust to taste
    
         # Django media
         #location /media  { 
         #    alias /path/to/your/mysite/media;  # your Django project's media files - amend as required
         #}
         
         # 配置静态文件路径
         location /static {
             alias /home/web/django/djangoProject/static; # your Django project's static files - amend as required
         }
    
         # Finally, send all non-media requests to the Django server.
         location / {
             proxy_pass http://django; #如果就一个,可以直接写proxy_pass http://IP:PORT;
             #uwsgi_pass  django;
             #include     /usr/local/nginx/conf/uwsgi_params; # the uwsgi_params file you installed
         }
     }
    

    (4) 执行 nginx -s reload 重新加载nginx配置文件
    (5) 通过本地浏览器访问 服务器IP:8001 即可正常显示(因为我使用的是nginx代理静态文件,所以8000端口访问的还是之前访问不到静态文件的样子)
    (建议uwsgi不对公网开放,通过nginx代理打到本地8000端口,只需要修改uwgsi.ini文件 将0.0.0.0:8000改为127.0.0.1:8000)

    3.png