部署Flask + uWSGI + nginx

作为一个选择综合症+洁癖患者,在部署 Flash app 的时候着实有点纠结。下面是我的部署过程,适用于各个 linux 发行版。

选择

  • Flask 开发使用 python3.5 ;
  • python 虚拟环境,使用 python3.3 开始自带的 venv;
  • 启动器使用 supervisor,后面会说明原因;
  • uwsgi 和 supervisor 均使用 pip 安装,而不使用发行版自带的版本。

因为 ubuntu 自带 uwsgi,我曾经纠结过使用系统自带版本还是使用 pip 版本。使用自带的版本的好处,就是安装后可以直接使用 /etc/init.d/uwsgi start 来启动,不需要自己写启动脚本,但我仍然选择了使用 pip 版本。下面是原因。

uwsgi 的版本在 Ubuntu 12.04 上比较老了(1.03),这让人心生不快。supervisor 的优势摆在那里,而且也是 python 写成,这激发了我的纯正血统情怀。还有一个优势就是 uwsgi 可以安装在 venv 之下,这样不必影响系统包的稳定性。

supervisor 也有系统自带版本,版本号很老了(3.0a8-1.1)。supervisor 文档 中贴心地提供了全套 initscripts ,在各个发行版上启动都不是问题。

安装 supervisor

supervisor 不支持 python3 ,这在官方文档中就已经说明:

Supervisor is known to work with Python 2.4 or later but will not work under any version of Python 3.

好在服务器上都有自带的 python2 。但我的服务器上的 python2 中并没有 pip,因此需要先安装 pip。

标准的 pip 安装方法是:

wget https://bootstrap.pypa.io/get-pip.py
python get-pip.py

但由于安装和下载过程中的全部内容都是国外的服务器,这个方法太耗时。下面提供一个简单的方法。

1. 访问 豆瓣的 pypi 源 ,在该页面中搜索 6.1.0.tar.gz ,下载搜索到的那个链接,例如我的下载链接为:

http://pypi.doubanio.com/packages/6c/84/432eb60bbcb414b9cdfcb135d5f4925e253c74e7d6916ada79990d6cc1a0/pip-6.1.0.tar.gz#md5=d0c349765bbc23743cec42b37bd8a281

更多的源请参见: 常用开源镜像站整理

2. pip 的安装依赖 setuptools ,搜索 20.1.tar.gz ,下载搜索到的那个链接。

3. 将下载到的两个压缩包解压,然后安装:

python setuptools-20.1/setup.py build
python setuptools-20.1/setup.py install
python pip-6.1.0/setup.py build
python pip-6.1.0/setup.py install

上面的版本号不一定要和我的一致,但一定要选择 tar.gz 的压缩包,这样的压缩包还是使用 egg 格式发布的,可以使用 setup.py 安装。新版本的 pip 和 setuptools 都使用 wheel 格式发布了,解压后无法使用 setup.py 安装。想了解 egg 和 wheel 的区别,可参考 Python 包管理工具解惑

安装了 pip 之后,就可以使用 pip install supervisor 了。

这里还有一个小插曲。我使用 常用开源镜像站整理 中提到的方法把 pypi 的源设置成了豆瓣 HTTPS 源,但更新 pip 的时候报错:

# pip install -U pip
/usr/local/lib/python2.7/dist-packages/pip-6.1.0-py2.7.egg/pip/_vendor/requests/packages/urllib3/util/ssl_.py:79: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
DEPRECATION: Failed to find 'pip' at https://pypi.doubanio.com/simple/pip/. It is suggested to upgrade your index to support normalized names as the name in /simple/{name}.
/usr/local/lib/python2.7/dist-packages/pip-6.1.0-py2.7.egg/pip/_vendor/requests/packages/urllib3/util/ssl_.py:79: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
Cannot fetch index base URL https://pypi.doubanio.com/simple/
/usr/local/lib/python2.7/dist-packages/pip-6.1.0-py2.7.egg/pip/_vendor/requests/packages/urllib3/util/ssl_.py:79: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning
Requirement already up-to-date: pip in /usr/local/lib/python2.7/dist-packages/pip-6.1.0-py2.7.egg

看反馈的信息可能是 urllib3 自带的 ssl 加密问题。pip 升级到 8.1.2 也有相同的问题。

