那年那日那朵花

".......(o´ω`o)......"

django应用部署

2016-05-16 14:17 linux python django

django应用的部署一般我从前到后采用nginx+ gunicorn + django +mysql的方式。这里总结了一下部署该博客网站的过程。就是在回忆过程中可能会有些遗漏和错误。。。。。。。

主要分为

  • 数据库部署
  • virtualenv环境搭建
  • 代码部署
  • nginx和gunicorn配置

1. 数据库部署

这里使用社区版mysql作为后台数据库,还是蛮轻量的,比较适合中小型网站,mysql很流行也很稳定,而且开源免费、网络上文档非常多。

操作系统使用的是centos7,而django我用的是1.8版本python最低需要2.7版本。centos7自带的就是python2.7,相较centos6内置的python2.6,免去了升级的功夫(不过我用virtualenv搭建python环境,至于操作系统是2.7还是2.6没啥关系),还有由于centos7内置的repo源里没有加入mysql,所以需要自己另外添加repo源。
可以这样做:

wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
rpm -ivh mysql-community-release-el7-5.noarch.rpm 
yum install mysql-server
#安装python的MySQL库
yum install MySQL-python
#启动mysql 貌似centos7改变了服务启动方式么 = = 
service mysqld start
Redirecting to /bin/systemctl start  mysqld.service
#默认数据库root密码为空,登录
mysql -uroot
#建库
create database dbname character set utf8 collate utf8_bin;
grant all privileges on dbname.* to usrname@localhost identified by 'xxxxx';
FLUSH PRIVILEGES;

OK,数据库建好了,用mysql -uusername 登录下,能登录就说明成功了。到时候建表啊或改表等操作,可以用django提供的migrate来做,十分方便。

虽然是一个小站,但是也应该养成定时备份的好习惯。整个库十分轻量,不写文章N天也不见得会有更新。可以每天定时把整个库或者自己用的几张表备份下,我这边就把除了django自建的表外的都备份了一下。脚本如下:

#!/bin/bash
#backup mysql tables
#Don't need tables: auth* django* 
MySQL_USER=xxxxx
MySQL_PASSWORD=xxxxx
MySQL_HOST=localhost 
MySQL_PORT=3306
MySQL_DUMP_PATH=/mysql_backup  
MySQL_DATABASE_NAME=blog 
DATE=$(date '+%Y-%m-%d')
a=0
[ -d ${MySQL_DUMP_PATH} ] || mkdir ${MySQL_DUMP_PATH}  
cd ${MySQL_DUMP_PATH}  
[ -d logs ] || mkdir logs  
[ -d ${DATE} ] || mkdir ${DATE}  
cd ${DATE}  
TABLE_NAME_ALL=$(mysql -u${MySQL_USER} -p${MySQL_PASSWORD} -P${MySQL_PORT} -h${MySQL_HOST} ${MySQL_DATABASE_NAME} -e "show tables"|egrep -v "(Tables_in*|auth*|django*)" )  
for TABLE_NAME in ${TABLE_NAME_ALL}  
do  
mysqldump -u${MySQL_USER} -p${MySQL_PASSWORD} -P${MySQL_PORT} -h${MySQL_HOST} ${MySQL_DATABASE_NAME} ${TABLE_NAME} >${TABLE_NAME}.sql
echo "${TABLE_NAME} dump ok"  
let a=$a+1
sleep 1  
done  
[ "$?" == 0 ] && echo "${DATE}: Backup tables succeed" >> ${MySQL_DUMP_PATH}/logs/BlogMysqlDump.log  
[ "$?" != 0 ] && echo "${DATE}: Backup tables not succeed" >> ${MySQL_DUMP_PATH}/logs/BlogMysqlDump.log  
echo "total  records:             $a"
exit 0

之后就设一个定时每天跑就是了,时间长了。可以手动或写个脚本把30天前甚至更久前的备份删除。

#backup mysql every day
0 3 * * * /root/tools/mysqlbackup.sh >> /tmp/backupmysql.log 2>&1

2.virtualenv环境搭建

virtualenv可以帮助解决在同一台服务器上共存不同python版本和不同环境的问题。它能提供一个虚拟环境,将不同的版本放在各自的虚拟环境中而互不影响,起到相互隔离的作用。

在安装前,先设计一个目录结构

sites/
└── myblog
    ├── database
    ├── media
    │   └── pic
    ├── source
    │   └── myblog
    ├── static
    │   ├── admin
    │   ├── bootstrap
    │   ├── css
    │   ├── jquery
    │   └── pic
    └── virtualenv
        ├── bin
        ├── include
        ├── lib
        ├── lib64 -> lib
        └── pip-selfcheck.json

在sites目录下面建立站点名称。然后在下层目录结构中分别存放数据库、图片、程序代码、静态文件、和虚拟环境。数据库目录可以不要,因为我使用的是mysql,如果使用sqlite的话就可以把文件存在database目录中了。

安装的话pip install virtualenv 然后cd 到virtualenv目录下,创建虚拟环境, virtualenv . 注意这里有个点。而且这台服务器用的python版本默认是2.7,如果需要指定版本的话需要先安装对应版本的python,然后指定该python环境创建。

virtualenv创建好虚拟环境后应该就会有bin include lib lib64 这几个目录了。那如何进入虚拟环境呢,cd 到 bin目录下 source activate 就可以了。

