我听说过“部署应用程序”这个短语,这听起来比将单个更改的文件上传到服务器要好/更容易/更可靠,但我不知道从哪里开始。
我有一个受版本控制的 Zend Framework 应用程序(在 Subversion 存储库中)。如何“部署”我的应用程序?如果我有一个不想覆盖的“上传”目录,我该怎么办?
我通过第三方托管我的应用程序,所以除了 FTP 之外我知道的不多。如果其中任何一项涉及登录我的服务器,请解释该过程。
我听说过“部署应用程序”这个短语,这听起来比将单个更改的文件上传到服务器要好/更容易/更可靠,但我不知道从哪里开始。
我有一个受版本控制的 Zend Framework 应用程序(在 Subversion 存储库中)。如何“部署”我的应用程序?如果我有一个不想覆盖的“上传”目录,我该怎么办?
我通过第三方托管我的应用程序,所以除了 FTP 之外我知道的不多。如果其中任何一项涉及登录我的服务器,请解释该过程。
自动部署 + 运行测试到登台服务器被称为持续集成。这个想法是,如果您签入破坏测试的内容,您会立即收到通知。对于 PHP,您可能需要查看Xinc或phpUnderControl
不过,您通常不希望自动部署到生产环境。正常的做法是编写一些脚本来自动执行任务,但您仍然需要手动启动。您可以为此使用Phing等框架或其他构建工具(一个流行的选择是Capistrano),但您也可以将几个 shell 脚本放在一起。我个人更喜欢后者。
脚本本身可以做不同的事情,具体取决于您的应用程序和设置,但典型的过程是:
svn export svn://path/to/repository/tags/RELEASE_VERSION /usr/local/application/releases/TIMESTAMP
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
)
不建议自动更新。仅仅因为您的单元测试通过并不意味着您的应用程序是 100% 工作的。如果有人在没有任何新单元测试的情况下签入一个随机的新功能,并且该功能不起作用怎么办?您现有的单元测试可能会通过,但无论如何该功能可能会被破坏。您的用户可能会看到完成了一半的事情。通过签入自动部署,您可能在几个小时内都不会注意到是否有一些不应该有的东西让它生效。
无论如何,如果您真的想要,进行自动部署并不难。您需要一个签入后挂钩,实际上步骤是:
1) 从最新签入中导出 2) 将导出上传到生产服务器 3) 解压/配置新上传的导出
我总是手动执行最后一步。通常它就像 SVN 导出、压缩、上传、解压缩、配置一样简单,最后两个步骤我只是将几个 bash 命令别名在一起来执行。然后我将根应用程序目录换成新的,确保我保留旧的作为备份,这很好。
如果您对在错误自动上线之前捕获错误的能力充满信心,那么您可以考虑使该过程自动化。不过,它给了我摇摆不定的感觉。
在我的 webdev 公司,我们最近开始使用Webistrano,它是流行的 Capistrano 工具的 Web GUI。
我们想要一个易于使用、快速部署的工具,具有集中式界面、问责制(谁部署了哪个版本)、回滚到以前的版本,最好是免费的。Capistrano 是众所周知的 Ruby on Rails 应用程序的部署工具,但不是集中式的,主要针对 Rails 应用程序。Webistrano 通过 GUI、问责制对其进行了增强,并添加了对 PHP 部署的基本支持(使用“纯文件”项目类型)。
Webistrano 本身就是一个 Ruby on Rails 应用程序,您可以将其安装在开发或登台服务器上。您为每个网站添加一个项目。向每个项目添加阶段,例如 Prod 和 Dev。
每个阶段可以有不同的服务器来部署,以及不同的设置。编写(或修改)一个“食谱”,这是一个告诉 capistrano 要做什么的 ruby 脚本。在我们的例子中,我只是使用了提供的配方并添加了一个命令来创建指向共享上传目录的符号链接,就像你提到的那样。
当您单击 Deploy 时,Webistrano SSH 进入您的远程服务器,对代码进行 svn 检出,以及您需要的任何其他任务,例如数据库迁移、符号链接或清理以前的版本。当然,所有这些都可以调整,毕竟它只是脚本。
我们对此非常满意,但我花了几天时间来学习和设置,尤其是因为我不熟悉 Ruby 和 Rails。尽管如此,我还是强烈推荐它用于中小型公司的生产用途,因为它被证明非常可靠、灵活,并且为我们节省了很多倍的初始投资。不仅可以加快部署速度,还可以减少错误/事故。
这种事情就是你所说的“持续集成”。Atlassian Bamboo(成本)、Sun Hudson(免费)和 Cruise Control(免费)都是流行的选项(按我的喜好排序)并且支持处理 PHPUnit 输出(因为 PHPUnit 支持 JUnit 输出)。
部署工作可以通过构建后触发器来完成。像这个线程上的其他人一样,在签入(和测试通过)进行自动部署之前,我会非常谨慎。
为了处理上传,经典的解决方案是将实际目录移出主网络空间,只留下一个新版本进行签出(就像我在下面的脚本中所做的那样),然后使用 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/docroot,同样,“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
我只是每隔几个 dts 推送一个新版本的网站,所以你可能不想每天多次使用这个(我的 APC 缓存不会喜欢这个网站的几个版本),但对我来说,我发现这对于我自己的部署来说非常没有问题。
检查 fredistrano,这是一个 capistrano 克隆,效果很好(安装有点混乱,但毕竟运行良好)
3 年后,我对部署最佳实践有了一些了解。我目前使用一个名为 Capistrano 的工具,因为它易于设置和使用,并且可以很好地处理许多默认设置。
自动化部署过程的基础是这样的:
脚本 SSH 连接到具有以下目录结构的生产服务器:
/your-application
/shared/
/logs
/uploads
/releases/
/20120917120000
/20120918120000 <-- latest release of your app
/app
/config
/public
...etc
/current --> symlink to latest release
Your Apache document root should be set to /your-application/current/public
该脚本使用当前日期时间在发布目录中创建一个新目录。在该目录中,您的代码将更新为您指定的标记。
需要在版本之间保留的东西放在共享目录中,并为这些共享目录创建符号链接。
这取决于您的应用程序以及测试的可靠性。
在我工作的地方,所有东西都会被检查到存储库中进行审查,然后发布。
从存储库中自动更新对我们来说并不明智,因为有时我们只是签入以便其他开发人员可以拉出更高版本并合并其中的更改。
要执行您所说的操作,需要某种辅助签入和签出,以允许主要签入区域的开发人员之间进行协作。虽然我对此一无所知,或者它是否可能。
还有需要处理的分支和其他类似功能的问题。