Django Web 项目在Windows环境的部署

     阅读:29

记录这个主要是怕自己忘了,也是工作的需要:之前的项目接口是公司前辈用Java语言开发的,对接伊始,自己工作主要负责现场部署实施,所以之前的环境由于是Java 语言开发,自然使用Apache 的 Tomcat 部署,但是随着业务的开展,客户提出很多个性化的需求自己想改接口但苦于当时自己并不掌握 Java 语言的编程开发一直未能实现。随着对业务逻辑的熟悉以及自己对Python语言开发的掌握,慢慢将相关模块化的东西通过使用python语言得以实现:从最开始的一个 Webservices到整个后台管理业务功能模块基于django 的实现,突然发现前辈使用Java 开发的接口功能只是整个后台系统中的一个小模块而已,因此决定将其抽离出来以自己熟悉的语言做自己的接口,维护起来也游刃有余,至少我自己就能确定哪些个性化可以实现,哪些是直接可以拒绝的!这样做,其一是与客户的沟通较为便捷、明确;其二,真的有些东西,自己没针对某个业务码过代码,真的很难理解。至少可以对业务逻辑掌握清楚吧!所以呢这个django web 小项目就诞生了,项目编写完成后希望部署到实际环境使用,那怎样部署呢?django 官网都建议不要使用 runserver 方式来部署项目,那到底以怎样的方式来部署呢?网上参考了很多帖子,方法万千,一天看下来整个脑子晕乎乎,做下整理,做个选择:

Linux环境部署模式:

        网上最流行的:Nginx + uWSGI

参考书籍中介绍的是:Nginx + Gunicorn + Supervisor

Windows 环境部署模式:

        网上流行的:Apache + mod_wsgi

还有就是:IIS + CGI + wfastcgi

为什么会有这么多的搭配呢?

首先理解一点:Django实现了WSGI协议,通过该协议可以使其运行在其他的WSGI容器中。

在以上的搭配中,先看可行性:

uWSGI 就是实现了WSGI协议、uwsgi、http等协议的Web 服务器;而Gunicorn 是一个 UNIX 下的 WSGI HTTP 服务器,因此两者均能承载django项目。

再看限制条件:

uWSGI 对 Windows 支持不良好,需要改好多东西,一顿操作猛如虎才能成功在Windows上安装uWSGI,自己未敢涉足; Gunicorn 就只能运行在Linux环境中,不支持windows平台。因此就出现了上面Linux环境部署的两种组合。

Nginx也是一款Web 服务器,个人理解在这两种组合中主要利用其出色的静态资源处理以及负载均衡方面的能力;

而 Supervisor 是一款进程控制软件,通过它既可以方便的监控和管理进程,也可以更方便的管理 Gunicorn 进程,它可以运行在大多数类UNIX系统,但是不能运行在任何windows系统。

再来看Windows 部署,Apache(Apache HTTP Server)本身就是一款很流行的Web Server,通过其内的 mod_wsgi 扩展模块,实现了Python WSGI标准,可以支持任何兼容Python WSGI标准的Python应用,因此也就能承载django项目喽!而 IIS 作为微软 Windows 的Web 服务器组件,自然能处理HTTP,和 apache 一样需要个辅助——wfastcgi

看了这么多也是时候做选择了:由于客户先前的操作系统是Windows server 2008,因此在Windows 部署的两种模式中,还是采用较为流行的 apache + mod_wsgi,需要一顿操作踩坑的就不尝试了!至于Linux 部署,早些时候自己编写的一个后台管理系统,也是基于django,曾经采用 Nginx + uWSGI + Centos 的模式在华为云上成功部署过,但现在基本又忘了,留待后面重新部署再写文档记录吧!

记录正题!!

环境介绍:

系统:Windows Server 2008 R2 Standard SP1 64位

工具:Apache 2.4 + mod_wsgi

语言:python

框架:Django

数据库:Mysql

部署用到的软件及对应版本如下:

1. Python ------------------->  python-3.7.2-amd64.exe

2. Apache2.4 -------------->  httpd-2.4.46-win64-VS16.zip

3. mod_wsgi ---------------> mod_wsgi-4.9.0-cp37-cp37m-win_amd64.whl

4. Mysql ---------------------> mysql-installer-community-5.7.21.0.msi

5. Django -------------------> 安装完 python 后 执行 pip install 项目包 完成项目环境依赖安装,版本为 3.2.12

 相关软件网络都可检索下载,为了以后方便更新:

Apache下载:https://www.apachehaus.com/cgi-bin/download.plx

mod_wsgi 下载:https://www.lfd.uci.edu/~gohlke/pythonlibs/#mod_wsgi

部署前准备:

1、下载相关软件

