uwsgi的python2+3多版本共存

1、首先,机器需要有python2和python3的可执行环境。

确保pip和pip3命令可用。原理就是在哪个环境下安装uwsgi。uwsgi启动的时候,就用的哪个python版本

未分类

2、安装virtualenv环境管理工具

未分类

3、创建python2和python3的虚拟环境

未分类

4、进入python2虚拟环境

未分类

5、进入python3虚拟环境

未分类

常规发布应用的时候。可以编写shell脚本执行相应的命令启动即可,如下

未分类

Ubuntu部署python3-flask-nginx-uwsgi-supervisor完美

安装虚拟环境

$ pip install virtualenv
$ pip install virtualenvwrapper

把虚拟机环境添加环境变量中

这个最好find / -name virtualenvwrapper.sh 看下位置

$ vi .bashrc
if [ -f /usr/local/bin/virtualenvwrapper.sh ]; then
    export WORKON_HOME=$HOME/.virtualenvs
    source /usr/local/bin/virtualenvwrapper.sh
fi

为flask项目创建一个虚拟环境

$ mkvirtualenv --python=python3 flask  #flask这个名字可以按自己需求修改,我项目是需要python3。所以选择 --python=python3,如果需要python2可以不加这个。
$ deactivate  #安装完虚拟环境后,先退出这个虚拟环境。

安装mysql数据库,安装数据这个没什么好提的网上有很多详细教程

$ apt install mysql-server mysql-client
$ apt install libmysqld-dev

安装nginx

$ apt install nginx   #这个安装也比较简单

安装supervisor

需要是python2 暂时不支持python3,这里有时候会遇到坑。pip install –upgrade pip 看看现在pip是什么版本。

$ vi /usr/local/bin/pip #如果发现pip是python3,不要慌用这个命令把第一行的python3修改python2 即可,如果是python2就无视这步
$ pip install supervisor #安装supervisor

安装uwsgi

需要注意flask项目需要的环境 选择python3 还是python2.

这个我的项目是python3,如果是python2创建虚拟环境就用python2。具体可以看上面的为项目创建虚拟环境

$ workon flask  #进入虚拟环境
$ pip install uwsgi  #这个之前装到虚拟环境里面

如果出现Failed building wheel for uwsgi执行下面语句

apt-get install python3-dev

项目文件创建

这个按自己需要创建,也可以按我这个创建

$ mkdir /www  #根目录下创建一个www
$ mkdir /www/wwwroot  #这个项目文件全部放这个理
$ mkdir /www/log #日志文件

uwsgi配置

uwsgi配置好后,可以测试下

uwsgi配置路径:/www/wwwroot/uwsgi.ini

$ cd /www/wwwroot #可以放到项目,按自己需求都可以
$ vi uwsgi.ini   #创建一个uwsgi配置文件

[uwsgi]
# 当前这个项目的路径
chdir           = /www/wwwroot
# 模块
module          = manage   #启动文件名 个人理解
# python的虚拟环境
home            = /root/.virtualenvs/python3
# 是否启用mater模式
master          = true
# 进程数
processes       = 2
# socket文件地址
socket          = /www/wwwroot/uwsgi.sock
# wsgi文件
wsgi-file       = /www/wwwroot/manage.py  #启动文件
# wsgi文件中的app变量
callable        = app
# socket文件的权限
chmod-socket    = 666

配置好后可以运行起来测试是否成功

$ workon python3 #进入虚拟环境
$ uwsgi --uid www --gid www --ini /www/wwwroot/uwsgi.ini #这个可以指定用户和用户组权限,也可以不指定。测试没能正常打开项目就往下面步骤继续配置

nginx配置

$ cd /etc/nginx/sites-enabled/   #切换到nginx默认配置目录
$ mv default default.bak #修改配置前先备份下配置
$ vi default
server {
        listen 80;
        server_name www.xxoo.com;
        charset utf-8;
        client_max_body_size 75M;
        access_log /www/log/xxoo.access.log;
        error_log /www/log/xxoo.error.log;

        location / {
                include uwsgi_params;
                uwsgi_pass unix:/www/wwwroot/uwsgi.sock; #这个.sock文件一定要和uwsgi配置中一样
        }
}

修改nginx配置/etc/nginx/nginx.conf ,第一行user www www ; Nginx用户及组:用户 组 按自己需求配置。详细配置参数网上自己找

supervisor配置

supervisor配置路径:/www/wwwroot/supervisor.conf

$ vi supervisor.conf
[program:python]  #这个python可以按自己需求写
# supervisor执行的命令
command=/root/.virtualenvs/py3-zqcms/bin/uwsgi --uid www --gid www --ini /www/wwwroot/uwsgi.ini
# 项目的目录
directory = /www/wwwroot
# 开始的时候等待多少秒
startsecs= 5   #按自己需求写
# 停止的时候等待多少秒
stopwaitsecs= 5 #按自己需求写
# 自动开始
autostart=true
# 程序挂了后自动重启
autorestart=true
# 输出的log文件
stdout_logfile=/www/log/supervisord.log
# 输出的错误文件
stderr_logfile=/www/log/supervisorderr.log

[supervisord]
# log的级别
loglevel=info

配置好后就运行

$ supervisord -c /www/wwwroot/supervisor.conf  #执行的时候注意是在python2环境

如何终止多余 Supervisor 进程?

$ ps -ef | grep supervisor  #查看
$ kill 4012 #结束进程

注意:uwsgi nginx supervisor我只是简单配置了下,各位可以按需求配置。详细配置参数网上有很多资料。哪里写错,可以留言告诉我。

nginx+uwsgi完美配置文件,解决“upstream prematurely closed connection”报错

