awakeBird Back-end Dev Engineer

项目部署路上的坑

2017-01-15

直播通项目终于更新上线了,看到自己的第一个Web应用在服务器上正常运作并且各项功能正常,内心一阵暗爽。看了一眼时间,从有想法到最终项目上线,一共用了大概一周左右时间,作为一个简单的flask应用,这点时间不算长也不算短,其中部署只花了一晚上就弄好了,在这里要感谢已经工作的老友提供思路,虽然部署的时候也踩过不少坑,但确实少走了许多弯路。所谓前人栽树后人?哈?

服务器选择

这里直接选择了朋友推荐的腾讯云,一路低配,在选择内存时担心1G内存不够选了2G(心疼),最终抛过代金券还是花了90大洋。不过,值!

部署思路

这里有两种思路可供选择,

  • gunicorn + supervisor + nginx, 部署流程简单清晰,但听说性能不好。
  • 朋友推荐的gunicorn + pm2方案,但看了一眼pm2,全部时node.js相关的代码,超纲了啊!

我的目的是让自。己的项目尽快跑起来,因此,选择了有较多参考资料和前人经验的第一种思路,第二种的话,以后在说吧。

开始部署

部署准备

好,登录服务器,输入用户名和密码登录Linux(这里选择和我平时用的一样的Ubuntu 16.04 64位机),先按照网上的教程将python和虚拟环境弄好,之后git clone代码。等等,者一大堆错误是什么,又是用户权限又是链接错误,折腾了许久未果,于是退而求其此,直接将本地代码复制到服务器上:

$ scp -r easySee ubuntu@www.mydomain.com:/var/www/easySee

刚开始不清楚这行代码的作用,照葫芦画瓢,于是很自然的在easySee目录下又嵌套了一个同名文件,好low。不过既然是自己的服务器,就先这样吧。之后在虚拟环境中安装requirements中的需求模块,部署准备完成。

Gunicorn

是什么

关于这部分内容,在部署的时候时完全没有考虑的,因为目的就是让项目尽快跑起来嘛。但不求甚解终归不是好的学习方法,还是要了解以下部署的每个部分是什么,能干嘛,于是补了这部分知识。

gunicorn是一个Python WSGI UNIX的HTTP服务器,是一个per-fork worker模型。换句话说,Gunicorn一般用来管理多个进程,有进程挂了Gunicorn就可以把它拉起来,防止服务器长时间停止服务,还可以动态调整worker的数量,请求多的时候增加worker的数量,请求少的时候减少,这就是所谓的per-fork模型,也是Gunicorn的主要优点。其他优点还有能与各种web框架兼容,只需要非常简单的执行,轻量级的资源消耗以及很快的响应速度。

怎么用

  • 安装
    (venv) $ pip install gunicorn
    
  • 运行(在项目根目录下)
(venv) $ gunicorn -w 4 -b 127.0.0.1:8080 manage:app

在本机上输入服务器ip及端口号后,马上看到了自己的应用。Yeah!这其实就是gunicorn的好处吧,根本不需要什么配置文件,一格指令就能将它启动。

tip: 这里网上教程说还需要添加一个wsgi.py的文件替换掉manage.py,并特别注明wsgi.py和manage.py没有半毛钱关系。然而我的试验结果是,这两个完全就是一模一样的嘛-,- ,先这样吧,出了问题再说。

Nignx

是什么

一个完整的代理请求过程为:客户端首先与代理服务器创建链接,接着根据代理服务器所使用的代理协议,请求对目标服务器创建链接或者获得目标服务器的指定资源。Web代理服务器(proxy)是网络的中间实体,代理位于Web客户端与Web服务器之间,扮演中间人的角色。HTTP的代理服务器即是Web服务器,又是Web客户端。

正向代理时一个介于客户端与原始服务器之间的服务器,为了从原始服务器获得内容,客户端向代理发送一个请求并指定目标,然后代理向原始服务器转交请求并将获得的内容返回给客户端。

反向代理服务器:在服务器端接受客户端的请求,然后把请求分给具体的服务器进行处理,再将服务器的响应结果返回给客户端。

