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

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

在开发中,我们只需将源代码树放入任何目录,build立一个virtualenv并运行 – 很简单。 我们可以在生产中做同样的事情,也许这是最实际的解决scheme,但是在生产环境中运行svn update只是感觉有点不对。 我们也尝试了fab ,但它从来没有第一次工作。 对于每个应用程序,其他事情都会出错 我觉得整个过程太困难了 ,因为我们要实现的目标基本上是非常简单的。 这是我们从部署过程中需要的。

  1. 我们应该可以运行一个简单的命令来部署应用程序的更新版本。 (如果最初的部署涉及到一点额外的复杂性,那也可以。)
  2. 当我们运行这个命令的时候,它应该把某些文件拷贝到Subversion版本库或者从本地工作拷贝到服务器上指定的“环境”,这可能意味着一个不同的virtualenv。 我们在同一台服务器上同时安装了应用程序和生产版本,因此需要将它们分开。 如果它安装到站点包中,那也可以,只要它可以工作。
  3. 我们在服务器上有一些configuration文件应该被保留(即不被覆盖或被部署过程删除)。
  4. 其中一些应用程序从其他应用程序导入模块 ,因此它们需要能够以某种方式将对方引用。 这是我们遇到的最麻烦的部分! 我不关心它是否通过相关import,网站包或其他方式工作,只要它在开发和生产中都可靠地工作。
  5. 理想情况下,部署过程应该自动安装我们应用程序所依赖的外部包(例如psycopg2)。

那真是它! 它能有多难?

Solutions Collecting From Web of "一个简单的Python部署问题 – 一个痛苦的世界"

通过将setuptools与virtualenv和pip相结合,开发和部署Python代码变得更容易。

核心思想

我发现最棘手的部分是运行一个开发环境,尽可能地反映已部署的设置,同时尊重Pythonic工具和习惯用法。 但事实证明,使用pip和setuptools可以非常容易地实现这些功能,这些功能一起允许您将开发树“安装”到Python环境中,而无需移动文件。 (其实setuptools本身就是这样做的,但是pip更好地作为前端处理依赖关系。)

另一个关键问题是准备一个干净的环境,在两个环境中都有一个已知的包。 Python的virtualenv在这方面是上帝之赐,允许您使用您自己的软件包选项来配置一个完全自定义的Python环境,而无需root访问权限或操作系统软件包(rpm或dpkg),而不受任何软件包和版本的限制正好安装在你的发行版上。

最后,一个令人烦恼的错误是创建与PYTHON_PATH相配的命令行脚本的困难。 这也是由setuptools相当优雅的处理。

配置

(为了简单起见,这是相当规范的,可以酌情分歧。)

  1. 准备一个Python工具可以调用的工作目录。
  2. 从这个页面的底部抓取最新的virtualenv并解压缩(无所谓)。
  3. 从工作目录中,建立一个新的Python虚拟环境:

     $ python <untarred_directory>/virtualenv.py venv 
  4. 你会想在这个虚拟环境中完成大部分的工作。 使用此命令( .source的快捷方式):

     $ . venv/bin/activate 
  5. 安装点子:

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

  7. 在每个目录中,您需要一个setup.py来定义包的内容和结构。 setuptools 文档是开始进行这项工作的非常好的资源。 这是值得花时间吸收大块的。

发展

一旦你的树结构准备好了,你几乎可以开始编码了。 但现在,相互依赖的软件包不能像在部署环境中那样彼此看到。 这个问题可以通过setuptools提供的一个简单的小技巧来解决,哪个pip可以使用。 对于您正在开发的每个软件包,运行以下命令(确保您处于项目的虚拟环境中,如上面的步骤3所示):

 $ pip install -e pkg1 

这个命令会把pkg1安装到你的虚拟环境中,而且不需要复制你的任何文件。 它只是添加一个指向包的发展根目录的site-packages目录的链接,并在该根目录下创建一个egg-info目录。 你也可以做到这一点没有点子,如下所示:

 $ cd pkg1 $ python setup.py develop 

它通常会工作,但是如果你有第三方的依赖关系(这应该在setup.py中列出,正如在setuptools文档中所解释的那样),pip更聪明地找到它们。

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

在这一点上,你可以启动python,加载你的一个模块,并开始玩弄它。 您可以编辑代码,下次导入代码时将立即可用。

最后,如果你想用你的包创建命令行工具。 不要用手书写。 你最终会得到一堆可怕的PYTHON_PATH黑客。 只需阅读setuptools文档中的自动脚本创建即可。 这会让你很伤心

部署

当您的软件包准备就绪后,您可以使用setup.py创建部署软件包。 进入这里的方式太多了,但是下面的内容会让你开始:

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

松散结束

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

这真的不难。 你需要主要与建立和supervisord国际海事组织。

虽然学习增强可能需要一点时间,但它是值得的,因为反复的设置减少了痛苦的数量。

关于nohup: nohup方法不适合严重的部署。 我有supervisord很好的经验。 这是运行生产Python应用程序的绝佳解决方案。 这是很容易安装。

一些具体的答案如下。

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

我一直在为我们的工作项目而努力。 这涉及到几个不同的部分。

首先,我们使用他们的引导能力自定义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/

现在,让我们通过初始检查现有项目。 在我们工作和更新项目时,我们在每个项目中使用结构命令来构建版本,然后部署它们:

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

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

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

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

有很多好的结构文件,你可以使用谷歌代码搜索浏览。 我知道我欺骗了一些我自己的用途。

这绝对是复杂的,有几个部分为了让事情顺利进行。 一旦你得到它运行,灵活性和速度的东西只是真棒。

看看构建重现性的部署。

另一个投票面料(还没有尝试过建设呢)。 我们已经成功使用了几个月了。

如果您在面料方面遇到麻烦,另一个选择是Capistrano 。 很好(甚至对于非Rails应用程序)。 只是停止使用它,因为使用Ruby部署Python应用程序感觉很奇怪;)

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

rsync的优点是只复制那些被改变的文件,只复制部分改变的文件的一部分,并且在所有机器上最后验证完整性和相同的内容。 稍后可以轻松地继续部分更新并中断,从而使您的部署更加健壮。

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

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

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

首先定义你的步骤。 这听起来像你想要:

  1. 从您的生产标签SVN出口(你不想有一个工作副本prod)
  2. 设置virtualenv
  3. easy_install或pip安装所需的软件包(或者可能使用预先下载和测试版本)
  4. 复制生产配置文件到你的目标(这是不是一个好主意,保持这个信息在你的源回购 – 虽然你可以让他们分别版本)
  5. 重新启动服务器并执行其他任何设置任务
  6. 运行冒烟测试和失败回滚

如果您正在进行负载平衡或取决于其他服务生产,则可能需要找出一种方法来展开有限的范围,以便您的所有客户不会一次受到影响。 如果您有一个类似产品的临时环境,也可以满足这种需求。