这段时间在折腾django,一开始用单一的uwsgi控制web访问,虽然说没有什么大问题,但是很多东西没法配置,比如超时时间,uwsgi虽然有个“harakiri”配置项,但并没有什么作用。

未分类

所以终究还是需要接口nginx来做前端代理,但是在代理的出现了一个问题,前端一直没有响应,nginx错误日志(/var/log/nginx/error.log)中出现如下报错

2017/12/21 10:36:48 [error] 9056#0: *18 upstream prematurely closed connection while reading response header from upstream, client: 180.160.72.9, server: localhost, request: "GET /favicon.ico HTTP/1.1", upstream: "uwsgi://127.0.0.1:8000", host: "127.0.0.1:8002"

nginx中access.log返回:

180.160.72.9 - - [21/Dec/2017:10:25:28 +0800] "GET / HTTP/1.1" 499 0 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"
180.160.72.9 - - [21/Dec/2017:10:25:53 +0800] "GET / HTTP/1.1" 499 0 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"
180.160.72.9 - - [21/Dec/2017:10:26:55 +0800] "GET / HTTP/1.1" 499 0 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"
180.160.72.9 - - [21/Dec/2017:10:27:55 +0800] "GET / HTTP/1.1" 502 575 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"

找了很多资料后,从v2ex某个评论中看到了某个点,就是代理的地址需要将端口换成sock进程文件,

最终完美的配置文件

新建一个conf配置文件,同时可解决大部分超时问题,内容如下:

fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 256k;         #以下四个参数已加大,如果设置太小也会出现timeout 504
fastcgi_buffers 16 256k;
fastcgi_busy_buffers_size 512k;
fastcgi_temp_file_write_size 512k;


server {
        listen  8002;
        server_name localhost;

        location / {
            include     uwsgi_params;
            uwsgi_pass   unix:/home/api/vuln_cn/log/uwsgi.sock;    #这里是关键,指向uwsgi.sock文件,不能用127.0.0.1:8000,否则会出现文中的报错
            uwsgi_param UWSGI_CHDIR  /home/api/vuln_cn;     #这里与uwsgi.ini中配置类似,指向django项目目录
            uwsgi_param UWSGI_SCRIPT vuln_cn.wsgi;     #同上,指向项目名称
            access_log /home/api/vuln_cn/log/access.log;     #定义访问日志
            uwsgi_read_timeout 1800;
            uwsgi_send_timeout 300;
            proxy_read_timeout 300;
            }
    }

以上,备忘

Ubuntu+uwsgi+Nginx部署Flask应用

由于是第一次在Linux部署Python应用,过程中遇到很多坑,也找了很多部署博客的分享。再一次体会到好文章带你上天堂,坏文章带你瞎逼忙的道理。索性就记录这次部署的全过程,供以后参考。

介绍

首先先介绍下各个技术的功能,以及他们组合的大致流程。部署的是一个web应用,从用户打开浏览器访问网页开始,到浏览到网页内容,这个过程就是各个技术实现功能的过程。

整体结构

  • 用户浏览器(客户端)打开网页,向服务器发起请求;
  • 请求传给Nginx服务器,Nginx将请求发给uWSGI;
  • uWSGI服务器发来的请求翻译为应用程序理解的形式,发给应用;
  • Flask应用接收请求并处理,将响应结果发给uWSGI;
  • uWSGI与Nginx服务器通信,将结果传给他;
  • Nginx服务器收到响应结果,将其传给客户端;
  • 浏览器显示响应结果,并进行下一个请求。

安装Python环境

阿里云Ubuntu服务器自带的Python2.7和Python3.4,所以尽管我的应用是Python3程序,也不必重新装Python3。

更新apt-get

sudo apt-get update

获取应用源码

由于我的代码放在github仓库,直接通过git来安装。首先安装git:

sudo apt-get install git

安装完成后,在用户目录中新建project目录mkdir project,存放我们的应用程序。不知道是不是在用户目录可以输入指令pwd查看。我们转到project文件夹下,使用git克隆项目源码:

git clone https://github.com/Blackyukun/YuBlog.git

转到项目目录cd YuBlog

安装pip和virtualenv

sudo apt-get install python-pip
sudo apt-get install python-virtualenv

创建虚拟环境

这里需要注意的是,如果直接virtualenv venv命令,创建的将会是Python2的虚拟环境。如果想要创建Python3的环境,需要指定Python3的目录:

virtualenv -p /usr/bin/python3 venv

如果成功,项目目录下会生成一个venv目录,那里就是我们的python3虚拟环境了。接下来激活虚拟环境:

source /home/xyy/py2env/bin/activate

退出虚拟环境命令是:deactivate

安装依赖包

如果项目实在虚拟环境中完成的,那么通常我们会使用pip freeze >requirements.txt命令列出项目所有依赖。然后当我们安装这些依赖的时候只需要使用命令:

pip install -i http://pypi.douban.com/simple/ -r requirements.txt

如果全部安装完成,那么我们的程序依赖环境全都准备好了。

安装Mysql数据库

我的程序是使用Mysql数据库做存储的,安装它也很简单,但是这里会有一个阿里云服务器的大坑。

sudo apt-get install mysql-server mysql-client
sudo apt-get install libmysqlclient-dev

安装过程中会需要你输入用户以及密码,暂且就使用root和password吧。

sudo netstat -tap | grep mysql命令检查Mysql是否安装成功,如果mysql的socket处于listen状态则表示安装成功。

登录mysql数据库命令:mysql -u root -p这里的root就是之前安装是设置的用户名,接着输入密码password。在Linux上,我们需要修改mysql的默认编码为utf-8,以便正确地处理中文。