因此,我把 pypi 源换成了没有 https 加密的地址(见下方),安装成功。

# pip install supervisor
Collecting supervisor
  Downloading http://pypi.zenlogic.net/packages/44/80/d28047d120bfcc8158b4e41127706731ee6a3419c661e0a858fb0e7c4b2d/supervisor-3.3.0.tar.gz (416kB)
    100% |████████████████████████████████| 419kB 3.3MB/s 
Collecting meld3>=0.6.5 (from supervisor)
  Downloading http://pypi.zenlogic.net/packages/py2.py3/m/meld3/meld3-1.0.2-py2.py3-none-any.whl
Installing collected packages: meld3, supervisor
  Running setup.py install for supervisor ... done
Successfully installed meld3-1.0.2 supervisor-3.3.0

配置 supervisor

下面以 ubuntu 为例进行配置。

  1. initscripts 下载 ubuntu 的启动脚本,复制到 /etc/init.d/supervisor
  2. 修改启动脚本中的路径,使其与安装路径相匹配。如果使用 pip 安装,supervisord 一般位于 /usr/local/bin/ 而非默认的 /usr/bin/ ;
  3. 执行 echo_supervisord_conf > /etc/supervisor/supervisord.conf 创建一个默认的配置文件;
  4. 调整 /etc/supervisor/supervisord.conf 中的几个路径相关的参数,使其与 /etc/init.d/supervisor 中的路径参数完全一致:
file=/var/run/supervisor.sock   ; (the path to the socket file)
logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
serverurl=unix:///var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)

上面的三个参数默认的值位于 /tmp 中,这样可能会导致执行 /etc/init.d/supervisor start 的时候由于找不到 pid 文件导致误判。看看成果吧!

# service supervisor start
Starting supervisor: supervisord.
# service supervisor status
supervisord is  not running.

(未完待续)

Homebrew 安装的 MySQL 在 EI Capitan 上无法启动

用 Homebrew 安装的 MySQL 5.7.12 莫名其妙就挂掉了,翻看系统日志,看到一堆这样的提示:

Jun 2 20:08:49 zrong-mbp com.apple.xpc.launchd[1] (homebrew.mxcl.mysql) : Service only ran for 0 seconds. Pushing respawn out by 10 seconds.

这样的提示每10秒一次,从中午一直到现在。 继续阅读Homebrew 安装的 MySQL 在 EI Capitan 上无法启动

一定要开的会

Solution

程序员都讨厌开会,我也讨厌开会。

《重来:更为简单有效的商业思维》 一书中对于开会有一段这样精彩的描述:

通常会议只是文字和抽象的内容,没有实质。
通常会议每分钟只传达出极为少的信息。
人们在会议中容易跑题堪比暴风雪里的芝加哥出租车。
会议要求做充分的准备,但是大多数人没有时间做这个。
频繁地提出模糊的议程而没有人能真的清楚目标是什么。
常常会出现至少一个傻瓜不可避免的,毫无意义的浪费大家时间。

上面列出的是低效失败会议的通病。就像那句著名的话一样:所有的糟糕的会议都是一样的,而完美的会议则根本不存在继续阅读一定要开的会

QCon2016全球软件开发大会随笔(二)

QCon2016全球软件开发大会随笔(一)


今天是QCon2016的第二天。北京的天气依然好得一塌糊涂。除了风大了点。啥也不说了,继续上短袖。

好天气1
好天气2

有了昨天的良好睡眠,今天听课终于是不困了。但无论如何,9个分会场的63场演讲是没办法同时听完的。也正因为有了更清醒的大脑,我采取了一种新的听课方法:10M听课法

继续阅读QCon2016全球软件开发大会随笔(二)

QCon2016全球软件开发大会随笔(一)

今天是QCon2016的第一天。北京的天气简直是好得不可思议,9°到31°的温差美得令人心醉。啥也不说了,短袖伺候。

好天气

和上个月来参加TFC(见国内VR发展现状——12届TFC会议期间见闻)不同的是,北京国际会展中心门口没有看到任何莫名其妙的布置,没有ShowGirl,专业的技术会议本来就应该这么低调才对。

继续阅读QCon2016全球软件开发大会随笔(一)