Magento 2 Deploy with Anistrano
I’ve inherited range of Magento 2 continuous delivery pipelines. Most suffering
from excessive downtime during deployments. Ideally, downtime should only be
needed when there is a need for running setup:upgrade
. Here is an example of
deployment steps developed by a prominent Adobe partner who will rename
nameless:
- Build application
- Put site in maintenance mode
- Push build artifact to all nodes
- Stop Magento cron
- Run
setup:upgrade
- Restart php-fpm and nginx
- Remove site from maintenance mode
The entire process leaves the site inaccessible for about 8 minutes, deploying
to 4-5 nodes. Executing setup:upgrade
accounts for 30 seconds of the downtime.
The pipeline puts the site in maintenance mode before pushing code to the nodes
because code was going directly into the document root. There is also no reason
for taking the site down when stopping the crons in our case. In the event of a
rollback we are left repeating the entire process.
Meet Anistrano
Anistrano is an Anisble port of Capistrano. This particular pipeline was already using Ansible for deployment tasks making Anistrano a great fit. The Anistrano docs provide a great primer on the main workflow. I recommend reading the docs if you are unfamiliar with Capistrano or Anistrano.
Building the POC
I set out building a quick POC for experimenting with Anistrano and Magento2. Ansitrano natively solves issues with the existing CD job.
- Natively separates deploy steps for a clearer view on what happens when.
- Is not writing directly to the live document root during the entire process.
- Retains prior releases on nodes in case you need to rollback.
Here’s the workflow I originally envisioned:
- Update Code - Push build artifact to remote hosts. Anistrano creates a
unique release directory for each deploy attempt and removes the need
existing need for taking the site down while pushing the code.
- Unpack and remove the artifact archive.
- Ensure proper ownership of the unpacked build.
- Symlink Shared Items - Anistrano allows sharing directories and files
between releases. For the POC I am sharing
var
,pub/media
andapp/etc/env.php
- Before Symlinking Release to Document Root
- Check database schema status with the new release with
setup:db:status
. We’ll use the output of the command for determining if the site should be placed in maintenance mode and runningsetup:upgrade
. - If the database schema is out of date we add the maintenance flag to the new release putting the site in maintenance mode as soon as the document root symlink is updated.
- Check database schema status with the new release with
- After Symlinking Release to Document Root
- Restart
php-fpm
. This clears opcache and prevents potential issues from swapping the symlinked document root whenvalidate_timestamps
is disabled (it should be on production servers). - Run
setup:upgrade
if the schema requires update. Otherwise, we flush the cache. - Remove the site from maintenance mode if needed.
- Restart
This limits downtime to about 45s when setup:upgrade
. The downtime is just a
few seconds when not updating the schema. You can find the Ansitrano tasks used
in this POC on GitHub