这里需要编辑MySQL的配置文件,把数据库默认的编码全部改为UTF-8。MySQL的配置文件默认存放在/etc/my.cnf或者/etc/mysql/my.cnf:

vim /etc/mysql/my.cnf

linux使用的是vim编辑器,不了解vim的可以自行了解。我们按i进去插入模式,将下面的指令粘贴到对应位置:

[client]
default-character-set = utf8
[mysqld]
default-storage-engine = INNODB
character-set-server = utf8
collation-server = utf8_general_ci

把队应指令放在对应地方就好了。配置完成后,在vim编辑器下,按ESC进入普通模式,键入:wq进行保存并退出。show variables like ‘%char%’;指令查看编码是否设置正确。如果看到utf8就表示正确。

未分类

接着重启数据库:

service mysql restart

重新登录mysql -u root -p创建我们的数据库,使用:create database mydb;创建名为mydb的库名(注意后面封号)。

中文乱码

这里我们会遇到一个坑,就是在后面程序启动保存数据的时候会出现中文乱码,但是我们明明已经编辑过默认编码了呀。这里我发现是阿里云服务器本身没有安装中文包,我们需要进行安装。

安装中文语言包

sudo apt-get -y install language-pack-zh-hans

修改语言环境设置

echo "LC_ALL=zh_CN.utf8" >> /etc/profile
echo "export LC_ALL" >> /etc/profile

查看语言

source /etc/profile
locale

看到zh_CN.UTF-8就成功了。接着需要重启服务器。

根本原因

虽然中文包安装成功了,但是这样就表示ok了吗?并没有,后来启动中网页中文显示依然乱码。我发现是保存数据库里的数据才会乱码,那么根本原因还是数据库编码问题。

我们需要在创建数据库时要同时定义他的默认编码:

删除数据库:mysql>delete database mydb;

创建数据库:mysql>create database mydb default character set utf8;

安装Nginx服务器

Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件IMAP/POP3代理服务器。其特点是占有内存少,并发能力强。用于接收HTTP请求并返回响应。安装:

sudo apt-get install nginx

启动:sudo /etc/init.d/nginx start

看到OK表示成功。接着需要配置Nginx。Nginx的配置文件在/etc/nginx/sites-available目录的default文件中,将其删除rm default。新的default创建并打开vim default,在里面写入:

server { 
  listen 80; # 80端口需要打开
  server_name X.X.X.X; #阿里云公网ip
  location / { 
  include uwsgi_params;
  uwsgi_pass 127.0.0.1:5000; # 指向uwsgi 所应用的内部地址
  uwsgi_param UWSGI_PYHOME /home/root/project/YuBlog/venv; # 虚拟环境目录
  uwsgi_param UWSGI_CHDIR /home/root/project/YuBlog; # 应用根目录
  uwsgi_param UWSGI_SCRIPT manage:app; # 启动程序
  uwsgi_read_timeout 100; 
 }  
}

重启Nginx:sudo service nginx restart

看到OK表示成功。如果失败,可以输入指令sudo nginx -t查找错误,进行处理。

安装uWSGI

uWSGI虽然也可以起到Web服务器的作用,那么为什么有了uWSGI还需要Nginx呢。具体的优势大家自行了解。在Nginx+uWSGI的结构中,它充当中间件的程序,是Web的通信协议。

安装:sudo pip install uwsgi

注意实在虚拟环境。安装成功后需要配置。我们在项目的根目录下也就是/home/root/project/YuBlog下,创建配置文件config.ini,添加内容:

[uwsgi]
master = true
home = venv
wsgi-file = manage.py
callable = app
socket = :5000
processes = 4
threads = 2

配置完成后,就可以启动uWSGI了。但在这之前,我们先启动应用程序,并添加程序必须的环境变量。

添加linux系统环境变量:export CONFIG=production

先创建迁移仓库:python manage.py db init

创建迁移脚本,migrate子命令用来自动创建:python manage.py db migrate -m “v1.0”

更新数据库操作:python manage.py db upgrade

创建管理员信息:python manage.py addAdmin

ctrl+c终止程序。

启动uWSGI: uwsgi config.ini

会看到很多信息,只要没有报错,就表明启动成功。

部署成功

如果Nginx和uWSGI全部启动成功,就说明部署已经成功了。打开外部浏览器,访问公网ip地址,就可以看到我们的程序已经跑起来了。

配置搭建阿里云服务器nginx+uwsgi (python)

关于使用nginx+uwsgi搭建web服务器,网上有很多教程,但是对新手来说都有些不好理解。下面我总结了一下,纯基础、好使。

首先理解一些基本概念:

WSGI是什么?

WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是为 Python 语言定义的 Web 服务器和 Web 应用程序或框架之间的一种简单而通用的接口。自从 WSGI 被开发出来以后,许多其它语言中也出现了类似接口。

WSGI 的官方定义是,the Python Web Server Gateway Interface。从名字就可以看出来,这东西是一个Gateway,也就是网关。网关的作用就是在协议之间进行转换。

uWSGI是什么?

uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。

nginx、uwsgi、flask之间的关系

  • 首先nginx 是对外的服务接口,外部浏览器通过url访问nginx

  • nginx 接收到浏览器发送过来的http请求,将包进行解析,分析url,如果是静态文件请求就直接访问用户给nginx配置的静态文件目录,直接返回用户请求的静态文件。如果是动态那么nginx就将请求转发给uwsgi,通过flask框架转换为某一函数或者方法进行调用,并处理后,返回给uwsgi。uwsgi转发给nginx,nginx最终将返回结果返回给浏览器。

  • 由此可见nginx并不是必须的,uwsgi完全可以完成整个的和浏览器交互的流程。但是要考虑到某些情况。

  • 安全问题程序不能直接被浏览器访问到,而是通过nginx,nginx只开放某个接口,uwsgi本身是内网接口,这样运维人员在nginx上加上安全性的限制,可以达到保护程序的作用。

  • 负载均衡问题一个uwsgi很可能不够用,即使开了多个work也是不行,毕竟一台机器的cpu和内存都是有限的,有了nginx做代理,一个nginx可以代理多台uwsgi完成uwsgi的负载均衡。

  • 静态文件问题用django或是uwsgi这种东西来负责静态文件的处理是很浪费的行为,而且他们本身对文件的处理也不如nginx好,所以整个静态文件的处理都直接由nginx完成,静态文件的访问完全不去经过uwsgi以及其后面的东西。