Nginx(“engine x”)是一款高性能的HTTP和反向代理服务器软件,既可以托管网站,进行HTTP服务,也可以作为反向代理服务器使用。

那么在Gunicorn前部署一层Nginx的目的是什么呢?

  • 负载均衡。
  • 静态文件支持
  • 伪静态化并缓存,减少动态请求数量
  • 依赖于nginx强大的功能和性能,可以做到访问控制,限速,限制链接数等。

也就是说,nginx可以缓冲请求和响应,也能缓存客户端发起的请求,这个过程时nginx擅长处理的,可以有效提高Gunicorn的处理能力。

怎么用

这里同样参照教程,安装完成后,直接进入Nginx的配置文件

sudo vim /etc/nginx/site-avalidable/default

当然,如果你怕搞错(就像我一样),可以先将配置文件备份

sudo cp /etc/nginx/site-avalidable/default /etc/nginx/site-avalidable/default.bak

之后将default暴力修改成下面的内容:

server {
    listen 80;
    server_name 119.29.3.128; # 这是HOST机器的地址也
    location / {
        proxy_pass http://127.0.0.1:8080; # 这里是指向 gunicorn host 的服务地址
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }

之后保存,重启Nignx服务器

sudo service nginx restart

supervisor

是什么

Supervisor是一个用Python写的进程管理工具,可以很方便的用来启动,重启,关闭进程(不仅仅是Python进程),还可以很方便的管理多个进程,同时启动同时关闭等等。因此将gunicorn用supervisor来包装,很方便的管理进程运行,并且可以防止gunicorn服务器挂掉。而且如果项目中需要多进程运行时,也可以用supervisor来配置。

怎么用

安装后首先将原始配置文件重定向到程序根目录:

$ echo_supervisor_conf>supervisor.conf

其实也可以不用进行这个步骤,但是每次打开supervisor服务时都要输入配置文件目录比较麻烦。 之后打开supervisor.conf,在最后加上自己的进程信息:

[program:easySee]
command=/home/ubuntu/venv/bin/gunicorn -w 4 -b 0.0.0.0:8080 manage:app     ; supervisor启动命令
directory=/var/www/easySee/easySee                                         ; 项目的文件夹路径
startsecs=0                                                                ; 启动时间
stopwaitsecs=0                                                             ; 终止等待时间
autostart=false                                                            ; 是否自动启动
autorestart=true                                                           ; 是否自动重启
stdout_logfile=/.../app/data/log/gunicorn.log                              ; log 日志
stderr_logfile=/.../app/data/log/gunicorn.err                              ; 错误日志
[program:XXXXX]                                                            ; 用于多进程

之后启动supervisor

$ supervisord -c supervisor.conf

之后的事不多说了,操作命令:

supervisord -c supervisor.conf                             通过配置文件启动supervisor
supervisorctl -c supervisor.conf status                    察看supervisor的状态
supervisorctl -c supervisor.conf reload                    重新载入 配置文件
supervisorctl -c supervisor.conf start [all]|[appname]     启动指定/所有 supervisor管理的程序进程
supervisorctl -c supervisor.conf stop [all]|[appname]      关闭指定/所有 supervisor管理的程序进程

这里要说下自己部署时出现的问题,在supervisor已经启动的状态下修改了配置文件,又不知道reload这个命令,于是想重新导入supervisor文件启动时出现了错误,提示端口正在被监听,这里给出解决方法:

$ ps -ef | grep supervisord

然后看到

root   2503  1  0 Nov19 ?  00:03:23 /usr/bin/python /usr/bin/supervisord
root   21337 2556  0 18:15 pts/8   00:00:00 grep --color=auto supervisord

再执行:

kill -s SIGTERM 2503

即可。

再说一点

写到这里,把部署期间的所有流程和问题处理基本又复习了一遍,主要用到的部分也大概知道都有什么作用了,再深入了解的话大概就到运维的范畴了,这次真的可以浅尝辄止了。

部署并没有想象中的恐怖,只是折腾的时间要久一点罢了。CS这东西还真就全凭折腾,耐下性子干就是了,之后及时回头看看,收获颇丰呢。

就这样啦。


Comments

Content