如何开始从Subversion存储库部署PHP应用程序?

24

我听说过“部署应用程序”这个词组,它听起来比单独修改文件上传到服务器更好/更容易/更可靠,但我不知道该从何开始。

我有一个Zend框架应用程序,它受版本控制(在Subversion存储库中)。我如何“部署”我的应用程序?如果我有一个“上传”目录,我不想覆盖它,应该怎么办?

我通过第三方托管我的应用程序,所以我除了FTP之外不太了解。如果其中任何步骤涉及登录到我的服务器,请解释该过程。


我觉得这是一个有趣的问题。我永远不会实现自动更新,但我想要的是一种类似于检出的实时副本,我可以随时切换...所以,与其有一个工作副本,然后从那里上传到Live服务器,我想在服务器上有一个实时的'工作'副本。那可能就是它应该的样子,但我从未尝试过。 - markus
我记得听说Stack Overflow正在做同样的事情。 - Elijah Glover
1
我最近听了一期关于这个问题的ITC播客,其中提到了http://timothyfitz.wordpress.com/2009/02/10/continuous-deployment-at-imvu-doing-the-impossible-fifty-times-a-day/上的博客文章。我更喜欢每周只进行几次推送,但是因为只有我在开发,所以情况确实如此。 - Alister Bulman
8个回答

21
自动部署和测试到暂存服务器被称为持续集成。这样,如果您提交了破坏测试的内容,您将立即收到通知。对于PHP,您可以考虑使用XincphpUnderControl
然而,您通常不希望自动部署到生产环境。正常做法是编写一些脚本来自动化任务,但仍需要手动启动。您可以使用Phing或其他构建工具(Capistrano是一个流行的选择),也可以组合几个shell脚本。我个人更喜欢后者。
这些脚本本身可以根据您的应用程序和设置执行不同的操作,但典型的过程是:
  • ssh到生产服务器。其余命令在生产服务器上通过ssh运行。
  • 运行svn export svn://path/to/repository/tags/RELEASE_VERSION /usr/local/application/releases/TIMESTAMP
  • 停止服务(Apache,守护进程)
  • 运行unlink /usr/local/application/current && ln -s /usr/local/application/releases/TIMESTAMP /usr/local/application/current
  • 运行ln -s /usr/local/application/var /usr/local/application/releases/TIMESTAMP/var
  • 运行/usr/local/application/current/scripts/migrate.php
  • 启动服务

(假设您的应用程序位于/usr/local/application/current中)


7
我不建议自动更新。仅仅因为你的单元测试通过了并不意味着你的应用程序百分之百可以正常工作。如果有人提交了一个没有任何新单元测试的随机新功能,而这个功能不能正常工作怎么办?你现有的单元测试可能会通过,但是这个功能仍然可能是坏的。你的用户可能会看到一个半成品。通过从check-in自动部署,如果有什么东西上线了却不应该上线,你可能几个小时都不会注意到。
总之,如果你真的想要自动部署,那么实现起来并不难。你需要一个post-check-in hook,而且步骤大致如下:
1)从最新的check-in中导出 2)上传导出文件到生产服务器 3)解压/配置新上传的导出文件
我通常手动执行最后两个步骤。一般来说,只需要SVN导出、打包、上传、解压、配置,最后两个步骤只需要将一些bash命令组合起来即可完成。然后用新的根应用程序目录替换掉旧的目录,确保保留旧的目录作为备份,就可以开始运行了。
如果你有信心能在它们自动上线之前发现错误,那么你可以考虑自动化这个过程。但这让我感到有点不安。

2
我同意您关于自动更新的建议。但是,我会用一些自动化的过程来替换您的手动更新过程。步骤越少,出错的可能性就越小。我们每天进行十几次部署,并尽可能地自动化以减少错误。我可以推荐Webistrano,它可以完成大部分您的步骤,但更加灵活和自动化。如果您的需求更简单,使用rsync的脚本可能会不错。 - Martijn Heemels

4
在我的Web开发公司,我们最近开始使用Webistrano,这是一个基于Web的GUI工具,可用于流行的Capistrano工具。
我们需要一个易于使用、快速的部署工具,带有集中式界面,可以追溯责任(谁部署了哪个版本),可以回滚到以前的版本,并且最好是免费的。Capistrano作为Ruby on Rails应用程序的部署工具而广为人知,但不是集中化的,主要针对Rails应用程序。Webistrano通过GUI增强了它的功能,提供了追溯责任,并添加了基本支持PHP部署(使用“纯文件”项目类型)。
Webistrano本身是一个Ruby on Rails应用程序,您可以将其安装在开发或暂存服务器上。您为每个网站添加一个项目。对于每个项目,您可以添加诸如Prod和Dev之类的阶段。
每个阶段可以有不同的服务器进行部署,并具有不同的设置。编写(或修改)一个“配方”,它是一个告诉capistrano该做什么的ruby脚本。在我们的情况下,我只使用了提供的配方,并添加了一个命令来创建共享上传目录的符号链接,就像您所提到的那样。
当你点击“部署”按钮时,Webistrano会SSH到你的远程服务器上,检出代码,执行其他任务,比如数据库迁移、符号链接或清理之前的版本等。当然,所有这些都可以进行调整,毕竟它只是一个脚本。
我们非常满意它,但我花了几天时间学习和设置,特别是因为我不熟悉Ruby和Rails。尽管如此,我强烈推荐在小型和中型公司中将其用于生产环境,因为它已经被证明非常可靠、灵活,并且节省了我们多倍的初始投资。它不仅加速了部署,还减少了错误/事故的发生。