好的接下来直接进入搭建过程。 首先你得有一台服务器。这个是我自己的阿里云esc服务器。然后通过ssh root@云服务器ip地址,然后输入密码进行登录。

安装 Python 环境

不多说,一般系统都自带python环境以及pip

安装Nginx

pip install nginx

或者

yum install nginx

安装VirtualEnv

不同的项目可能会引用各种不同的依赖包,为了避免版本与和应用之间的冲突而造成的“依赖地狱”。VirtualEnv 可以为每个Python应用创建独立的开发环境,使他们互不影响。

pip install virtualenv

安装VirtualEnv 后只需要在项目目录内运行 virtualenv 目录名 就可以建立一个虚拟环境文件夹。 假定我的项目目录叫 /home/www/myproj进入该目录后运行

virtualenv venv

项目目录下得到新的venv目录即虚拟环境 (虚拟环境目录可以叫venv,自己随意)

输入

source venv/bin/activate 

进入虚拟环境,前面多了虚拟目录名(venv)

安装 uWSGI

pip install uwsgi

安装 Flask

pip install flask

项目文件

假设到现在为止项目里面只有一个最简单的文件 hello.py,里面内容如下:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello World!"

配置uwsgi

同志们,项目的准备工作准备的差不多了。接下来就是一些配置问题(哎,以前碰到的坑巨多)。

好,在项目目录下新建一个uwsgi.ini

touch uwsgi.ini

创建好了以后,用vim在uwsgi.ini写入以下内容:

[uwsgi]
master = true
home=/home/www/myproj/venv
wsgi-file = hello.py
callable = app
socket=127.0.0.1:5000
stats=127.0.0.1:9191
processes = 4
threads = 4
buffer-size=32768

运行uwsgi试试,如果输出类似以下信息,说明成功。

uwsgi --ini uwsgi.ini
(venv)my_flask root$ uwsgi uwsgi.ini

[uWSGI] getting INI configuration from uwsgi.ini

*** Starting uWSGI 2.0.8 (64bit) on [Tur Sep 19 14:34:11 2017] 
// 此处略去那些无用的启动信息
Stats server enabled on 127.0.0.1:9191 fd: 15 ***

ok,uwsgi已经配置完成,ctrl+c 关闭程序。

配置Nginx

找到配置文件nginx.conf(我的在目录/etc/nginx/nginx.conf),修改以下部分

server {
        charset      utf-8;
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  xxxx域名地址
        root         /home/www/myproj;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
           include      uwsgi_params;
           uwsgi_pass   127.0.0.1:5000;
           uwsgi_param UWSGI_PYHOME /home/www/myproj/venv;
           uwsgi_param UWSGI_CHDIR  /home/www/myproj;
        }
    }

启动Nginx服务器、启动uwsgi服务器

这个地方要注意,我在这卡了我1天。因为有俩个服务器,所以俩个都要启动。

service nginx restart

uwsgi --ini uwsgi.ini

大功告成

nginx+uwsgi+django部署python项目

初次部署nginx+uwsgi+django真是经历了千难万险,因此在这里整理分享一下,希望在这条路上行走的你有所帮助。

我使用的系统是fedora27,已经安装了python3和pip3,这两个没有安装的各位先自行安装。

Nginx

  • 安装
dnf install nginx
  • 配置
location / {
    uwsgi_pass  127.0.0.1:9090;
    include     uwsgi_params; # the uwsgi_params file you installed
}

nginx的配置只需要改这些

Django

  • 安装
dnf install setuptools
pip3 install django
pip3 install PyMySQL
pip3 install mysqlclient
#安装mysqlclient可能会遇到以下下问题,
dnf install mysql-devel # 解决 OSError: mysql_config not found
dnf install gcc # 解决 unable to execute 'gcc': No such file or directory
dnf install redhat-rpm-config # 解决gcc: 错误:/usr/lib/rpm/redhat/redhat-hardened-cc1:No such file or directory
#python-devel for python2.x
#python3-devel for python3.x
dnf install python3-devel 解决 致命错误:Python.h:No such file or directory
  • 启动
#在你的项目目录下
[jeffery@localhost pythontest]$ python3 manage.py runserver 0.0.0.0:8000
Performing system checks...

System check identified no issues (0 silenced).
November 30, 2017 - 08:11:58
Django version 1.11.7, using settings 'pythontest.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.

这样django就启动成功了,可以在浏览器中用8000端口访问一下项目

uwsgi

  • 安装
pip3 install uwsgi
  • django_socket.ini配置
[uwsgi]
socket = 127.0.0.1:9090
chdir = /projects/pythontest
module = pythontest.wsgi
processes = 2
pidfile = uwsgi.pid
daemonize = /var/log/uwsgi/uwsgi9090.log

chdir——你的项目根目录
module——入口文件,即wsgi.py相对于项目根目录的位置,“.”相当于一层目录。如果是用django创建的项目,wsgi.py这个文件是自动生成的,自己找一下。
daemonize——作为后台进程执行,日志输出的地方,目录没有的自己创建下

  • wsgi.py
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pythontest.settings")

