在一个开发环境中运行不同版本的Python(wsgi)应用程序

首先

我的开发用Linux环境中通过操作系统的包管理命令安装了Python 2.7和Django 1.4。由于我正在开发的应用程序在这个环境中可以正常运行,所以没有问题。

有一次,我决定尝试将即将发布的Django 1.7与Python 3.4结合起来,以探索到底会遇到什么样的困难。

我們希望在相同的環境下進行先行技術的調查,同時不破壞現有的開發環境。

然而,这个”一个操作系统,多个Python和Django”的概念其实相当困难。上次我尝试的时候(参考链接:http://qiita.com/amedama/items/79994598d9f4daa69d13),由于Apache2的mod_wsgi无法同时运行多个版本的Python,所以进展一直停滞不前。

本次我们尝试作为替代方案,在同一主机上独立搭建一个wsgi服务器,并额外从Apache2设置反向代理来解决这个问题。

详细来说

    • aptで入れたPython2.7 + django 1.4 環境

 

    pyvenv と pip を駆使した Python3.4 + django 1.7 環境

我們將探索在一個開發環境中同時並行啟動兩個環境的方法。

此外,我还遇到了与Django 1.7不兼容的实际改动,我也会稍稍介绍一下。

请任意选择:在文章的末尾,我还附上了一个7分钟的视频,展示了本文内容的一部分在实际终端上的实践过程。您可以选择阅读文章,观看视频,或是两者兼顾,随您喜好。

以下是重要角色:

    • Python2.7 … 安定のPython2系

 

    • Python3.4 … Python3期待の星

 

    • Apache2 … フロントエンド。mod_wsgi経由でwsgiサーバにもなるが、mod_wsgi1つは1つのPython環境しか提供出来ないため、上に乗っかるwsgiアプリはPython2系のどれかかPython3系のどれか一種類でしか動かなくなる。Linux1環境にApacheバイナリを2つ入れるというのは若干狂気に見えたのでやってない。

 

    • django 1.4 … 古い子

 

    • django 1.7 … 生まれてないベータ

 

    • xbuild … Python3.4のビルドを最初に行うときに使う

 

    • virtualenv … Pythonの環境を作るもの

 

    • pyvenv … Python3系で導入されたvirtualenvみたいなの

 

    • tornado … 単体動作するwsgiサーバ

 

    • supervisor … デーモンプロセスを束ねるデーモン。今回はwsgiサーバを束ねる

 

    /opt … 今回Djangoプロジェクト等はここに打ち込む

django应用程序的views.py文件

由于这次,views.py的内容本身并不重要,所以我们将继续使用以下内容:
返回Python版本和Django版本的纯文本。

from django.http import HttpResponse
import django
import sys

def home(request):
    version = ('Python: {}\nDjango: {}\n'
               .format(sys.version.replace('\n', ' '),
                       django.get_version()))
    return HttpResponse(version, content_type="text/plain")

运行manage.py中的runserver命令

我安装了apt上的东西(Python2.7 + Django 1.4)。

假设已经事先准备好了tornado和django(较旧版本)等工具。
我认为无论是使用sudo pip还是apt-get(如果是Debian系统)命令都可以。

蛇足是这样的:如果使用pip安装的话,默认会安装1.6版本的Django,如果没有指定版本。根据本文的结果来看,在Debian wheezy (7.5)中使用apt-get install python-django是最接近目标的。根据我的了解,Ubuntu 12.04LTS安装的是1.3版本的Django,而Ubuntu 14.04LTS则安装的是1.6版本。换句话说,不同的环境有不同的情况。重要的是,Django 1.7并不会被安装。至于Python 3.4,在Ubuntu 14.04LTS中可以通过apt-get来安装。

    • django-admin startproject test1

 

    • settings.pyのsqlite3に関する設定をする。

db/db.sqlite3 をファイル保存先とし、www-dataから書き込めるようにする)

views.pyとurls.pyを変更
python mangae.py syncdb

python manage.py runserver

ブラウザで Python 2.7.3, Django 1.4.5 の文字列を確認

使用pyvenv和pip将Python3.4和Django 1.7结合在一起。

我正在创建第二个虚拟环境,有没有更好的方法呢?

$ xbuild/python-install 3.4.0 /opt/python3.4.0
$ cd /opt
$ /opt/python3.4.0/bin/pyvenv /tmp/venv
$ source /tmp/venv/bin/activate
(venv)$ pip install https://www.djangoproject.com/download/1.7b3/tarball/
(rehash on zsh)
(venv)$ python --version
Python 3.4.0
(venv)$ django-admin.py --version
1.7b3
(venv)$which pip
/opt/test2/venv/bin/pip
(venv)$ django-admin.py startproject test2
(venv)$ cd test2
(venv)$ deactivate
(rehash on zsh)
$ /opt/python3.4.0/bin/pyvenv venv
$ source venv/bin/activate
(venv) $ pip install https://www.djangoproject.com/download/1.7b3/tarball/
(rehash on zsh)
    • settings.pyのsqlite3のdb保存先をdb/db.sqlite3へ変える

 

    • パーミッションを変更

 

    • views.pyとurls.pyを変更

 

    • python mangae.py syncdb