然后就可以根据自己的需要安装python模块了。 然后安装完了可以pip freeze > requirement.txt 生成虚拟环境所需的包列表,在当前的虚拟环境下安装的python模块是相互间隔离的。

3.代码部署

我的代码是提交到github上面的,部署的话很简单。先cd 到上面提到的source目录 git clone XXXXX,就能把代码下载到本地了,然后需要注意的是配置文件的修改,特别是DATABASES TIME_ZONE STATIC_URL 等等以及多说的相关配置,是与本地开发电脑不同的,需要改成线上环境的配置。像是配置文件的话一般是不需要每次更新的,可以在配置文件所在的目录下创建一个.gitignore文件,在里面添加不需要更新的文件,例如/settings.py 。那么以后的更新就可以用git pull 来进行了。

4.nginx和gunicorn配置

这一块主要的目的是用nginx来伺服静态页面和图片,同时将nginx暴露在公网上更加安全可靠。gunicorn是专业的python WSGI http服务器,因为在生产环境下不应该再使用django自带的开发服务器了。

具体的我之前已经写过了 = = 可以参考过去的博客文章,就当作这篇是一个补充或者拾遗把。


================2016.08.03 分割线=================

今天需要重新部署一套django环境,所以照着原来自己写的文档部署,结果发现——————并没有什么卵用。。。。。挺多细节的地方都忘了。

所以记录以下几点提醒下自己。

首先是nginx,nginx直接到官方网上http://nginx.org/packages/下载对应系统的rpm包。不多说了

然后再/etc/nginx/conf.d下另建一个配置文件,内容如下为例

server {
    listen       8000;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;

    location / {
        #nginx反向代理默认是80端口,如果前面配置的listen是80的话这里只要配proxy_set_header Host $host;如果是其他端口要加$server_port变量,否则http请求头传递端口信息会变成80端口,这样就错了
        proxy_set_header Host $host:$server_port;
        #获取用户ip
        proxy_set_header X-Forwarder-For $remote_addr;
        proxy_pass  http://127.0.0.1:8999;
    }

    location /static {
        alias /root/workorder/static;
    }

    location /media {
        alias /root/workorder/media;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

}

这里贴一下,以后可以用作模板。主要是提醒下自己因为实际的工作环境中django肯定是关闭debug模式的,一旦关闭debug模式,django框架就不再伺服静态文件了。所以nginx还要配置location /static项,如果有必要处理图片的话 要配置location /media 。而且还有一点要补充,如果项目中使用了django框架admin模块里的日期插件等js和css的话,开发中可以直接在页面中引入

 <link rel="stylesheet" type="text/css" href="/static/admin/css/forms.css" />
 <script type="text/javascript">window.__admin_media_prefix__ = "/static/admin/";</script>
 <script type="text/javascript">window.__admin_utc_offset__ = "28800";</script>
 <script type="text/javascript" src="/admin/jsi18n/"></script>
 <script type="text/javascript" src="/static/admin/js/core.js"></script>
 <script type="text/javascript" src="/static/admin/js/jquery.js"></script>
 <script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
 <script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
 <script type="text/javascript" src="/static/admin/js/actions.js"></script>
 <script type="text/javascript" src="/static/admin/js/calendar.js"></script>
 <script type="text/javascript" src="/static/admin/js/admin/DateTimeShortcuts.js"></script>

但是一旦debug模式关闭后,由于改为nginx伺服静态页面,这些就失效了,会报找不到这些js的。需要将django源码中admin模块用的js和css文件放到自己django项目中的static目录中。我就图方便直接将admin模块里存放静态文件的整个admin文件夹放到static目录中了,这样html标签也就不需要修改了。

另外遇到个奇葩问题,就是django的setting.py文件中我配置了STATIC_ROOT项目,照理说,配置完成后使用python manage.py collectstatic 命令就会把对应django项目中的static目录中的文件拷贝到STATIC_ROOT所配置的目录中,但是这次不知道为啥,一执行该命令,等了很久也不输出东西,用top监控一下系统 就会看到该进程将一颗CPU的负载占满了,= = !。 不过没关系,知道了原理,在部署脚本里把文件拷贝过去就可以了。

第三点,由于使用gunicorn作为wsgi server。启动的时候经常是手工配置参数的,这次决定写一个配置文件,这样方便管理。配置文件如下:

bind = "127.0.0.1:8999"
workers = 2
chdir  = "/root/workorder/source/workordersys"
accesslog = "/root/workorder/logs/gunicorn_access.log"
errorlog = "/root/workorder/logs/gunicorn_error.log"
daemon = True

bind表示绑定的ip端口,就是前面nginx转发过来流量的地址
workers表示启动多少个处理请求的进程数,官网文档中有这么配置,将workers开到cpu线程数X2+1,将配置文件作为python source file,在里面引用python模块写成python代码,不过我不推荐这样。不是高并发业务,处理请求的进程数也没必要开那么大。

import multiprocessing

bind = "127.0.0.1:8000"
workers = multiprocessing.cpu_count() * 2 + 1

chdir 表示转换工作目录。 因为启动的时候后面要跟 一个字符串 表示django中的wsgi的application方法,所以要指定工作目录。
accesslog和errorlog分别表示日志和错误日志
daemon 表示开启守护进程

启动的话也不需要 nohup gunicorn XXXXXXX & 这种方式了 ,直接gunicorn -c gunicorn.cfg workordersys.wsgi:application 就可以了。

心情

Cloudhu 个人随笔|built by django|

沪ICP备16019452号-1