application = get_wsgi_application()
  • 启动
uwsgi --ini django_socket.ini

启动完我们就可以去上面daemonize 配置的日志中看看是否启动成功
Nginx中配置的地址端口要和django_socket.ini中保持一致
接下来用浏览器访问下Nginx,有人应该已经能够成功看到自己的python项目了

不行的请继续往下看

VirtualEnv

VirtualEnv的作用:创建隔离的Python环境,解决模块或库的版本冲突或依赖。(我的系统中既有python2.7又有python3.6)

  • 安装
pip3 install virtualenv
  • 创建虚拟环境
virtualenv mytest

mytest是我这边起的名字,可以随便起
创建不了的看下自己当前用户权限够不够, 不是root用户就到 /home目录下找你现在登录的角色的目录,然后进入用户目录下再执行上面的安装命令,执行完以后用ls看下有没有mytest这个文件夹,进入mytest的bin中

[jeffery@localhost /]$ cd /home/jeffery/mytest/bin/
[jeffery@localhost bin]$ ls
activate          django-admin      pip          python         wheel
activate.csh      django-admin.py   pip3         python3
activate.fish     easy_install      pip3.6       python3.6
activate_this.py  easy_install-3.6  __pycache__  python-config
  • 激活mytest虚拟环境
[jeffery@localhost bin]$ source ./activate
(mytest) [jeffery@localhost bin]$ 

此时我们看到命令行前面加上了(mytest),这代表我们在mytest的虚拟环境中,这个时候按照上面django的安装配置重新配置一次,最后在这个虚拟环境中启动django。(我们上面启动的可以不要了,虚拟环境中启动就可以了)

  • 修改django_socket.ini
[uwsgi]
socket = 127.0.0.1:9090
chdir = /projects/pythontest
module = pythontest.wsgi
processes = 2
pidfile = uwsgi.pid
daemonize = /var/log/uwsgi/uwsgi9090.log
home = /home/jeffery/mytest

这里面我们加上了最后一行,也就是配置home——虚拟环境mytest的根目录。

重新启动uwsgi,用浏览器访问Nginx,成功访问python项目。

uwsgi+flask 部署网站

摘要: 采用uwsgi作为web服务,将flask框架开发的web程序运行在centos云服务器上

概要

本文主要是叙述用uwsgi作为web服务运行flask开发的网站。本人查阅网上很多资料。跟着他们的步骤做,总是出现各种问题。折腾好久后,终于能正常运行了。故记录下来,供自己和他人查阅。

开发环境

centos7 64bit 云服务器,python 3.5 , uwsgi 2.0

因为博主用flask开发的web使用的python3.5 ,所以,就在云服务器上安装了3.5.如果你的项目是其他版本python开发的,请安装对应的版本。这里不多加叙述安装问题。

安装uwsgi

因为我的python版本是3.5的。所以一下所有关于python的操作指令都是python3 和pip3.这个如果你的不是,请对应自己的来改。比如你的是python 2.7版本的,你的python指令的开头应该是python或者python2,安装包指令应该是pip2或者pip

有很多方式提供安装,比如yum 安装,手动下载安装包,编译安装,已经pip安装。这里我们选择pip安装。这种方式感觉更靠谱。因为我用yum install uwsgi指令安装,最后uwsgi指定的python版本是我的旧版本2.7.而不是最新的3.5。所以卸载 了,又重新采用了pip安装

安装uwsgi的指令如下:

pip3 install uwsgi

建立软连接

因为我的python3.5是手动下载安装的。所以上一步安装uwsgi,安装成功后,只在我指定的安装目录下。而这个目录下,没有设置环境变量。所以我再shell上输入uwsgi,是不被识别的。为了解决这个问题,我需要建立一个软连接,然后将软连接文件放在环境变量中有的路径下。比如/usr/bin下。

ln -s /usr/python3.5/bin/uwsgi /usr/bin/uwsgi
*如果你安装完后,在shell上面,输入uwsgi已经能够被识别了,那么上面的指令你可以不用操作了。

安装一些依赖包

有些资料上面写着

yum install build-essential 
yum install python-dev

这两条指令,但是这两条指令,在centos上是不叫这个名字的。所以会发现安装不成功。

以下是正确的安装指令:

安装build-essential需要下面的指令:

yum groupinstall "Development Tools"

yum install -y gcc 

yum install g++


yum kernel-devel

因为centos上面没有python-dev的包,而是要安装Python-devel

yum install Python-devel

flask程序包的目录结构

未分类

app是一个包,里面只有一个view.py文件和init文件.初始化文件是空的。下面贴出view.py文件的内容

# encoding: utf-8
#!/usr/bin/ python3
'''
@author: rabbit

@contact: 739462304@qq.com

@time: 2017/11/27 14:09

@desc:

'''

from flask import  Flask

app=Flask(__name__)

@app.route("/")
def hello():
    return "Hello World"


#if __name__ == "__main__":
#    app.run(host='0.0.0.0', port=5000)

manager.py的作用只是作为一个脚本启动入口,通过它启动flaskweb网站。比如你输入

python3 manage.py runserver --host 0.0.0.0

manager.py 内容也贴出来给大家

# encoding: utf-8
#!/usr/bin/env python
'''
@author: rabbit

@contact: 739462304@qq.com

@time: 2017/11/27 14:15

@desc:

'''

from flask_script import Manager, Shell

from app.view import app

manager=Manager(app)

def make_shell_context():
    return dict(app=app)

manager.add_command("shell",Shell(make_context=make_shell_context))

@manager.command
def deploy():
    '''run deployment tasks'''
    pass


if __name__=='__main__':
    manager.run()