1
处理上传的经典解决方案是将实际目录移出主网站空间,仅留下一个新版本供检查(如下面的脚本所示),然后使用Apache将其作为网站的一部分“别名”放回原位。
Alias /uploads /home/user/uploads/

如果您对服务器没有足够的控制权,则选择会更少。

我有一个脚本,可以将给定的脚本部署到开发/生产网站(它们都在同一台服务器上运行)。

#!/bin/sh

REV=2410
REVDIR=$REV.20090602-1027

REPOSITORY=svn+ssh://topbit@svn.example.com/var/svn/website.com/trunk
IMAGES=$REVDIR/php/i
STATIC1=$REVDIR/anothersite.co.uk

svn export --revision $REV  $REPOSITORY $REVDIR

mkdir -p $REVDIR/tmp/templates_c
chown -R username: $REVDIR
chmod -R 777       $REVDIR/tmp $REVDIR/php/cache/
chown -R nobody:   $REVDIR/tmp $REVDIR/php/cache/ $IMAGES
dos2unix $REVDIR/bin/*sh  $REVDIR/bin/*php
chmod 755 $REVDIR/bin/*sh $REVDIR/bin/*php

# chmod -x all the non-directories in images
find $IMAGES -type f -perm -a+x | xargs -r chmod --quiet -x
find $STATIC1 -type f -perm -a+x | xargs -r chmod --quiet -x

ls -l $IMAGES/* | grep -- "-x"

rm dev && ln -s $REVDIR dev

我将修订号和日期/时间放在检出目录名称中使用。中间的chmod也确保图像的权限正确,因为它们也链接到我们专用的图像服务器。

最后发生的事情是旧的符号链接.../website/dev/被重新链接到新检出的目录。然后Apache配置具有.../website/dev/htdocs/的文档根目录。

还有一个匹配的.../website/live/htdocs/文档根目录,同样,“live”是另一个符号链接。这是我的另一个脚本,将删除live符号链接,并用dev指向的内容替换它。

#!/bin/sh
# remove live, and copy the dir pointed to by dev, to be the live symlink
rm live && cp -d dev live

我每隔几天只推送一次新版本的网站,所以你可能不想一天使用多次(我的APC缓存不喜欢有几个版本的网站),但对于我来说,我发现这对我的部署非常无问题。


1
这种东西被称为“持续集成”。Atlassian Bamboo(收费)、Sun Hudson(免费)和Cruise Control(免费)都是受欢迎的选项(按我的偏好顺序),并且支持处理PHPUnit输出(因为PHPUnit支持JUnit输出)。
部署工作可以通过后构建触发器完成。像本帖中其他人一样,在提交时进行自动化部署(和测试通过)之前,我会非常谨慎。

1

1

经过三年的学习,我对部署最佳实践有了一些了解。我目前使用一个叫做Capistrano的工具,因为它易于设置和使用,并且可以很好地处理许多默认值。

自动化部署流程的基本步骤如下:

  1. 您的代码已准备好投入生产,因此已标记为发布版本:v1.0.0
  2. 假设您已经配置了部署脚本,您可以运行该脚本,并指定刚创建的标签。
  3. 脚本通过SSH连接到您的生产服务器,该服务器具有以下目录结构:

    /your-application
        /shared/
            /logs
            /uploads
        /releases/
            /20120917120000
            /20120918120000  <-- 您的应用程序的最新版本
                /app
                /config
                /public
                ...etc
        /current --> 符号链接到最新版本
    
    您的Apache文档根目录应设置为/your-application/current/public
    
  4. 脚本在releases目录中创建一个带有当前日期时间的新目录。在该目录中,您的代码将更新为您指定的标签。

  5. 然后删除原始符号链接并创建一个新的符号链接,指向最新版本。

需要在版本之间保留的内容放在共享目录中,并创建符号链接到这些共享目录。


我听说在PHP应用程序部署中使用符号链接的一个反对意见是:当部署发生时,应用程序可能正在require一组类文件。这会导致不兼容的更改被少数用户使用(而且PHP不会知道这一点,因为每个文件的前后状态都在同一路径上)。将重新生成Apache vhost配置文件的脚本指向发布路径,然后进行优雅的reload是否更安全? - halfer

0

这取决于您的应用程序以及测试的可靠程度。

在我工作的地方,所有内容都会被检入存储库进行审核,然后才会发布。

对于我们来说,从存储库自动更新并不明智,因为有时我们只是为了让其他开发人员拉取更新版本并合并其更改而进行检入。

要做到您所说的需要某种形式的二次检入和检出,以允许开发人员在主要检入区域之间进行协作。虽然我不知道那是否可能或者如何实现。

还存在分支等功能的问题需要处理。


你可以设置一个发布标签,以及一个仅部署已标记为稳定的修订版本的提交后钩子。也就是说,无论你进行多少次提交、分支和标记,只有遇到“稳定”关键字时才会部署。 - Martijn Heemels

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接