There was a time when PHP developers had to use deployment tools for general web applications. You can see this, for example, in Johannes Schickling's tutorial on deploying a Laravel application using Capistrano. It's a Ruby tool and you need to write Ruby code. These tools get the job done, but have limited integration with PHP applications. This can lead to poor solutions for some scenarios.
But nowadays, we are lucky to have some deployment tools written in our language that allow for deeper integration. Rocketeer is one such tool, inspired by the Capistrano and Laravel frameworks.
Rocketeer is a modern tool that provides an excellent approach to your deployment needs. That is, run tasks and manage applications across different environments and servers. On top of that, it also has some magic, like installing Composer dependencies if acomposer.json
file is detected. For modern PHP applications, you get sane defaults and automation of common tasks. And you can customize and extend everything.
You can describe it as an SSH task runner that runs on the client. These commands are executed on the server over an SSH connection. Unfortunately, if you use a shared hosting provider that only has FTP access, you're out of luck. You'll also need a remote repository from which the tool can fetch your code. Git and SVN are supported by default. Need support from another version control system? Write your own implementation using the provided interface.
You can install Rocketeer in two different ways. You can download the phar file and make it executable, or install it through Composer. I am a supporter of the latter. Having it as a dependency can be easily installed when cloning the repository. This can benefit anyone who clones the repository to get it up and running.
Install using Composer:
$ composer require anahkiasen/rocketeer --dev
I don't recommend you install it globally. Keeping it at the repository level will ensure that every deployer is running the same version. I recommend addingvendor/bin
to your PATH. You can then use the binary by enteringrocketeer
in the project root directory.
let's start! Start by booting directories and files for configuration. You can do this by runningrocketeer ignite
in the project root directory.
When your application starts, the tool creates a.rocketeer
folder in your project. The contents of the directory will look like this:
| .rocketeer | -- config.php | -- hooks.php | -- paths.php | -- remote.php | -- scm.php | -- stages.php | -- strategies.php
These are all the configuration files you need to start setting up your deployment. Whenever I reference the configuration file from here on, it exists in the.rocketeer/
directory.
It's important to understand how Rocketeer manages its folder structure on the server side, as it's a bit different than a regular setup. It uses some directories to manage certain aspects of the deployment so it can do its job efficiently. You specify the path where you want to deploy the application on the server and the tool will handle the rest. If you had/var/www/app
as your application directory, the folder would look like this.
| /var/www/app | | -- current => /var/www/app/releases/20160103183754 | | -- releases | | | -- 20160101161243 | | | |-- uploads => /var/www/app/shared/uploads | | | -- 20160103183754 | | | |-- uploads => /var/www/app/shared/uploads | | -- shared | | | -- uploads
The most important folder iscurrent
, which points to your latest version. This is where your web server's document root should be set. So what happens when deploying?
releases
directory.current
to the new version.This process makes your deployment transparent to users. Switching between versions is almost instantaneous and is often called atomic deployment.
Some data should persist between your deployments. For example, this could be file uploads, user sessions, and logs. These files or folders go into theshared
directory. The tool creates symbolic links in each version for the version you configure.
Event-driven tools, all policies and tasks will be triggeredbefore eventsandafterat runtime. They also provide specialpauseevents when tasks fail. For example, for a general failure this might bedependency.halt
ordeploy.halt
. This allows us to hook processes where needed.
The default events that occur during deployment are:
deploy.before
:在任何事情发生之前。create-release.before
:在创建新的发布目录之前。create-release.after
:创建新的发布目录后。dependency.before
:在安装或更新依赖项之前。dependency.after
:安装或更新依赖项后。也许请确保供应商文件夹中的二进制文件是可执行的。test.before
:运行测试之前。test.after
:运行测试后。migrate.before
:运行数据库迁移之前。也许您想备份数据库?migrate.after
:运行数据库迁移后。deploy.before-symlink
:在将版本符号链接为当前版本之前。deploy.after
:已完成。您可以通知人们一切顺利或其他情况。我们还可以创建自己的事件,我们可以触发和监听这些事件。目前,我们将坚持为我们提供的这些事件。现在它们对我们来说就足够了。
在 Rocketeer 的核心,我们发现了一个名为“任务”的概念。幕后发生的大部分事情都是核心任务。任务的定义可以是作为部署中的步骤执行的一组指令。如果我们查看该工具提供的一些类,我们可以大致了解什么是任务:诸如Deploy
、Setup
、迁移
、class="inline">回滚和class="inline">依赖项。当您部署时,部署命令本身就是一个带有子任务的任务。
在这里,您将开始了解该工具与 PHP 的集成程度,因为您将用该语言编写任务。您可以通过三种不同的方式创建自己的任务:
任意终端命令。这些是您想要在服务器上运行的单行代码。对于很多事情都很有用,例如运行gulp build ---development
。
关闭。如果您需要更多的灵活性或复杂性,您可以将任务编写为闭包(匿名函数)。假设您想在部署期间为 API 生成文档。
function($task) { return $task->runForCurrentRelease('apigen generate source src destination api'); }
课程。对于更复杂的任务,您应该利用该选项为任务创建类。您创建一个类并扩展Rocketeer\Abstracts\AbstractTask
。然后,您必须至少提供说明和execute()
方法。这是一个完全无用的示例,只是为了显示任务类的结构:
namespace MyDeployableApp\Deploy\Tasks; class HelloWorld extends \Rocketeer\Abstracts\AbstractTask { /** * Description of the Task * * @var string */ protected $description = 'Says hello to the world'; /** * Executes the Task * * @return void */ public function execute() { $this->explainer->line('Hello world!'); return true; } }
请注意,您必须自己注册任务类。您可以通过hooks.php
文件执行此操作,并将其添加到custom
数组...
'custom' => array('MyDeployableApp\Deploy\Tasks\HelloWorld',),
...或者您可以通过外观来做到这一点:
Rocketeer::add('MyDeployableApp\Deploy\Tasks\HelloWorld');
注册后,就可以执行它:
$ rocketeer hello:world staging/0 | HelloWorld (Says hello to the world) staging/0 |=> Hello world! Execution time: 0.004s
我们首先讨论事件,因为我们将任务挂接到流程中需要它们的地方。您可以通过几种方式来做到这一点。选择您喜欢且满足您的复杂程度要求的一个。
定义任务的最简单方法是在hooks.php
文件中。它为此提供了两个数组,指定在某些事件之前或之后执行任务。
'before' => [ 'setup' => [], 'deploy' => ['hello:world'], 'cleanup' => [], ],
您可能已经知道所提供的任务非常通用。以依赖项
为例。我们谈论的是哪种依赖关系以及哪个包管理器?
这就是策略发挥作用的地方。策略是任务的具体实现,例如使用 Behat 运行测试或使用 Gulp 构建前端。任务有一个默认策略,可以选择通过 CLI 运行其他策略。我们可以这样列出可用的策略:
$ rocketeer strategies +--------------+----------------+-----------------------------------------------------------------------+ | Strategy | Implementation | Description | +--------------+----------------+-----------------------------------------------------------------------+ | check | Php | Checks if the server is ready to receive a PHP application | | check | Ruby | Checks if the server is ready to receive a Ruby application | | check | Node | Checks if the server is ready to receive a Node application | | deploy | Clone | Clones a fresh instance of the repository by SCM | | deploy | Copy | Copies the previously cloned instance of the repository and update it | | deploy | Sync | Uses rsync to create or update a release from the local files | | test | Phpunit | Run the tests with PHPUnit | | migrate | Artisan | Migrates your database with Laravel's Artisan CLI | | dependencies | Composer | Installs dependencies with Composer | | dependencies | Bundler | Installs dependencies with Bundler | | dependencies | Npm | Installs dependencies with NPM | | dependencies | Bower | Installs dependencies with Bower | | dependencies | Polyglot | Runs all of the above package managers if necessary | +--------------+----------------+-----------------------------------------------------------------------+
假设您正在为您的应用程序使用 BDD With Behat,而不是 TDD。然后您想使用 Behat 而不是 PHPUnit 来运行测试。由于它是一个测试运行程序,因此已经有一个策略命名空间,但没有实现。创建目录.rocketeer/strategies/
并将新的BehatStrategy.php
放入其中。
namespace MyDeployableApp\Deploy\Strategies; use Rocketeer\Abstracts\Strategies\AbstractStrategy;use Rocketeer\Interfaces\Strategies\TestStrategyInterface; class BehatStrategy extends AbstractStrategy implements TestStrategyInterface { public function test() { return $this->binary('vendor/bin/behat')->runForCurrentRelease(); } }
您现在可以将测试策略切换到strategies.php
中的新实现。
'test' => 'Behat',
您是否拥有或已经考虑过基础设施并不重要。如果您的应用程序部署到许多服务器上的许多环境中,这并不重要。火箭人将随时为您服务。您甚至可以在同一服务器上拥有许多不同的位置。这就是术语“连接”和“阶段”的用武之地。
连接是您部署应用程序的服务器。这通常称为环境,生产和登台就是这样的例子。在该工具中配置这些连接是轻而易举的事。您可以通过嵌套数组或为每个连接保留单独的文件来完成此操作。每个连接中还可以有多个服务器。
阶段就像连接中的连接,一种“连接感知”。您可以使用阶段在单个服务器上设置暂存和生产环境。因此,您将拥有一个包含两个阶段的连接,而不是两个单独的连接。
一个很棒的功能是我们可以使用插件扩展我们的流程。有一些官方的可以与 Laravel、Slack、HipChat 和 Campfire 集成。 Packagist 上也有一些,但不是很多。通过 CLI 安装插件是一项简单的任务:
$ rocketeer plugin:install rocketeers/rocketeer-slack
尽管插件数量有限,但为将来开发插件留下了空间。它讲述了一个很好的哲学。为什么不开发自己的一款呢?
为了让您的应用程序启动,您需要一些基本配置。您需要告诉 Rocketeer 在哪里可以找到您的应用程序以及应该将其部署到哪里。首先,我们在config.
中设置应用程序名称并配置生产服务器。
'application_name' => 'my-deployable-app', // [...] 'connections' => [ 'staging' => [ 'host' => 'staging.my-deployable-app.com', 'username' => '', 'password' => '', 'key' => '/Users/niklas/.ssh/id_rsa', 'keyphrase' => '', 'agent' => '', 'db_role' => true, ], 'production' => [ 'host' => 'www.my-deployable-app.com', 'username' => '', 'password' => '', 'key' => '/Users/niklas/.ssh/id_rsa', 'keyphrase' => '', 'agent' => '', 'db_role' => true, ], ],
您现在拥有应用程序名称和用于部署应用程序的服务器。此设置使用 SSH 密钥身份验证,但您也可以使用用户名和密码进行连接。要提示输入用户名和密码,请设置'key' => ''
。该工具会将凭据存储在您的本地计算机上,并在以后每次使用它们。我不建议在配置文件中设置用户名和密码,因为您永远不希望将凭据提交到您的存储库。
您现在应该做的是更改部署到的默认连接。将默认设置设置为生产并不理想。您不想意外地部署到生产中。因此,在同一文件中,查找default
键并将值更改为staging
。
'default' => ['staging'],
应用程序名称本身并不那么重要。但如果您没有指定要部署到的文件夹,它将使用它作为根目录中的文件夹名称。默认情况下,根目录设置为/home/www
。使用此应用程序名称,它将部署到/home/www/my-deployable-app
。如果您想更改根目录,可以在remote.
中进行更改。
// Deploys to /var/www/my-deployable-app/ 'root_directory' => '/var/www/',
在同一文件中,您可以覆盖应用程序名称并为应用程序指定目录。
// Deploys to /var/www/tutsplus-tutorial 'app_directory' => 'tutsplus-tutorial',
现在您已经有了部署的接收端,但您还需要设置代码的位置,以便可以提取它。您可以通过在scm.php
中设置远程存储库来执行此操作。默认情况下它使用 Git,但它也支持 SVN。您告诉它我们的存储库的地址,并在需要时提供凭据。我建议您在这里也使用 SSH 密钥身份验证,并将用户名和密码留空。
'repository' => 'git@github.com:owner/name.git', 'username' => '', 'password' => '', 'branch' => 'master',
由于您添加了到生产服务器的连接,因此您想要部署 master 分支。
在大多数情况下,您不希望所有连接或阶段都使用相同的配置选项。例如,您想要将另一个分支部署到临时环境。 Rocketeer 允许您使用config.php
覆盖连接和阶段的配置值。要在暂存连接上部署名为“暂存”的分支,请执行以下操作:
'on' => [ 'connections' => [ 'staging' => [ 'scm' => [ 'branch' => 'staging', ] ] ], ],
它使用嵌套数组来覆盖配置值。在staging
键下,找到要更改的文件中的相应键。在本例中,它是branch
,位于scm.php
。
现在您已完成成功部署所需的一切设置。您尚未满足完整部署的要求,但足以将应用程序克隆到服务器并提供给最终用户。首先,您可以执行检查策略来查看您的服务器是否满足要求。
$ rocketeer check
如果一切正常,您可以通过运行进行部署:
$ rocketeer deploy
由于这是您的第一次部署,Rocketeer 将确保一切都达到标准。该工具创建它所需的目录以及我们的应用程序将驻留在其中的目录。如果一切顺利,您应该在服务器上拥有完整的应用程序构建。
如果您在上一节中将默认连接更改为暂存,则它将始终部署到暂存。当然,除非您告诉它部署到其他地方。当您想要在不同的连接或多个连接上进行部署时,可以使用--on
开关。
# Deploy to production $ rocketeer deploy --on="production" # Deploy to staging and production $ rocketeer deploy --on="staging,production"
想看看按下按钮后您的服务器上会发生什么吗?使用--pretend
标志让该工具告诉您它将在服务器上执行什么。
$ rocketeer deploy --pretend
不幸的是,我们需要处理会破坏功能或对基础设施造成严重破坏的部署。然后您需要快速回滚到最新版本。幸运的是,这是一个简单的操作 - 只需运行命令:
$ rocketeer rollback
由于它存储了许多构建,因此执行回滚速度很快。它将current
的符号链接更改为以前的版本。
设置共享目录很简单 - 只需将它们添加到shared
数组(位于remote.php
中)。 Rocketeer 将在之后的部署中为您创建并链接这些文件夹。指定的路径应该相对于您的根文件夹。
'shared' => [ 'storage/logs', 'storage/sessions', 'storage/uploads', '.env', ],
大多数共享目录还需要 Web 服务器能够写入它们。写入日志、会话或文件上传通常是任何应用程序执行的任务。您可以将这些内容添加到remote.php
中的permissions.files
数组中。
'permissions' => [ 'files' => [ 'storage/sessions', 'storage/logs', 'storage/uploads', ], // [...] ],
如果应用程序依赖于任何类型的依赖项,则需要安装或更新依赖项。该工具支持最流行的包管理器。如果您有默认设置,则无需进行任何配置。它将检测并安装或更新 Composer、Npm、Bower 和 Bundler 的依赖项。依赖项
的默认策略设置为Polyglot
。这是该工具检测和安装不同包管理器依赖项的方法。
但是,假设您想要在 staging 上安装所有依赖项,并且该工具默认使用--no-dev
标志。也许您想安装 PHPUnit 来运行测试,这是一个开发依赖项。在strategies.php
中,您可以找到composer
键,它告诉工具如何执行 Composer。然后,您可以在config.php
中覆盖此设置:
use Rocketeer\Binaries\PackageManagers\Composer; // [...] 'on' => [ // [...] 'connections' => [ 'staging' => [ 'strategies' => [ 'composer' => [ 'install' => function (Composer $composer, $task) { return $composer->install([], ['--no-interaction' => null, '--prefer-dist' => null]); } ], ], ] ], ],
当您拥有完整的版本时,在符号链接到当前版本之前,迁移数据库通常是您想要做的事情。无论您使用什么工具,您都可以让它在deploy.before-symlink
之前运行。这个钩子不是普通的钩子,而是一个内部钩子。然后,您需要在hooks.php
以外的其他地方注册它。您可以在events.php
中执行此操作,如果该文件尚不存在,则可以创建该文件。
use Rocketeer\Facades\Rocketeer; // Laravel Rocketeer::addTaskListeners('deploy', 'before-symlink', function ($task) { $task->runForCurrentRelease('php artisan migrate'); }); // Symfony2 Rocketeer::addTaskListeners('deploy', 'before-symlink', function ($task) { $task->runForCurrentRelease('php app/console doctrine:migrations:migrate'); }); // Stand-alone Doctrine Rocketeer::addTaskListeners('deploy', 'before-symlink', function ($task) { $task->runForCurrentRelease('doctrine migrations:migrate --no-interaction'); });
在部署过程中运行测试是确保不会出现损坏的代码或测试的好方法。默认情况下,该工具使用 PHPUnit,您可以在安装或更新依赖项后挂钩测试运行器来运行。
'after' => [ 'setup' => [], 'deploy' => [], 'dependencies' => ['test'], 'cleanup' => [], ],
我们现在应该看到它在每个部署上执行 PHPUnit,并且如果测试失败,它将中止。确保您看到它的输出,否则在查找 PHPUnit 二进制文件或测试套件时可能会出现问题。
staging/0 |---- Test (Run the tests on the server and displays the output) fired by dependencies.after staging/0 |------ Test/Phpunit (Run the tests with PHPUnit) $ cd /var/www/my-deployable-app/releases/20160129220251$ /var/www/my-deployable-app/releases/20160129220251/vendor/bin/phpunit --stop-on-failure [deploy@staging.mydeployableapp.com] (staging) PHPUnit 4.8.21 by Sebastian Bergmann and contributors. [deploy@staging.mydeployableapp.com] (staging) [deploy@staging.mydeployableapp.com] (staging) . [deploy@staging.mydeployableapp.com] (staging) Time: 4.79 seconds, Memory: 6.00Mb [deploy@staging.mydeployableapp.com] (staging) OK (1 test, 1 assertion) [deploy@staging.mydeployableapp.com] (staging)staging/0 |=====> Tests passed successfully
通常我们的应用程序不仅仅是后端,除非它们是 REST API。使用 Grunt、Gulp 或 Webpack 等工具运行前端构建工具是一项常见任务。使这成为我们部署过程的一部分没有什么比使用钩子来运行以下命令更奇特的了:
'after' => [ 'setup' => [], 'deploy' => [], 'dependencies' => ['gulp build'], 'cleanup' => [], ],
前端通常也依赖于依赖项,因此在安装或更新工具后运行工具。
如果您不想在部署时创建新版本,则可以选择运行更新。执行此操作时请务必小心,因为您将无法回滚到以前的版本,只能回滚到以前的版本。但这是一种使用最新更改更新应用程序的快速而简单的方法:
$ rocketeer update
有时,在本地环境中运行任务可能会很好。假设您想要运行 PHPCS 检查或构建静态资产并将它们上传到服务器,从而消除服务器上某些二进制文件的需要。如果您创建任务类,则可以将受保护变量$local
设置为true
。
class MyTask extends Rocketeer\Abstracts\AbstractTask { protected $local = true; // [...] }
部署过程是应用程序生命周期的重要组成部分。像 Rocketeer 这样的工具可以让您轻松地使这成为一件简单的事情。当将它用于 PHP 应用程序时尤其如此,因为它与 PHP 应用程序集成得非常好。
对于那些刚刚开始使用 PHP 或希望通过扩展来扩展您的知识、站点或应用程序的人,我们在 Envato Market 中提供了您可以学习的各种内容。
Writing an introductory tutorial for Rocketeer is a daunting task. The tool is so flexible that drawing a stop is not easy. I hope I understood the possibilities of using this tool and how it can benefit you and your application. If you want to learn more, I recommend reading the full documentation. There is much more to this tool than what I can cover in this article.
The above is the detailed content of Rocketeer: The ultimate tool for deploying PHP applications. For more information, please follow other related articles on the PHP Chinese website!