使用ini文件配置uwsgi,使网站运行起来

我们可以看到项目里面有个叫config.ini文件,这个是我后期加到项目里的。不是该网站程序所自带的。

我们可以vim 去编辑这个config.ini并保存它。指令如下:

先创建一个新的文件,名字叫config.ini

vim config.ini

未分类

也给出文件内容,方便大家复制粘贴

[uwsgi]


#uwsgi启动时,所使用的地址和端口(这个是http协议的)
http=0.0.0.0:5000

#uwsgi 启动时所使用的地址与端口(这个是socke协议)
socket=0.0.0.0:8001


#指向网站目录
chdir=/root/deployTest

#python 启动程序文件

wsgi-file=manage.py

#python 程序内用以启动的application 变量名

callable=app


#处理器数

processes=4

#线程数

threads=2

#状态检测地址

stats=127.0.0.1:9191

对上面的内容我稍微解释一下。因为本人当初看别人写的这个地方的 配置,说的太模糊了。一直运行不起来,也不晓得是uwsgi没有安装好,还是这个配置文件的问题。搞的很头疼。简要说明如下:

chdir=/root/deloyTest

这个一定要指定到你的项目的目录中

callable=app

这个最难理解。因为当时项目最开始建立了一个叫app的文件夹,同时也建立了一个app.py的文件。app.py文件里面又有一个变量叫app。所以看到有的资料这么写,我很懵逼。最后我才把项目的app.py改成了view.py.经过本人测试。这个app的意思是对应view.py文件里面的flask变量名app.如果view.py里面的变量名改成了application。那么这个配置文件里面也要把app换成application.

启动uwsgi 挂起网站

一起准备妥当,只差最后临门一脚了

指令如下:

未分类

正常运行,界面如上。

浏览器输入网址,应该就能得到我们网站的界面了。

截图如下:

未分类

最后祝你成功!

Flask+uWSGI 的 Logging 支持

本文基于 Flask 0.12.2 。

当 Flask App 被部署到生产环境时,我们会选择关闭 DEBUG 配置。在这种情况下,Flask 中使用 flask.current_app.logger.info() 打印的 LOG 仿佛消失了一样。它们去了哪里呢?

默认的 Handler

下面的源码位于 [flask.logging][loggin] 中。从源码可以看出,Flash 自动创建了 logger 并加入了一个 DEBUG 级别的 Handler 和一个 ERROR 级别的 Handler。根据 DEBUG 变量的值,DEBUG Handler 在生产环境下是不生效的。因此我们就只能看到来自于 ProductHandler 的 ERROR 级别 Log 信息。

def create_logger(app):
    """Creates a logger for the given application.  This logger works
    similar to a regular Python logger but changes the effective logging
    level based on the application's debug flag.  Furthermore this
    function also removes all attached handlers in case there was a
    logger with the log name before.
    """
    Logger = getLoggerClass()
    class DebugLogger(Logger):
        def getEffectiveLevel(self):
            if self.level == 0 and app.debug:
                return DEBUG
            return Logger.getEffectiveLevel(self)
    class DebugHandler(StreamHandler):
        def emit(self, record):
            if app.debug and _should_log_for(app, 'debug'):
                StreamHandler.emit(self, record)
    class ProductionHandler(StreamHandler):
        def emit(self, record):
            if not app.debug and _should_log_for(app, 'production'):
                StreamHandler.emit(self, record)
    debug_handler = DebugHandler()
    debug_handler.setLevel(DEBUG)
    debug_handler.setFormatter(Formatter(DEBUG_LOG_FORMAT))
    prod_handler = ProductionHandler(_proxy_stream)
    prod_handler.setLevel(ERROR)
    prod_handler.setFormatter(Formatter(PROD_LOG_FORMAT))
    logger = getLogger(app.logger_name)
    # just in case that was not a new logger, get rid of all the handlers
    # already attached to it.
    del logger.handlers[:]
    logger.__class__ = DebugLogger
    logger.addHandler(debug_handler)
    logger.addHandler(prod_handler)
    # Disable propagation by default
    logger.propagate = False
    return logger

要解决这个问题,我们需要创建自己的 Handler 。

创建自己的 Handler

在创建了 Flask app 之后,调用下面的 _set_logger 方法将 app 实例传入即可。详细的介绍见代码中的注释。

def _set_logger(flaskapp):
    """
    设置 Flask app 的logger
    """
    # 删除 Flask 的默认 Handler
    del flaskapp.logger.handlers[:]
    if flaskapp.config.get('DEBUG'):
        # 在 DEBUG 模式下,使用 StreamHandler,并使用 DEBUG 级别,这样可以将所有的信息都输出到控制台
        hdr = logging.StreamHandler()
        hdr.setLevel(logging.DEBUG)
        flask.logger.setLevel(DEBUG)
    else:
        # 不使用 StreamHandler 的原因,是 uwsgi 可能会在标准输出中加入它自己的 Log,为了避免Log被弄乱,单独使用一个 FileHandler
        hdr = logging.FileHandler(config.getdir('logs', 'app.log'), encoding='utf8')
        hdr.setLevel(logging.INFO)
        flask.logger.setLevel(INFO)
    # 加入足够详细的信息
    LOG_FORMAT = """
[%(asctime)s] %(levelname)s in %(module)s.%(funcName)s [%(pathname)s:%(lineno)d]:
%(message)s"""
    hdr.setFormatter(logging.Formatter(LOG_FORMAT))
    # 如果存在 sqlalchemy 的 Log 对象,也为其加入这个 Handler
    for log in (flaskapp.logger, logging.getLogger('sqlalchemy')):
        if log:
            log.addHandler(hdr)

