Zero-downtime deployment magento
Set up zero-downtime deployment using magento-actions
In this article will be shown how to make a zero-downtime deployment using our magento-actions. Magento-actions is a github action package that helps magento developers improve their CI/CD processes. Although the action itself does more than handling a zero-downtime deployment, the later will be our main focus here. Fell free to check out the github repo of the actions, to learn more about the other CI/CD operations, enabled by the module, such as testing (integration tests, static tests, etc...), code quality check (phpcs), etc...
The process shown here, can be used to migrate from manual deployment to a zero-downtime one.
1- SSH and server setup
The first thing to do is to create the ssh certificates that will be used by github actions server in order to execute specific operations on the target server (copy tarball, deploy, linking, etc...). We suppose the server used is linux, so we will be using open-ssl 's keychain generator (ssh-keygen) to create a public and private certificates.
For that make sure you have ssh-keygen available, if not consider installing keychain (apt install keychain).
Then execute the following command line to generate said certificates :
ssh-keygen -t rsa -b 4096 -N '' -f staging_ssh_key
Two files will be created :
stagging_ssh_key (the private key)
stagging_ssh_key.pub (the public key)
Next, copy the content of the public key file into the file named authorized_keys in the ssh directory on your staging/production server, create the file if none existent.
The file is found in the ~/.ssh/ directory, ~ corresponding to the home directory of the user which will be used to login from github actions server.
The private key will be feed into github actions secret, we'll come back to it shortly.
Unless, you're using a self-hosted runner in which case, make sure nonetheless the ip is whitelisted.
2- Setup your git project
Now we'll create, and setup on the local host the git repository used a VCS during the devs.
If not already done, execute the following commands :
mkdir myAwesomeShop
cd myAwesomeShop
git init .
Now we will set the directory following the required scaffolding:
├── .github # directory used by github applications i.e github actions
│ └── workflows # directory where the workflows are found, see below for an example of main.yml
├── README.md
└── magento # directory where you Magento source files should go
After creating the files and directories, copy the content of your current magento project (root directory) to the magento dir.
And then, create a file name main.yml in the subdirectory .github/workflows/.
The content of the file will be the following:
For Magento 2.1 to 2.3
name: m2-zerodownTime-deploy
on: [push]
jobs:
magento2-build:
runs-on: ubuntu-18.04
container: ubuntu
name: 'm2 tests & build'
services:
mysql:
image: docker://mysql:5.7
env:
MYSQL_ROOT_PASSWORD: magento
MYSQL_DATABASE: magento
ports:
- 3106:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v1
with:
submodules: recursive
- name: 'launch magento2 build'
if: always()
uses: MAD-I-T/magento-actions@v2.0
env:
COMPOSER_AUTH: ${{secrets.COMPOSER_AUTH}}
with:
php: '7.1'
process: 'build'
- name: 'start magento2 zero downtime deploy'
if: success()
uses: MAD-I-T/magento-actions@v2.0
env:
COMPOSER_AUTH: ${{secrets.COMPOSER_AUTH}}
BUCKET_COMMIT: bucket-commit-${{github.sha}}.tar.gz
MYSQL_ROOT_PASSWORD: magento
MYSQL_DATABASE: magento
HOST_DEPLOY_PATH: ${{secrets.STAGE_HOST_DEPLOY_PATH}}
HOST_DEPLOY_PATH_BUCKET: ${{secrets.STAGE_HOST_DEPLOY_PATH}}/bucket
SSH_PRIVATE_KEY: ${{secrets.STAGE_SSH_PRIVATE_KEY}}
SSH_CONFIG: ${{secrets.STAGE_SSH_CONFIG}}
WRITE_USE_SUDO: false
with:
php: '7.1'
process: 'deploy-staging'
- name: 'unlock php deployer if the deployment fails'
if: failure() || cancelled()
uses: MAD-I-T/magento-actions@v2.0
env:
COMPOSER_AUTH: ${{secrets.COMPOSER_AUTH}}
BUCKET_COMMIT: bucket-commit-${{github.sha}}.tar.gz
MYSQL_ROOT_PASSWORD: magento
MYSQL_DATABASE: magento
HOST_DEPLOY_PATH: ${{secrets.STAGE_HOST_DEPLOY_PATH}}
HOST_DEPLOY_PATH_BUCKET: ${{secrets.STAGE_HOST_DEPLOY_PATH}}/bucket
SSH_PRIVATE_KEY: ${{secrets.STAGE_SSH_PRIVATE_KEY}}
SSH_CONFIG: ${{secrets.STAGE_SSH_CONFIG}}
WRITE_USE_SUDO: false
with:
php: '7.1'
process: 'cleanup-staging'
For magento 2.4
name: m2-actions-test
on: [push]
jobs:
magento2-build:
runs-on: ubuntu-latest
container: ubuntu
name: 'm2 unit tests & build'
services:
mysql:
image: docker://mysql:8.0
env:
MYSQL_ROOT_PASSWORD: magento
MYSQL_DATABASE: magento
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
elasticsearch:
image: docker://elasticsearch:7.1.0
ports:
- 9200:9200
options: -e="discovery.type=single-node" --health-cmd="curl http://localhost:9200/_cluster/health" --health-interval=10s --health-timeout=5s --health-retries=10
steps:
- uses: actions/checkout@v1
with:
submodules: recursive
- name: 'this step starts static testing the code'
if: always()
uses: MAD-I-T/magento-actions@v3.7
env:
COMPOSER_AUTH: ${{secrets.COMPOSER_AUTH}}
with:
php: '7.4'
process: 'unit-test'
elasticsearch: 1
- name: 'this step will build an magento artifact'
uses: MAD-I-T/magento-actions@v3.7
env:
COMPOSER_AUTH: ${{secrets.COMPOSER_AUTH}}
with:
php: '7.4'
process: 'build'
elasticsearch: 1
- name: 'starts magento2 zero downtime deploy with no permission check'
if: success()
uses: MAD-I-T/magento-actions@v3.7
env:
COMPOSER_AUTH: ${{secrets.COMPOSER_AUTH}}
BUCKET_COMMIT: bucket-commit-${{github.sha}}.tar.gz
MYSQL_ROOT_PASSWORD: magento
MYSQL_DATABASE: magento
HOST_DEPLOY_PATH: ${{secrets.STAGE_HOST_DEPLOY_PATH}}
HOST_DEPLOY_PATH_BUCKET: ${{secrets.STAGE_HOST_DEPLOY_PATH}}/bucket
SSH_PRIVATE_KEY: ${{secrets.STAGE_SSH_PRIVATE_KEY}}
SSH_CONFIG: ${{secrets.STAGE_SSH_CONFIG}}
WRITE_USE_SUDO: false
with:
php: '7.4'
deployer: 'no-permission-check'
process: 'deploy-staging'
- name: 'unlock php deployer if the deployment fails'
if: failure() || cancelled()
uses: MAD-I-T/magento-actions@v3.7
env:
COMPOSER_AUTH: ${{secrets.COMPOSER_AUTH}}
BUCKET_COMMIT: bucket-commit-${{github.sha}}.tar.gz
MYSQL_ROOT_PASSWORD: magento
MYSQL_DATABASE: magento
HOST_DEPLOY_PATH: ${{secrets.STAGE_HOST_DEPLOY_PATH}}
HOST_DEPLOY_PATH_BUCKET: ${{secrets.STAGE_HOST_DEPLOY_PATH}}/bucket
SSH_PRIVATE_KEY: ${{secrets.STAGE_SSH_PRIVATE_KEY}}
SSH_CONFIG: ${{secrets.STAGE_SSH_CONFIG}}
WRITE_USE_SUDO: false
with:
php: '7.4'
process: 'cleanup-staging'
Now that the local git project is setup, we shall move on to the github setup.
3- Setup your github repository
Create the github repository to receive your project (instructions on github).
Now that the project is created, time to create the variables used by github actions (e.g ${{}} in the file above main.yml).
For that, go to Settings>Secrets of your github project and create and fill the following variables accordingly:
COMPOSER_AUTH = {"http-basic":{"repo.magento.com": {"username": "xxxxxxxxxxxxxx", "password": "xxxxxxxxxxxxxx"}}}
STAGE_HOST_DEPLOY_PATH = The path to the root dir on the satging or prod server (i.e /var/www/myawesomeshop/) STAGE_SSH_PRIVATE_KEY = The content of the ssh private key create in the beginning e.g ssh_staging_key STAGE_SSH_CONFIG = Host staging # this must be staging or production according to your deployment type User ubuntu # the staging/prod username bound to the ssh connecting IdentityFile ~/.ssh/id_rsa # Do not modified this unless you know what you're doing HostName my-awesome-shop.fr # the hostname or ip addr of your deployment server prod or staging Port 22 # The ssh often 22 to be modified accordingly to the server setup
The remaining setup is recommended but optional, indeed, to avoid failure during the first deployment. You should create theses dirs and files:
Create $HOST_DEPLOY_PATH/shared/magento/app/etc/ directory (i.e /var/www/myawsomeshop/shared/magento/app/etc/
Place your configured env.php in the directory
And we set!
Also when configuring you http server (apache, nginx etc...), the ROOT directory should be $HOST_DEPLOY_PATH/current/magento/ .
4- Launch the process
Now you can push your repository to github, the action will automatically start building and deploying your magento to prod (I.e on:[push] in main.yml). Make sure your magento, database and env.php are setup accordingly. Still in any case, if the deployment fails the cleanup task, will be launched.
In a successful scenario, you should see something similar to:
Successful CI/D Magento2
Also we do offer hands on paid support, if you're having trouble setting up your CI/CD, please checkout the offer details here.
Side note: Please feel free to check our Gitlab-CI extension of this tool.