一个简单的Python部署问题 - 一个痛苦的整个世界

时间:2010-04-29 23:55:51

标签: python linux deployment pylons

我们在Linux上运行了几个Python 2.6应用程序。其中一些是Pylons Web应用程序,其他只是我们使用nohup从命令行运行的长时间运行的进程。我们还在开发和生产中使用virtualenv将这些应用程序部署到生产服务器的最佳方法是什么?

在开发中,我们只需将源代码树放入任何目录,设置virtualenv并运行 - 足够简单。我们可以在生产中做同样的事情,也许这是最实用的解决方案,但在生产中运行svn update感觉有点不对劲。我们也试过fab,但它从来没有第一次运作。对于每个应用程序,出现其他问题。令我感到震惊的是整个过程太难了,因为我们想要实现的目标从根本上说非常简单。这是我们对部署过程的期望。

  1. 我们应该能够运行一个简单命令来部署应用程序的更新版本。 (如果初始部署涉及一些额外的复杂性,那很好。)
  2. 当我们运行此命令时,它应该将某些文件从Subversion存储库或本地工作副本复制到服务器上的指定“环境”,这可能意味着不同的virtualenv。我们在同一台服务器上有应用程序的暂存和生产版本,因此它们需要以某种方式保持独立。如果它安装到site-packages中,那也没关系,只要它能正常工作。
  3. 我们在服务器上有一些应该保留的配置文件(即不会被部署过程覆盖或删除)。
  4. 其中一些应用程序从其他应用程序导入模块,因此他们需要能够以某种方式相互引用彼此。这是我们最麻烦的部分!只要它在开发和生产中都可靠地运行,我不关心它是通过相对导入,站点包还是其他方式工作。
  5. 理想情况下,部署过程应自动安装我们的应用程序所依赖的外部包(例如psycopg2)。
  6. 真的是这样!这有多难?

8 个答案:

答案 0 :(得分:23)

setuptools结合virtualenvpip,可以更轻松地开发和部署Python代码。

核心理念

我发现,最棘手的部分是运行一个开发环境,尽可能地反映部署的设置,同时尊重Pythonic工具和习语。但事实证明,使用pip和setuptools可以很容易地实现这一点,它们允许您在不移动文件的情况下将开发树“安装”到Python环境中。 (实际上setuptools会自行完成这一切,但是pip更好地充当前端句柄依赖项。)

另一个关键问题是在两个环境中准备一个包含已知包的干净环境。 Python的virtualenv在这方面是一个神派,允许您使用自己选择的包配置完全自定义的Python环境,无需root访问权限或OS包(rpm或dpkg),并且不受任何包和版本的限制恰好安装在你的发行版上。

最后,一个令人讨厌的bug-bear是难以创建与PYTHON_PATH搭配良好的命令行脚本。 setuptools也非常优雅地处理了这个问题。

设置