我们还可以重写 Flask 对象的 log_exception 方法,自动将所有的异常记录下来,并提供一些更详细的信息:

class MYFlask(Flask):
    def log_exception(self, exc_info):
        """...description omitted..."""
        self.logger.error(
            """
Request:   {method} {path}
IP:        {ip}
Agent:     {agent_platform} | {agent_browser} {agent_browser_version}
Raw Agent: {agent}
            """.format(
                method=request.method,
                path=request.path,
                ip=request.remote_addr,
                agent_platform=request.user_agent.platform,
                agent_browser=request.user_agent.browser,
                agent_browser_version=request.user_agent.version,
                agent=request.user_agent.string,
            ), exc_info=exc_info
        )

uWSGI 的 Logging 配置

我使用 INI 格式的配置文件,文件名一般为 uwsgi.ini。其中关于 Logging 的配置,我常用这样几个:

; 将写入 log 的工作委托给 master 进程
log-master = true
; 单独开一个线程进行 log 写入工作,这样有更好的性能
threaded-log = true
; 所有 log 都会写入这个文件
; 若希望所有 log 放在一起,设置了此选项后,不要设置 req-logger 和 logger 选项
; %d 代表 uwsgi.ini 所在文件夹(包含结尾的/), %n 代表 uwsgi.ini 的主文件名
; 魔术变量: http://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/Configuration.html#magicvars
daemonize = %dlogs/%n.log
; 将 uWSGI 请求 log 写入单独的 log 文件,这样做可以让log更加分离,便于查错
; 设置了此选项后,daemonize 设置的输出文件就得不到任何输出了
req-logger = file:%dlogs/req.log
; 将 uWSGI stdout/stderr log 写入单独的 log 文件
; 因为设定了 req-logger ,必须同时设定 logger ,此时 daemonize 不会有任何输出
logger = file:%dlogs/%n.log

自定义 uWSGI 的请求 log

uWSGI 会在 log 中自动写入请求 log,默认的格式如下:

[pid: 22740|app: 0|req: 162/324] 127.0.0.1 () {36 vars in 608 bytes} [Wed Nov 29 11:42:08 2017] GET /login/?code=001SkzFb1ppEDu0lTzHb1WPCFb1SkzF0 => generated 181 bytes in 69 msecs (HTTP/1.1 200) 5 headers in 209 bytes (2 switches on core 1)

关于其中信息如何解释,文档中并没有详细进行介绍,只能通过阅读 源码 logging.c 理解。

我在 uWSGI 的邮件列表中找到一封邮件 Default Log Format Explained? 介绍了 log 中每个项的详细作用。

pid -> the pid of the worker managing the request
app -> the id (it is a integer, starting from 0) of the app, it makes
sense when multiple apps are hosted in the same instance. It is -1 when no
app managed the request (like when serving static files) or when the ‘app’
concept does not apply (like with php or cgi’s)
req: N/M -> N is the number of managed requests by the current worker for
the specific app, M is the grand total (sum of all requests of all
workers)

then you have REMOTE_ADDR followd by the (optional) REMOTE_USER (very
similar to apache)

vars are the number of CGI vars in the request, and their size (from the
uwsgi protocol point of view). The size is never higher than the
–buffer-size (higher requests are discarded)

The time of the request follows

Then you have REQUEST_METHOD + REQUEST_URI

Then the response size and the time required for generating it

“via” is the techology used to send the response, currently can be
sendfile, routing or offloading.

The response status follows, as well as the number of response headers.

“core” is the low-level concept for uWSGI concurrency context in a process
(can be a thread or a greenlet or a fiber or a goroutine and so on…)
while switches count is incremented whenever an app “yield” its status
(this has various meanings based on the lower concurrency model used)

根据上面找到的资料和 格式化uWSGI请求日志 文档,通过设置 log-format 选项,我们可以模仿出默认的请求 log:

log-format = [pid: %(pid)] %(addr) (%(user)) {%(vars) vars in %(pktsize) bytes} [%(ctime)] %(method) %(uri) => generated %(rsize) bytes in %(msecs) msecs (%(proto) %(status)) %(headers) headers in %(hsize) bytes (%(switches) switches on core %(core))

除了 app: 和 req: 没有提供对应变量,其它的值都可以显示出来。

其它

日志编码器 也是一个重要的选项,若有需要可以添加该设置。

uWSGI 还可以使用 touch-logrotate 和 touch-logreopen 来实现 logging rotate,但为了让系统更加简单的独立,我建议使用 logrotate 来实现 logging rotate,并已经在 uWSGI+rsyslog 实现 rotating logging 一文中介绍过具体做法。

需要注意的是,我在 单独使用 logrotate 中提到的使用 copytruncate 选项替换 create 选项,是因为没有通知 uWSGI 重新打开 log 文件。要做到这一点非常简单,除了使用刚才提到的 touch-logreopen 之外,还可以使用 Master FIFO 中的 l 命令。

在阿里云上通过Ubuntu+uwsgi+nginx+mysql部署Flask(新手向)

0. 前言

这其实也是你所看到的这个网站的部署方式。

老规矩,上环境。截至2017年11月:

Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-62-generic x86_64)

uwsgi –version 2.0.15

nginx version: nginx/1.10.3 (Ubuntu)

supervisord -v 3.2.0

而我的个人电脑是

4.13.12-1-ARCH x86_64 GNU/Linux

1. 创建Ubuntu并创建新用户

在阿里云购买好ECS,我选择的最便宜的1核那个,一年300多,买完之后在控制台可以选择系统,选择好后输入root用户的密码。

未分类

随后会告诉你一个网页上可以连接到服务器的密码,你得记住。随后在网页上登录到服务器。键入

adduser edison

创建一个新用户,当然了用户名你自己取,这里是我的名字。

