Magento releases have more steps than most web applications: Composer dependencies, database schema through setup:upgrade, dependency injection compilation, static content deployment and a reindex, in that order, with a cache flush at the end. Done on a live store, any one of them can take the site down for minutes. This post follows a Magento developer building a release path on MassiveGRID PaaS, which is built on Virtuozzo Application Platform, formerly Jelastic, that keeps the risky steps off production.

The developer works for an outdoor-equipment retailer we will call Tarn & Fell. Production is the auto-scalable Magento cluster; for development and staging he uses the Magento Standalone package, a single optimised PHP application server with MariaDB, a search engine and optional Redis, which installs in a few minutes and costs a fraction of the cluster.

Why staging is standalone and production is a cluster

Staging does not need high availability; it needs to be a faithful copy of production's code and data at a fraction of the cost. The Standalone package runs the same Magento version, the same PHP and MariaDB versions and the same search engine as the cluster, so an extension that compiles and installs on staging will do so on production. What it lacks, the load balancer, the second PHP node, the replicated database, is exactly what a developer does not need to test a module. The developer keeps a permanent staging environment and stops it at night with the Start/Stop Scheduler add-on; a stopped environment is billed for disk only.

For anything that touches the cluster's own behaviour, such as a change to Varnish VCL or to how sessions are stored, he instead clones production, which produces a full copy of the cluster for the hours he needs it.

The release checklist, and where each step runs

StepStaging (Standalone)Production (cluster)
composer install with the locked dependenciesYes, from the release branchIn the build, not on the live nodes
bin/magento setup:upgradeYes, against a fresh copy of the production databaseOnce, from one node, with the layer in maintenance for the seconds it takes
setup:di:compile and setup:static-content:deployYesIn the build artifact
indexer:reindexYes, timedScheduled indexers by cron; full reindex only if a release requires it
Cache flush and Varnish warm-upYesAfter the last node deploys
Smoke test: PDP, cart, checkout with a test paymentManual and scriptedScripted against each node as it comes back

Rehearsing setup:upgrade against real data

The step that fails in surprising ways is setup:upgrade, because a schema change behaves differently on a table with two million rows than on a developer's fixture. Before every release the developer restores last night's production dump into staging using the Database Backup/Restore add-on, deploys the release branch through the platform's Deployment Manager and runs the upgrade with a timer. If it takes four seconds, the production window is four seconds. If a third-party module's patch takes four minutes because it rewrites a large table, he knows to schedule the release at 03:00 rather than at lunch, and to tell the store manager. There is no other way to learn that number.

Deploying to the cluster without a maintenance page

Production has two or more PHP nodes behind the balancer, and the platform can run any layer operation sequentially: one node is taken out of the balancer, updated, given a configurable pause (30 seconds by default), then the next. For code-only releases, meaning no schema change, the developer uses that directly: the Deployment Manager deploys the built release to the layer sequentially, and shoppers are served by the other node throughout. The build artifact already contains compiled DI and static content, so the node is ready the moment the files land.

For releases with schema changes he adds a short controlled step. Magento's setup:upgrade must run once against the shared database, and while it runs the code on the nodes and the schema can briefly disagree. He puts the store in Magento's maintenance mode with the store's own IP allowlisted, runs the upgrade from one node (the four seconds he measured on staging), then deploys the code sequentially and lifts maintenance. Shoppers see a maintenance page for seconds rather than minutes, and only for releases that need it.

Cron, indexers and the shared filesystem

Two Magento specifics catch developers who come from single servers. The first is cron: Magento's scheduled indexers, email queue and cache cleaning must run from exactly one place, or jobs collide. In the cluster the developer runs the Magento cron on the master PHP node only, using the platform's cron editor for that node, and none on the nodes added by scaling. The second is media: product images uploaded through the admin must appear on every node, which is why the cluster stores pub/media on shared storage mounted into each PHP node. Code, by contrast, is deployed to each node's local disk, where PHP's OPcache wants it.

Rolling back

Because the Deployment Manager keeps the previous deployment, a code-only rollback is a redeploy of the previous build, sequentially, in a couple of minutes. A rollback after a schema change is a database restore from the backup taken at the start of the release window plus the code redeploy, which is why the release starts with an on-demand backup and why the developer measured the restore time on staging too. He has needed the second kind once; it took eleven minutes at 03:00 and nobody outside the team knew.

Frequently Asked Questions

Can I skip maintenance mode during setup:upgrade if I use zero-downtime deployment tricks?

Magento does not officially support running setup:upgrade without maintenance mode, and code that expects the new schema can error against the old one for the seconds the upgrade takes. Keep the window as short as your staging rehearsal showed, and use maintenance mode with your IP allowlisted. For code-only releases no maintenance is needed.

Why not build on the production nodes?

Composer, DI compilation and static content deployment are CPU-heavy and take minutes. Doing them on a live node steals CPU from shoppers and lengthens the deploy. Build once on staging or in CI, then deploy the artifact to production so each node is updated in seconds.

How do I move from Standalone to the cluster when the store grows?

Install the cluster package, deploy your code, import the database from a Standalone backup, copy media to the shared storage node, run setup:upgrade and reindex, then switch DNS. The Standalone environment then becomes your permanent staging.

Rehearse on standalone, release to the cluster

Magento Standalone installs a complete Magento 2 stack in minutes on MassiveGRID PaaS for staging and development, with the Auto-Scalable Magento Cluster as the production target. Pay per cloudlet-hour, stop staging at night. Free 14-day trial.

Magento Standalone on MassiveGRID PaaS

Further Reading