(为了简单起见,这是相当规范的。请随意分开。)

  1. 准备一个Python内容可以称之为家的工作目录。
  2. this page的底部抓取最新的virtualenv并解压缩(无论在哪里)。
  3. 从工作目录中,设置一个新的Python虚拟环境:

    $ python <untarred_directory>/virtualenv.py venv
    
  4. 您希望在此虚拟环境中完成大部分工作。使用此命令执行此操作(.source)的快捷方式:

    $ . venv/bin/activate
    
  5. 安装pip:

    $ easy_install pip
    
  6. 为您要创建的每个可安装程序包创建目录。

  7. 在每个目录中,您需要一个setup.py来定义包的内容和结构。 setuptools documentation是一个非常好的资源,可以开始使用它。值得花些时间吸收它的大部分。
  8. 开发

    一旦树状结构准备就绪,您几乎已准备好开始编码。但是现在,依赖于彼此的软件包在部署环境中无法看到彼此。这个问题通过setuptools提供的一个巧妙的小技巧解决,以及哪个pip使用。对于您正在开发的每个包,请运行以下命令(确保您位于项目的虚拟环境中,如上面的步骤3所示):

    $ pip install -e pkg1
    

    此命令会将pkg1安装到您的虚拟环境中,并且不会复制任何文件。它只是添加指向包的开发根目录的site-packages目录的链接,并在该根目录中创建一个egg-info目录。您也可以在没有点的情况下执行此操作,如下所示:

    $ cd pkg1
    $ python setup.py develop
    

    它通常会起作用,但如果您有第三方依赖项(应该在setup.py中列出,如setuptools文档中的here所述),那么pip会更聪明地找到它们。

    需要注意的一点是,setuptools和pip都没有任何关于在你自己的包中找到依赖关系的聪明之处。如果目录B中的PkgB依赖于目录A中的PkgA,则pip install -e B将失败,因为pip无法知道在目录A中可以找到PkgA;它将尝试并失败,从其在线存储库源下载PkgA。解决方法只是在每个包依赖后安装它们。

    此时,您可以启动python,加载其中一个模块并开始使用它。您可以编辑代码,下次导入时它将立即可用。

    最后,如果要使用包创建命令行工具。不要手工写。你最终会得到一堆可怕的PYTHON_PATH黑客,这些黑客从来都不能正常工作。只需阅读setuptools文档中的automatic script creation即可。这样可以免除你的痛苦。

    部署

    当您的软件包准备好执行操作时,您可以使用setup.py来创建部署软件包。这里有太多的选择,但以下内容应该让你开始:

    $ cd pkg1
    $ python setup.py --help
    $ python setup.py --help-commands
    

    结束

    由于问题的广泛性,这个答案必然是不完整的。我没有处理长期运行的服务器,Web框架或实际部署过程本身(特别是使用pip install的--index-url来管理第三方和内部包的私有存储库以及-e vcs+... ,这将从svn,git,hg或bzr中提取包。但我希望我已经给你足够的绳索将它们捆绑在一起(只是不要把它自己挂起来: - )。

答案 1 :(得分:6)

这真的不难。您需要主要使用buildoutsupervisord IMO。

虽然学习构建可能需要一点时间,但它值得,因为在重复设置中它会减少疼痛。

关于nohup: nohup方法不适合严肃的部署。我对supervisord有很好的经验。它是运行生产python应用程序的绝佳解决方案。这很容易设置。

以下一些具体答案。

  1. 要部署的单个命令:Buildout就是答案。我们使用它几年以来没有太多问题
  2. 通常就像你查看来源一样。然后运行buildout。此外,将安装程序复制到站点包中可能不是一个好主意。更好地保持环境分离。
  3. 配置不会被覆盖。
  4. 你可以/应该考虑为普通包装制作鸡蛋。就像你可以为包构建egg(比如commonlib)并将其上传到你的代码库中一样。然后,您可以在buildout.cfg
  5. 中将其指定为依赖项
  6. Buildout能够构建与中央/顶级安装完全分开的大多数基本软件包。但是根据我的经验,如果作为操作系统包安装了带有c扩展名的python包,那就容易多了。

答案 2 :(得分:5)

我一直致力于为我们的工作项目实施这项工作。这涉及到一些不同的部分。

首先,我们使用他们的引导功能自定义virtualenv.py,以添加您自己的自定义创建后功能和标志。这些允许我们定义常见的项目类型,并为我们提供一个命令来创建一个新的virtualenv,从git存储库检出项目,并使用pip和requirements.txt将任何需求安装到virtualenv中。 文件。

所以我们的命令如下: python venv.py --no-site-packages -g $ git_proj -t $ tag_num $ venv_dir

http://pypi.python.org/pypi/virtualenv http://pip.openplans.org/

现在让我们完成对现有项目的初步检查。在我们工作和更新项目时,我们在每个项目中使用fabric命令来构建版本,然后部署它们:

http://docs.fabfile.org/0.9.0/

我有一个fab命令:make_tag检查未使用的提交,打开需要更新版本字符串的文件,构建和上传sphinx文档,然后将最终标记提交到存储库。

另一方面是fab deploy命令,它将通过ssh执行指定标记的git co,对任何新需求运行pip更新,运行所需的任何数据库迁移,然后重置Web服务器(如果这是一个Web应用程序。

以下是标记功能的示例: http://www.google.com/codesearch/p?hl=en#9tLIXCbI4vU/fabfile.py&q=fabfile.py%20git%20tag_new_version&sa=N&cd=1&ct=rc&l=143

您可以使用Google代码搜索浏览大量优质的结构文件。我知道我为自己的使用而欺骗了一些。

这绝对是复杂的,有几个部分,以使事情顺利进行。一旦你开始运行,事情的灵活性和速度就会很棒。

答案 3 :(得分:2)

请查看Buildout以获得可重现的部署。

答案 4 :(得分:0)

另一项面料投票(尚未尝试过Buildout)。我们已成功使用它几个月了。

如果您遇到布料问题,另一个选项是Capistrano。效果很好(即使对于非rails应用程序)。只停止使用它因为使用Ruby来部署Python应用程序感觉很奇怪;)

答案 5 :(得分:0)

我会使用rsync从您的生产“主要”服务器向外同步,从您的“beta测试”平台向您的生产“主要”服务器同步。

rsync的好处是只复制那些已更改的文件,并仅复制部分更改的文件,并在所有计算机上验证最终的完整性和相同内容。可以在以后轻松地继续进行部分通过和中断的更新,从而使您的部署更加强大。

Subversion或Mercurial在这种情况下也不是一个坏主意。 Mercurial有 允许您“拉”或“推”而不是仅从一个中央源更新的优点。您可能会发现一些有趣的案例,其中分散模型(mercurial)效果更好。

答案 6 :(得分:0)

如果你是一个扩建人,那么你应该知道minitage.recipe.scripts能够生成一个文件来设置你的python环境。来自您的Web服务器的源和您的buildout是完全可移植的。

答案 7 :(得分:0)

听起来你想要的是构建脚本。所以写一个,使用shell,python,ant或你最喜欢的构建工具。如果您不喜欢用XML编写,pant允许您在python中编写ant脚本。有几个人提到了buildout,但我对此没有任何经验。

首先定义您的步骤。听起来你想:

  1. 从您的生产代码中导出SVN(您不希望在prod中有工作副本)
  2. set virtualenv
  3. easy_install或pip安装所需的软件包(或者可能使用预先下载和测试的版本)
  4. 将生产配置文件复制到您的目标(将此信息保存在源代码库中并不是一个好主意 - 尽管您可以将它们单独版本化)
  5. 重新启动您的服务器&amp;做任何其他设置任务
  6. 运行冒烟测试并在失败时回滚
  7. 如果您正在进行负载平衡或依赖于其他服务生产,您可能想要找出一种方法来推出有限的范围,这样您的所有客户都不会立即受到影响。如果你有一个类似生产的登台环境,也可能满足这种需求。