随后在我的电脑上用ssh连接服务器,这样方便操作些,此处怎么ssh连接服务器就不说了,百度谷歌一大把。

此处先用

ssh root@ip 

来连接。会提示加入密钥回车就好,然后输入你root也就是刚开始创建云盘时的那个密码。就连接成功了。

输入

nano /etc/sudoers

为新创建的用户加入sudo权限:

未分类

输入

apt-get update

更新索引,这里如果比较慢的话可以替换成中科大的源,如何替换百度谷歌就好也很简单。随后开始安装必要的软件。

2.安装python3和git

先安装python3

apt install python3-pip

随后使用pip3安装虚拟环境模块

pip3 install virtualenv

此时可以切换至edison这个新用户。

ssh edison@ip

我是把网站放在了github上,之后更新程序也方便管理。所以这里安装git

未分类

这里发现提示了

sudo: unable to resolve host:xxx

的信息,不影响使用的。可以通过修改hosts文件解决

未分类

未分类

输入y然后回车继续安装git。

在/home/edison下新建目录blog,在blog下git clone把源代码拷下来。

创建虚拟环境:

未分类

注意这里的虚拟环境使用的python3版本。

可以通过启动虚拟环境查看,确实是py3:

未分类

在blog下再新建一个logs文件夹。此时blog应该有三个文件夹,其他两个一个是venv文件夹一个是你的程序的文件夹。

未分类

3. 安装nginx

输入

sudo apt-get install nginx

安装nginx。输入

sudo /etc/init.d/nginx start

启动服务,shell会显示ok提示启动nginx服务成功。这时候打开浏览器,直接输入你的ECS服务器的公网ip就可以看到

未分类

就说明nginx启动成功。接下来用一个小的flask程序进行小小的演示。

创建一个test.py:

未分类

然后在虚拟环境下(根据前文,这时候已经在虚拟环境中了,可以从下图的shell里第一行的前面的venv字眼看出)

pip3 install flask

安装flask模块。

4. 安装uwsgi和supervisor并配置

接下来安装

pip install uwsgi

未分类

然后(此时所在文件夹是blog里)新建一个uwsgi的配置文件,并编辑以下内容,然后启用uwsgi:

未分类

未分类

未分类

可以看到uwsgi已经在运行了。这时候ctrl+c退出uwsgi。

接下来安装supervisor后进入配置文件夹,新建一个文件并输入:

sudo apt-get install supervisor
cd /etc/supervisor/conf.d
sudo nano blogSupervisor.conf

未分类

然后输入

sudo service supervisor start

开启进程管理。

5. 配置nginx

进入/etc/nginx/sites-available/,编辑里面default文件,其中内容是:

未分类

然后输入

sudo service nginx restart

重启nginx服务器。打开浏览器输入你的公网ip,就能看到

Hello World! 啦

未分类

这里部署就基本完了,只要把上述的配置文件里提到test这个py文件替换成你的文件,例如manage.py就好了。

6. Mysql和后续

接下来简单说说怎么使用mysql:

安装pymysql,在config.py里使用

“mysql+pymysql://root:xxx@localhost:3306/xxxxx”

的方式启用mysql。

p.s

在使用mysql上尝试了很多方法,但是由于ubuntu的系统python是2,而虚拟环境中python为3,所有总有一些包安装不上,特别是mysqldb的问题,只能使用mysql+pymysql的方法。但是很奇怪的现象是,我的archlinux默认的python是3.6,使用的mariadb,但是不用pymysql也能连接上mysql,而且:

$ python                                                           
Python 3.6.3 (default, Oct 24 2017, 14:48:20) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import MySQLdb
>>> 

百思不得其解,如果有缘人看到了这里希望能给出答复。

Nginx+uwsgi 安装配置

在前面的章节中我们使用 python manage.py runserver 来运行服务器。这只适用测试环境中使用。
正式发布的服务,我们需要一个可以稳定而持续的服务器,比如apache, Nginx, lighttpd等,本文将以 Nginx 为例。

安装基础开发包

Centos 下安装步骤如下:

未分类

CentOS 自带 Python 2.4.3,但我们可以再安装Python2.7.5:

未分类

安装Python包管理

easy_install 包 https://pypi.python.org/pypi/distribute

安装步骤:

未分类

pip 包: https://pypi.python.org/pypi/pip

安装 pip 的好处是可以用 pip list、pip uninstall 管理 Python 包, easy_install 没有这个功能,只有 uninstall。

安装 uwsgi

uwsgi:https://pypi.python.org/pypi/uWSGI
uwsgi 参数详解:http://uwsgi-docs.readthedocs.org/en/latest/Options.html

未分类

测试 uwsgi 是否正常:
新建 test.py 文件,内容如下:

未分类

然后在终端运行:

未分类

在浏览器内输入:http://127.0.0.1:8001,查看是否有”Hello World”输出,若没有输出,请检查你的安装过程。

安装 Django

未分类

测试 django 是否正常,运行:

未分类

在浏览器内输入:http://127.0.0.1:8002,检查django是否运行正常。

安装 Nginx

安装命令如下:

未分类

你可以阅读 Nginx 安装配置 了解更多内容。

uwsgi 配置

uwsgi支持ini、xml等多种配置方式,本文以 ini 为例, 在/ect/目录下新建uwsgi9090.ini,添加如下配置:

未分类

Nginx 配置

找到nginx的安装目录(如:/usr/local/nginx/),打开conf/nginx.conf文件,修改server配置:

未分类

你可以阅读 Nginx 安装配置 了解更多内容。

设置完成后,在终端运行:

未分类

在浏览器输入:http://127.0.0.1,你就可以看到 django 的 “It work” 了。