python manage.py runserver

ブラウザで Python 3.4.0, Django 1.7b3 の文字列を確認

使用tornado在命令行上启动WSGI服务器

顺便提及,我参考了以下这篇文章。

    • http://www.tornadoweb.org/en/stable/index.html

 

    • https://github.com/facebook/tornado

 

    https://github.com/bdarnell/django-tornado-demo

我们将在这次更新中,在项目的根目录下,通过将tornado_main.py文件放置在下一个文件中来模糊问题。

与 https://github.com/bdarnell/django-tornado-demo 内容几乎相同,只是增加了通过命令行修改端口号的功能。另外,这次与 HelloHandler 无关的代码我忘记删除了。

from tornado.options import options, define, parse_command_line
import django.core.handlers.wsgi
import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.wsgi

define('port', type=int, default=18000)

class HelloHandler(tornado.web.RequestHandler):
  def get(self):
    self.write('Hello from tornado')


def main():
    parse_command_line()
    wsgi_app = tornado.wsgi.WSGIContainer(
        django.core.handlers.wsgi.WSGIHandler())
    tornado_app = tornado.web.Application(
        [('/hello-tornado', HelloHandler),
         ('.*', tornado.web.FallbackHandler, dict(fallback=wsgi_app)),
         ])

    server = tornado.httpserver.HTTPServer(tornado_app)
    server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == '__main__':
  main()

请注意,如下所述,在 Django 1.7 中,使用此 tornado_main.py 实现将无法正常运行。

使用apt-get准备的选择

$ DJANGO_SETTINGS_MODULE=test1.settings python tornado_main.py

确认Python和Django的版本

pyvenv和pip的方法

(venv)$ pip install tornado
(venv)$ PYTHONPATH=venv/lib/python3.4/site-packages DJANGO_SETTINGS_MODULE=test2.settings python tornado_main.py

请确认Python和Django的版本。

让主管以守护进程的方式启动两个WSGI应用程序。

这次,我会给主管安排在apt中。就像上面所提到的分开管理的好处一样,我觉得对于主管来说并没有什么优势。

补充一点,虽然在apt-get中直接使用3.0a8也可以,但是我选择从不稳定版本中获取源码(3.0r1.1)进行构建。这与本篇文章无关,只是提供参考。

在安装了apt的supervisor后,将以下配置文件放置在/etc/supervisor/conf.d/目录下。

[program:test1]
command=python tornado_main.py --port=18101
directory=/opt/test1
autostart=true
autorestart=true
user=www-data
environment = DJANGO_SETTINGS_MODULE="test1.settings"

[program:test2]
command=/opt/test2/venv/bin/python tornado_main.py --port=18102
directory=/opt/test2
autostart=true
autorestart=true
user=www-data
environment = PYTHONPATH="/opt/test2/venv/lib/python3.4/site-packages", DJANGO_SETTINGS_MODULE="test2.settings"

两者都进行了活动,令人欣喜。

应用程序注册表尚未准备好。

2.7的情况还可以,但3.4的话就不能正常运作了。

在查看/var/log/supervisor/supervisord.log文件的同时,我们会详细列举并分析异常情况。

造成原因是因为Django 1.7的规格变更。

If you’re using Django in a plain Python script — rather than a management command — and you rely on the DJANGO_SETTINGS_MODULE environment variable, you must now explicitly initialize Django at the beginning of your script with:

>>> import django
>>> django.setup()

哦,好的。

from tornado.options import options, define, parse_command_line
import django
import django.core.handlers.wsgi
import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.wsgi

define('port', type=int, default=18000)

class HelloHandler(tornado.web.RequestHandler):
  def get(self):
    self.write('Hello from tornado')


def main():
    // For django 1.7
    django.setup()
    parse_command_line()
    wsgi_app = tornado.wsgi.WSGIContainer(
        django.core.handlers.wsgi.WSGIHandler())
    tornado_app = tornado.web.Application(
        [('/hello-tornado', HelloHandler),
         ('.*', tornado.web.FallbackHandler, dict(fallback=wsgi_app)),
         ])

    server = tornado.httpserver.HTTPServer(tornado_app)
    server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == '__main__':
  main()

现在两者都可以在相同的开发环境下运行。

在Apache2中使用反向代理

由于我甚至不记得端口号,因此提前设置一个反向代理可能是一个不错的主意。(只是,由于需要单独使用supervisord和Apache来管理端口号,所以可能会在以后变得麻烦。)

启用mod_proxy,设置ProxyPass和ProxyPassReverse。省略

    • http://localhost/test1

 

    http://localhost/test2

我们通过进行类似的操作来确认Python和Django的版本是否不同。

请看以下信息

虽然有些微妙,但我已经在终端上尝试运行了。

bannerAds