This post was originally posted on David Alger’s blog.
Overview
This article will cover how to use the capistrano-magento2 Capistrano Gem (created by our very own David Alger) to deploy Magento 2 to stage and/or production servers.
Capistrano is a tool used to run scripts on multiple servers, typically with the purpose of deploying code changes to those servers. Capistrano works well with both single node deployments as well as multiple node deployments that include separate application and database servers sitting behind a load balancer. When you use Capistrano, you get a lot of functionality “for free” and you only need to implement scripts to handle your application-specific deployment steps.
The Magento community has been using Capistrano to deploy Magento 1 for many years. There are a couple of Capistrano Gems for Magento 1 (capistrano-magento by Peter Rhoades and Magentify by Alistair Stead). However, since Magento 1 was fairly simple to deploy (compared to Magento 2), many merchants and agencies didn’t use a deployment tool like Capistrano. However, Magento 2’s deployment requirements are greater and it is necessary to have some sort of scripted process to deploy Magento 2 updates. Rather than building your own deployment scripts from scratch, it makes sense to use an open source community tool that is time-tested and used by many developers.
A Capistrano deployment can be initiated from any machine with Capistrano installed and the proper configuration files in place. When Capistrano deploys changes, it connects via SSH to the configured server(s) and runs the necessary commands to deploy a new revision of the project. The typical workflow is to run the deploy command from your local development machine. Deployment configuration files are typically committed to the Magento repository. That way, any developer working on the project can deploy changes to a configured environment assuming they have the appropriate SSH access.
Prepare your Magento 2 project/repo
This article assumes the following:
- You’ve chosen the “Composer metapackage” method of installing Magento.
- You have a copy of Magento 2 that you’ve installed locally (or on a non-Capistrano enabled stage server) and you’d like to deploy it to the stage and/or production environments using Capistrano.
- You have a Git repo that contains
composer.lock
andcomposer.json
files that were created when you installed Magento usingcomposer create-project
. Your.gitignore
should look something like this: magento2-community-edition/blob/master/.gitignore See the first few paragraphs of Alan Kent’s blog post for more details regarding this project setup approach. - You have a Magento 2 database dump that you’re able to import into the server(s) on which you’re going to deploy to using Capistrano. capistrano-magento2 does not support deploying a Magento 2 application from an uninstalled state and assumes a working database and the app/etc/env.php and app/etc/config.php files exist on the target environment (more on this later).
Installation
To install Capistrano, run this command:
$ gem install capistrano
See this page if you run into issues: http://capistranorb.com/documentation/getting-started/installation/
To install capistrano-magento2, run this command:
$ gem install capistrano-magento2
Install Capistrano in your Magento 2 project
Follow steps 1-3 in this section of the
capistrano-magento2 readme. Once you follow these steps, the tools
directory in your Magento 2 project should look like this:
. └── tools └── cap ├── Capfile ├── config │ ├── deploy │ │ ├── production.rb │ │ └── staging.rb │ └── deploy.rb └── lib └── capistrano └── tasks
I recommend committing these files to your Magento 2 Git repo.
Prepare your application server(s)
Before you deploy, you need to prepare your stage and/or production environments. For the purpose of this article, let’s assume that you are going to deploy Magento 2 to two environments:
- www.example.com
- stage.example.com
Classy Llama uses Capistrano to deploy to both production and stage environments. While we could get away with deploying to stage manually (especially if stage is running in developer mode, which I don’t recommend), using the same deployment process in both environments ensures that your stage environment is an accurate reflection of production.
For the rest of this article, we’re going to talk about deploying to the stage.example.com environment, but the steps will be identical to the production environment. Here is an example of the commands that you would need to run to prepare the stage.example.com environment:
$ ssh [email protected] $ cd /var/www/html $ mkdir -p shared/app/etc $ touch shared/app/etc/env.php
The capistrano-magento2 gem deploys files using the ownership of the SSH user that is used to connect to the server. In order to avoid permissions issues, you should ensure PHP and your web server is running as that user. While it is considered best practice to run your stage and production sites on separate servers, Capistrano doesn’t care about this can be easily configured to deploy stage/production to the same server by changing the config values in the tools/cap/config/deploy/*.rb
files.
Edit the shared/app/etc/env.php
file and add the necessary settings (DB credentials, etc) and ensure a proper app/etc/config.php file is committed to your repository (this file is created when bin/magento setup:install
is run). Now import the Magento database and update the necessary values in the core_config_data
table to reflect the new URL.
Configure your web server to use /var/www/html/current/pub
as the document root. If your web server is running Apache, make sure you have mod_realdoc installed and configured to avoid issues with symlinked deployments and the Zend Opcache. If your web server is running Nginx, make sure your FastCGI proxy configuration is using the $realpath_root
variable instead of $document_root
for both SCRIPT_FILENAME and DOCUMENT_ROOT params sent to PHP-FPM.
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; fastcgi_param DOCUMENT_ROOT $realpath_root;
First deployment to stage
Now you can deploy Capistrano to your server. On your development machine, run this command in the tools/cap
directory:
$ cap staging deploy
When you run that command, Capistrano will verbosely report on its progress. Here is a summary of what Capistrano does in this process:
- Creates a new
/var/www/html/releases/<TIMESTAMP>
directory for the new release - Checks outs the latest copy of the develop branch (the
:branch
value specified instaging.rb
) - Symlinks the
:linked_files
and:linked_dirs
into the new release folder - Runs
composer install
in the release directory. This will download and install the dozens of dependencies declared incomposer.lock
. Composer caches packages, so subsequent deployments should be faster than your initial deployment. - Changes directory/file permissions in the new release folder to 770/660, respectively (these may be updated in future releases of the capistrano-magento2 gem to be further secured by default, and also allow for greater configurability).
- Runs
bin/magento setup:static-content:deploy
andbin/magento setup:di:compile-multi-tenant
- Once all of those commands run, the new release directory will be nearly ready to be switched to the “current” release. However immediately before doing so, the current release (the “current” symlink) will be put into maintenance mode using
bin/magento maintenance:enable
. The reason this is done is because thebin/magento setup:upgrade --keep-generated
command will be run immediately after the site is put into maintenance mode. This is important because any new or updated modules will have their version numbers updated in thesetup_module
table and if the current release sees that its modules aren’t in sync with that table, it will throw an error. - Capistrano deployments are atomic, so if any of the commands up to this point failed, the deployment will fail and the
/var/www/html/current
symlink will continue to point to the release directory it was pointed to before you began the deployment. - At this point, the
/var/www/html/current
symlink will be switched to point to the newreleases/XXXXXXXX
directory. - Flushes cache via
bin/magento cache:flush
The deploy process implemented for deployment of Magento 2 by the capistrano-magento2 Gem can be seen in lib/capistrano/tasks/deploy.rake
If you completed all of the previous steps properly, you should now be able to browse to http://stage.example.com and see your newly deployed Magento site. When you want to deploy future code changes to stage, ensure the changes are in the develop branch and run the cap staging deploy
command again to deploy the latest changes to stage.
Once you deploy to stage, the /var/www/html
directory on your stage server should look something like this:
. ├── current -> /var/www/html/releases/20160526030129 ├── releases - this directory will contain the latest X releases. X is defined by :keep_releases which defaults to 5 │ └── 20160526030129 ├── repo - this is a bare clone of your Git repository ├── revisions.log - a line for each release with the commit hash, release date, and username of the machine that deployed └── shared - this is a permanent directory that contains the files/directories referenced by :linked_files and :linked_dirs ├── app │ └── etc │ └── env.php ├── pub │ ├── media │ └── sitemap.xml └── var ├── backups ├── composer_home ├── importexport ├── import_history ├── log ├── session └── tmp
Now that your stage deployment is configured, follow the same steps to setup your production deployment.
Additional capistrano-magento2 Features
In addition to deploying changes, the capistrano-magento2 Gem also supports a number of Magento maintenance commands. Run cap -T
in the tools/cap
directory to see a list of commands. Many of the commands are simply aliases for bin/magento
commands. The benefit of running them from Capistrano is two-fold: You don’t need to SSH into your stage or production server in order to run the command, as Capistrano handles that for you. Secondly, if you have multiple application servers, you can run a single command in all of your application servers simultaneously. These are the commands available in version 0.2.4 of capistrano-magento2:
cap magento:cache:clean # Clean Magento cache by types cap magento:cache:disable # Disable Magento cache cap magento:cache:enable # Enable Magento cache cap magento:cache:flush # Flush Magento cache storage cap magento:cache:status # Check Magento cache enabled status cap magento:cache:varnish:ban # Add ban to Varnish for url(s) cap magento:composer:install # Run composer install cap magento:indexer:info # Shows allowed indexers cap magento:indexer:reindex # Reindex data by all indexers cap magento:indexer:set-mode[mode,index] # Sets mode of all indexers cap magento:indexer:show-mode[index] # Shows mode of all indexers cap magento:indexer:status # Shows status of all indexers cap magento:maintenance:allow-ips[ip] # Sets maintenance mode exempt IPs cap magento:maintenance:disable # Disable maintenance mode cap magento:maintenance:enable # Enable maintenance mode cap magento:maintenance:status # Displays maintenance mode status cap magento:setup:di:compile # Runs dependency injection compilation routine cap magento:setup:permissions # Sets proper permissions on application cap magento:setup:static-content:deploy # Deploys static view files cap magento:setup:upgrade # Run the Magento upgrade process
Reverting
Capistrano supports reverting to previous releases using cap deploy:rollback
. This can be useful if you mistakenly deploy code to an environment and want to immediately revert it. However, if you want to use this feature, there are some things you need to be aware of:
- If your newest release contained new extensions or newer versions of extensions, you’ll need to manually adjust the values in the
setup_module
table or else you will get errors. - If a deployment fails or you cancel it, the releases/<TIMESTAMP> directory for that failed release will still exist. If you rollback, Capistrano will use the most recent release directory, even if it was not a successful deploy.
- After reverting, you’ll need to run the
cap magento:cache:flush
command - I’ve only used this command once, so there may be other things you need to do that I’m not listing here.
OS X notifications
If you’d like to get OS X notifications of successful/failed deployments, follow the steps outlined under “Terminal Notifier on OS X” in the README
Review pending changes before deploying
If you want to see what changes you’re about to deploy to an environment, you can add the capistrano-pending gem as a dependency. Add this line to tools/cap/Capfile
:
require 'capistrano-pending'
Now, cd
to tools/cap
and run these commands to see pending commit messages and file changes (respectively):
$ cap stage deploy:pending $ cap stage deploy:pending:diff
Flushing Varnish cache
If you’re using Varnish to cache your static assets, you’ll need to take some extra steps to get capistrano-magento2 to flush Varnish. I’m not going to cover those steps in this article, but if you’d like to learn more, feel free to post a comment below.
Summary
It can take a while to get familiar with and setup an automated deployment system, but due to the amount of effort required to manually deploy changes to stage/production environments with Magento 2, the payoff should be worth the investment. Especially because deploying with Capistrano ensures a minimal amount of site downtime when deploying.
If you have any questions or feedback, I’d love to hear them in the comments section below.