2、确定项目在本地运行正常后进行项目打包

这里涉及到项目文件怎样传输到部署服务器上的问题,一种是 Git 方式,本地先 push 到 自己的GitHub ,再由部署服务器从 GitHub 上 pull ;一种是直接通过 Pycharm 的 Deployment 工具上传到部署服务器上;这两种都需要部署服务器能够访问Internet,第一种留待测试,再做记录,第二种之前在华为云上部署后台管理系统使用过,也留待重新部署再做记录。这里由于客户对要部署的服务器做了限制,无法访问Internet,所以前两种都用不了,那就采用第三种——项目打包

项目打包流程:

① 在项目文件上层(注意不是与 manage.py 同级目录)创建 setup.py 文件,里面的 install_requires 参数直接通过 pip freeze > requirements.txt 取得并填入,这样到部署环境中直接 pip install 项目包 就能安装整个项目的依赖

② CLI 进入setup.py路径下,执行: python setup.py sdist 这种方式会在同级目录中创建一个dist文件夹,打包好的项目包文件就在里面,包以 .tar.gz结尾

 若执行:python setup.py bdist_wheel ,可能会报错:

安装 wheel 后再执行:

 执行完成会在setup.py 同级目录下生成两个文件夹,一个dist,里面放着 .wheel 文件,一个build文件夹,里面 lib 目录里存放着从项目里面打包出来的包(一个包(“模块”)包含了一个或多个 Python 代码文件,一个包通过 import foo.bar 或 from foo import bar 的形式导入。而一个目录(例如 polls)要成为一个包,它必须包含一个特定的文件 __init__.py,即便这个文件是空的

3、将项目包和相关软件传输至部署服务器(这里我是以虚拟机来做测试,可以直接将 deploy 文件复制进去)

 完成以上操作,虚拟机创建快照:系统初始化完毕,文件传输成功

开始部署:

1、安装桌面辅助软件:浏览器、notepad++、压缩软件、输入法等

2、安装python,注意添加环境变量

 安装完成验证成功与否:

3、安装 Mysql

① 首先安装 .NET Framework 4.5.2 来运行 mysql installer

 ② 安装mysql 依赖 Microsoft Visual C++2013运行库_023195421,按照系统位数安装对应依赖运行库 :

③ 开始安装MySQL:

这里若选择 Full 完全安装,则需要更多的依赖项,Manual 项要手动安装:

​这里根据业务需要就选择 Server only:​ 后续默认选择,到选择类型的时候下拉选择 Server 类型

​ 设置数据库密码:​后续直接默认直到完成安装,再来验证安装结果:

需要手动添加mysql环境变量:从所有程序中找到刚安装的mysql选项,定位到安装位置中的bin目录,将其下mysql可执行程序的路径添加到环境变量 path中

注意前面添加英文分号间隔(;)

 添加完成环境变量再来查看:

成功登录,查看数据库信息,并执行:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION; 

做授权,其一是为了项目对数据库的访问,其二为了本地能远程登录虚拟机数据库做相关操作。

这里可以做数据库的简单初始化:创建需要的数据库:

create database 数据库名称 character set 'utf8';

也可以通过主机中的navicat来远程连接虚拟机Server 2008的数据库 进行创建,若出现连接不上,需要检查虚拟机防火墙是否关闭?(先确定主机能否ping通虚拟机IP)连接主机IP与虚拟机IP是否一致等

 可见,主机与虚拟机网络不通,查看虚拟机防火墙状态:

防火墙处于打开状态,将其关闭 

 Ok!现在再来连接数据库:

4、安装Apache:

        ① 创建部署目录:C:\djangoWebRoot,将apache包解压缩得到 Apache24并将其移动至部署目录下:

 ② 对 apache 做初始配置,修改conf下的httpd.conf,确保能正常访问欢迎界面,notepad++打开httpd.conf ,修改apache根目录路径:

 修改端口号:

修改监听主机及端口号:

​ 其他暂不用动,保存修改,接着将apache在系统中注册成服务:

CLI 进到apache 的bin目录下执行:httpd.exe -k install -n "apache2.4"

​到计算机服务中查看并启动apache 

 启动成功到浏览器验证:

至此apache 初步安装成功! 

5、安装mod_wsgi

① 设置 pip 安装源:用户主目录下创建 pip 目录,其中创建 pip.ini文件,使用国内清华源:

​ [global]
index-url=https://pypi.tuna.tsinghua.edu.cn/simple

② 检查pip版本,升级至最新版本:

查看:pip show pip 或者 pip -V

升级:python -m pip install --upgrade pip

​ ③ CLI进入mod_wsgi 安装包所在目录下:

pip install mod_wsgi-4.9.0-cp37-cp37m-win_amd64.whl

④ 将mod_wsgi模块引入apache:

查看mod_wsgi 安装配置信息:mod_wsgi-express module-config ,将回显的信息复制到httpd.conf中:

 至此,mod_wsgi安装完毕!

 6、将项目压缩包放入部署路径下并解压缩,解压缩完将项目文件移动至部署目录(c:/djangoWebRoot)下,删除解压缩后的文件夹,这里没使用.wheel压缩包,这种留待后续验证看有啥区别,直接解压缩 sdist 的 PrescriptionPushSystem-0.1.tar并移动:

7、在httpd.conf 中配置项目:

 8、安装项目内环境依赖:pip install 项目压缩包

pip install PrescriptionPushSystem-0.1.tar.gz

 9、重启apache服务,访问站点做初步验证测试:

 

 页面样式未加载,需要设置静态资源访问:由于在我的项目中静态资源都是放在项目根目录下的 static 文件夹下,setting.py 配置如下:

10、django setting.py 以及 httpd.conf中对静态资源的相关设置

 这里记录下django setting.py中的三个与static 有关的三个参数

STATIC_URL:STATIC_URL,自己理解是提供一种对静态资源访问时对地址路径的一种便捷机制,首先用户访问页面,页面加载静态资源,也是通过一个 url 发起HTTP或者HTTPS请求来访问,url里面要是正确的地址路径才能访问到,那么在代码里面也就需要指定正确的路径,如果采用硬编码(将完整的绝对路径写入页面代码中)的方式,最不好的就是维护起来很难!想想一张图片或者一个静态资源位置发生变动,得一处一处的到页面代码中找到引用的地方再一一修改,不得疯了!基于STATIC_URL,django有模板标签的使用:在模板顶部加载该标签:{% load static %} ,这样,页面中静态资源的访问url就可以写成这样:{% static '资源' %},比如要访问的是 /static/css/background/style.css 就可以写成:{% static 'css/background/style.css' %},这对于项目所有静态资源在一个公共的static下用起来很方便。

STATICFILES_DIRS :是用来指定静态资源所在的目录,注意它是个列表,由它告诉django先到STATICFILES_DIRS里面的目录下寻找静态文件,其次再到各个app的static文件夹下面找。在我的项目中所有静态资源都在STATICFILES_DIRS目录下。

STATIC_ROOT:它是用来配置部署之后的静态资源路径。一旦django部署作为生产环境,它的静态文件访问接口就不能从Django框架中走,必须在Django框架前端部署nginx或者其他web服务器来提供静态访问入口,就是STATIC_ROOT指定的目录

总结一下:首先,Django 提供了静态资源访问功能,通过在 INSTALLED_APPS 中增加 'django.contrib.staticfiles' 这个App,这个App 在开发环境中(DEBUG=True)提供静态资源的服务功能,django提供STATIC_URL的模板配置方式,到STATICFILES_DIRS中查找需要的静态资源返回给模板,当到生产环境,STATICFILES_DIRS就”失效“了,这时候STATIC_ROOT就上台唱戏了!Django提供collectionstatic命令(python manage.py collectstatic)来收集所有的静态资源到STATIC_ROOT配置的目录中,提供给Nginx或其他Web 服务器调用

因此现在需要设置STATIC_ROOT,并且设置DEBUG=False:

这里注意一点:懒得拼写采用复制修改特别注意 STATIC_ROOT 是字符串而并非列表,设置错了到时候执行收集命令会报错!

 执行静态收集命令:

 到项目根目录下会看到多了一个collectstatic文件夹

 修改完django中的静态配置,重启apache做个验证看看:

似乎并没有起作用啊!咋回事?再看看apache里面对于静态资源的配置:

所以还是之前的配置,并且之前Directory 都错了,多了一级目录:

把后面的路径修改成 collectstatic并保存:

 重启apache再验证一下:

 哟呵!出来了。在setting.py中 ALLOWED_HOSTS = ['*'] 做了这样的设置,用主机浏览器访问看看:

效果一样,尝试登录

Server 500,关闭了DEBUG,所以统一返回500,需要到日志中查看原因,不看也知道,数据库未初始化的问题 

11、数据库方面的初始化操作

需要做数据库迁移生成session表,数据库初始化有多种方式,反正用自己可行的方式创建需要的数据表就Ok啦!当然对于完全全新的生产环境初始化是必须的!由于我的项目是应用到原有生产环境,相当于做个升级改版,故不需要创建数据表,只需要初始化session表就行。

 OK!至此部署完成。

后续有时间再探索其他方式的部署 再记录差异点,尤其是管理后台通过Nginx + uWSGI部署到云上需要回顾一下!都踩坑记录完再尝试实现自动化部署,留待后续!