Magento 2 Deployment

Marco de Vries

April 18, 2017

7 min lezen

In Magento 1, it was still possible to change the code of a live webshop on the fly. In Magento 2, this is no longer an option. A deployment step is needed. In this article I’ll tell you what deployment is, why it is necessary, and what our approach to it is at the moment.

Deployment is the process of moving new code from the safeness of the development environment to the hard reality of production. Since Magento is written in PHP, it is well suited to copy single files from development to production without any disruption of the live shop. However, as processes get more complex, and the demands for real-time performance more severe, things like pre-processed code and caching take the place of flexibility. Moving to production becomes a process by itself.

Tool: Deployer

We have written a custom deployment tool around Deployer. Deployer is a PHP tool that allows easy interaction with a production server. I will give some examples of the steps it takes to deploy, but we don’t release the source code because there’s no one-size fits all deployment script. Different companies working with Magento have different demands on a deployment tool. However, Deployer is easy to work with and can be tailored by any developer versed in PHP.

Our tool contains a directory with a config file for each shop. Changes to the deployment tool are easy to make.

Directories and public_html

The production server directory structure we crafted looks like the standard Deployer structure, with some differences:

shared is the directory that contains all files that are shared between releases: config files, images, feeds, sessions, logs. It is set up once and never touched again. Next to the database, the shared folder is the only essential part of the webshop that needs to be backed up.

The release directories (5, 6, 7, current) contain symlinks to subdirectories of this shared folder. The symlinks are preferably relative. Absolute symlinks may have more severe permission constraints on some servers.

public_html, which is normally a directory, is turned into a symlink that points to:

deployments/releases/current/pub

Hosting providers don’t always provide the possibility to set the document root to whatever directory you would like (e.g. pub). By changing public_html into a symlink, you take that power into your own hand.

In our setup, current is not a symlink pointing to the latest release dir, as is the case in standard Deployer. It’s a plain directory. We have made this change because symlinks are regularly cached (for example by webserver Apache) for some time and this is problematic. Notably, when an extension is updated to a new version, the version in the table “setup_module” must match the version in the code’s “module.xml”. When a new version is deployed, some long lived Apache children may still hold cached symlinks to previous release code for several minutes. Database version and code version do not match and Magento throws an error. Always pointing the symlink public_html to the same directory (current/pub) solves this problem.

When a new release is made, the deployment process creates a new release dir, say ‘8’.

In the switch stage, after maintenance mode is enabled, current and 8 switch names. This can be done with three ‘mv’ instructions.

After this the database is updated, caches are cleared (notably Redis) and maintenance mode is disabled. The shop is offline for just a few seconds.

Rollback

In case of an emergency, we can reactivate a previous release of the shop by just changing directory names.

This does not work if an extension has a new version, because the version of the code does not match the version in the database anymore. In such a case, change the version in the extension’s module.xml manually to prevent prolonged downtime.

Deployment stages

Whenever a new release is needed, we give a single command to the server to start the deployment process. At this point the deployment tool goes through five phases:

  • create a build version of the shop
  • update its code, its module versions and its database
  • prepare a new release directory on the production server
  • switch to the new directory
  • clean up old releases

These phases are described in more detail below.

Create the build shop

The first 2 phases take place on the build server.

In the first release, a complete “build shop” is created on the build server, programmatically. It consists of an empty database and a composer install of a Magento installation. There’s no need to copy the production database to the build server, because all we’re interested in is the table “setup_module”, presuming that our build process is the only process that adds extensions to the production server.

Update the build shop

The shop on the build server is updated to the new version. The code is pulled from the BitBucket Git repository, and the third party code is installed using Composer. The update is done on the previous state of the build server, so that “git pull” only downloads the changes since the previous release.

All these steps are performed on the offline build shop:

  • git pull
  • create a file pub/static/deployed_version.txt
  • composer install
  • apply a set of patch files for known Magento problems
  • chmod +x bin/magento
  • build vendor/snowdog/frontools/node_modules for Sass compilation
  • set the build shop to production mode
  • bin/magento setup:upgrade
  • bin/magento di:compile
  • bin/magento setup:static-content:deploy
  • Do ‘gulp styles’ to compile css files from sass files
  • git checkout pub/.htaccess (because it is overwritten by earlier steps)

Prepare a new release on production

Deployer takes care of creating a new directory.

rsync can be used to copy code to the production server very efficiently. The following command copies the folder $source to the folder $target on the server via SSH. It checks if the directory $current on the production server already has the needed files, so they don’t need to be transferred. Even better, it creates hard links to these existing files, and this saves both time and disk space. It excludes the .git directory.

rsync --link-dest {$current} --exclude ".git/" -e "ssh -p {$port}" -a {$source} {$target}

Finally Magento is set to production mode if it wasn’t already (first release only).

Switch

In this phase, the new release is activated.

  • bin/magento maintenance:disable
  • mv {$new} {$temp} && mv {$current} {$new} && mv {$temp} {$current}
  • bin/magento setup:upgrade –keep-generated
  • bin/magento cache:flush
  • bin/magento maintenance:enable

Cleanup

We keep up to 10 releases per shop. Older releases are removed in this phase.

Finally

A separate deployment process is a must have for a Magento 2 webshop. It ensures that changes to the shop are made in a controlled fashion that ensures minimal downtime. Problems in the upgrade process show up in the offline build environment where they can still be fixed. If the released code shows problems only after it has gone live, there’s also the possibility to quickly revert to the previous code. These features make that a deployment tool is not only a necessity, it can also be an improvement to maintenance quality.

A deployment tool needs to keep evolving to adapt to changing circumstances however. Magento 2.2 promises a near-zero downtime deployment model, so this may change everything again!

Make sure to consult the Magento deployment page if you’re planning to create a deployment process.

Hebben wij jouw interesse gewekt?

Laten we er eens over kletsen, onder het genot van een goede kop koffie!

neem contact op