用daapi
项目(Dashboard 2.0的JSON API)为实例,介绍用到的一些Python第三方库、一些用Python做web项目的best practice,以及如何使用Ansible来做自动部署。
可以直接在命令行运行Python的package或者module,类似这样:python -m module_name
。
比如python -m this
,输出The Zen of Python。
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
另外还有一点就是写Python的时候应该ask forgiveness not permission,也就是说不先检查我是否可以这么做,而是直接这么做,然后检查是否抛异常。
跑一个web server,把当前目录通过8000
端口暴露出去,方便偶尔共享文件。
$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
美化JSON。
$ echo '{"a": 1, "b": 2}'
{"a": 1, "b": 2}
$ echo '{"a": 1, "b": 2}' | python -m json.tool
{
"a": 1,
"b": 2
}
用版本控制系统。用requirements.txt
列出项目完整依赖。使用virtualenv
隔离不同项目之间的Python依赖。config.py
从环境变量里读取配置信息,比如数据库的连接信息。
这些东西Heroku的The Twelve Factors指南有很详细的阐述。
- Heroku: https://www.heroku.com/
- The Twelve Factors: http://12factor.net/
Heroku是一个非常有意思的平台,不限语言,不限框架,提供许多web app运行的infrastructure。大家可以试着在上面部署一个web app感受一下。
完整的依赖见requirements.txt
文件:
Flask
Flask-Script
SQLAlchemy
colander
psycopg2
passlib
itsdangerous
times
redis
requests
lxml
我基本上只是把文档连接给出来,这些库不但代码写的好,而且文档都非常的优秀。
- Flask: http://flask.pocoo.org/ 已经非常大众的,灵活的服务器端
MVC
框架。 - Flask-Script: http://flask-script.readthedocs.org/en/latest/
- SQLAlchemy: http://www.sqlalchemy.org/ 最好的ORM。
- colander: http://docs.pylonsproject.org/projects/colander/en/latest/ Schema验证库。比如判断用户登陆接口需要传
username
,password
两个参数,每个参数各有要求,比如用户名不能太长,密码不能太短等。
from colander import SchemaNode, MappingSchema
from colander import String
from colander import Length
class LoginSchema(MappingSchema):
username = SchemaNode(String(), validator=Length(max=127))
password = SchemaNode(String(), validator=Length(min=3, max=127))
- psycopg2: http://pythonhosted.org/psycopg2/ Postgres数据库的Python客户端库,是对
libpq-dev
的封装。 - passlib: http://pythonhosted.org/passlib/ 正确的做密码加密、验证的最轻松方式。
daapi
的User model只需要这么写:
from passlib.apps import custom_app_context as pwd_context
class User(Base):
......
def set_password(self, raw_password):
self.pw_hash = pwd_context.encrypt(raw_password)
def check_password(self, raw_password):
return pwd_context.verify(raw_password, self.pw_hash)
......
最后pw_hash
存储到数据库中就是类似这样的:$6$rounds=64445$IUu672cizY6zRU9Q$pXI73zFHSF2CQpze4p/0PRyI4xyM7irDFS.mehJNBSYxQPIpb3yU0NMbGeKSlrv9dmaUz0BU5.11wr19CACc11,非常的业界良心。
- itsdangerous: http://pythonhosted.org/itsdangerous/ 名字取的非常酷。文档比实际代码长几倍。作者和
Flask
作者是同一人,现在已经是Flask
的依赖之一,用于处理Flask
里cookie session的签名、验证。daapi
用它实现session_key
的签名、验证。 - times: https://github.com/nvie/times/
daapi
其实只用times.to_unix
把一个UTC时间的datetime.datetime
对象转化成Unix Timestamp。出镜理由是API好记,并且简单的API背后有深刻的理论支持:Dealing with Timezones in Python。 - redis: https://github.com/andymccurdy/redis-py Python的redis客户端库。介绍如何使用redis的lua脚本支持来扩展redis的功能。
- requests: http://www.python-requests.org/ 又一个不需要介绍的Python库。介绍如何发挥这个库的
requests.session
特性(HTTP 1.1的Keep Alive支持)。requests的作者还有另外一个非常有用的项目:http://httpbin.org/,代码在https://github.com/kennethreitz/httpbin,是一个Flask的web app,部署在Heroku上面(作者本人是Heroku员工)。 - lxml: http://lxml.de/lxmlhtml.html lxml.html是Python HTML解析库中最成熟、兼容性最好、速度最快的。
演示首先用Vagrant
起了两台Ubuntu 12.04的虚拟机,一台web(192.168.100.10),一台db(192.168.100.20)。
虚拟机起来后Vagrant
会调用Ansible
完成机器的安装配置。web用nginx反向代理,uwsgi作为app server,用Supervisor进行进程监控,基本上是Python web app部署的标准做法。db用Postgres数据库。
详细的配置见Vagrantfile
:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant::Config.run do |config|
config.vm.define :web do |web_config|
web_config.vm.box = "precise64"
web_config.vm.box_url = "http://files.vagrantup.com/precise64.box"
web_config.vm.forward_port 80, 8080
web_config.vm.network :hostonly, "192.168.100.10"
web_config.vm.provision :ansible do |ansible|
ansible.playbook = "devops/webserver.yml"
ansible.inventory_file = "devops/hosts"
end
end
config.vm.define :db do |db_config|
db_config.vm.box = "precise64"
db_config.vm.box_url = "http://files.vagrantup.com/precise64.box"
db_config.vm.forward_port 5432, 54322
db_config.vm.network :hostonly, "192.168.100.20"
db_config.vm.provision :ansible do |ansible|
ansible.playbook = "devops/dbserver.yml"
ansible.inventory_file = "devops/hosts"
end
end
end
然后执行ansible-playbook devops/deploy.yml -i devops/hosts --private-key=$HOME/.vagrant.d/insecure_private_key
完成部署。
Ansible
的详细配置在daapi
项目下的devops
目录。
部署完成后,直接访问 http://192.168.100.10/ 即可。
- Vagrant: http://www.vagrantup.com/
- Ansible: http://www.ansibleworks.com/
- Vagrant的Ansible支持: http://docs.vagrantup.com/v2/provisioning/ansible.html