Gitlab CI/CD pipeline with aws integration for magento 2 deployment
February 18, 2022 ยท View on GitHub
Feature highlights
- Created with simplicity and ease of use in mind, inspired by magento cloud pipeline
- Emphasis on zero downtime during deployment, must have at least 2 nodes for this
- Separate root to build application changes without affecting mage root
- State checking flow for optimized build of pipeline/server/application related changes
- Simple deploy summary for pipeline/server/application section in tabular format during each deployment
- Support to sync nginx, php, logrotate and magento env changes directly from repository to golden server
- Composer auto update flow when last update run exceeds 30 days during deployment even without any changes
- Patches install complete flow to auto apply, revert and delete relevant changes
- Aws cli integration to create image, update launch configuration and start/wait for instance refresh
Important configuration information
- Part of static
pub/staticon efs causes massively slow static deployment so it should not been kept on efs - Part of static
var/view_preprocessedwill be on efs due to entirevarbeing efs, so custom configuration will be done later on to remedy massively slow static deployment - Part of static
pub/static/_cacheshould for now be in efs as it generates only on demand and not sharing it breaks layout static cache bug - Crontab for
rootandubuntuuser will be auto deleted on auto scaling nodes to avoid conflicting cron runs, this effectively allows golden server to be also used as a dedicated cron server. It is achieved using launch configuration user data. - Logrotate config has
*.cfsavedextenstion so regular cron skips it and we can define custom schedule usingrootuser'scrontabas required
# Magento log rotation
45 20 * * * /usr/sbin/logrotate /etc/logrotate.d/magento.cfsaved -s /var/lib/logrotate/magento.status
Contents overview
- Project sequence diagram
- Pre-Requistices
- Configure repository and user for deployment
- Configure gitlab server
- Configure golden server
- Usage of pipeline and extra information
1. Project sequence diagram

2. Pre-Requistics
- Proper credentals/vpn to ssh into staging/production ec2 servers
- Magento 2 existing project installed and running on staging/production ec2 server
- These folders mounted on efs
app/etc,varandpub/mediain ec2 server mage root - All services endpoint accessible from staging/production ec2 server
- Proper credentals to ssh into gitlab hosted server
- Gitlab installed/running, magento repository configured in gitlab and two gitlab shell runner configured
- Access to all relevant aws credentals and aws cli installed and configured in gitlab/staging/production server
- Ssl configured using
ssl terminationexternally from loadbalancer side
3. Configure repository and user for deployment
- Clone this repository in your pc and cd into it
- Follow steps below to configure repository for existing and cloud
- Follow steps below to configure a new new user for deployment
Existing magento repository
- Add the config samples to your existing magento repository, replace
$path_to_your_projectwith your project path
cp .gitlab-ci.yml.dis $path_to_your_project/.gitlab-ci.yml
cp .gitignore.dis $path_to_your_project/.gitignore
cp .rsyncignore.dis $path_to_your_project/.rsyncignore
cp -r .ec2.dis $path_to_your_project/.ec2
- Modify
.gitignorefile as needed .ec2/sharedhas config samples which will be shared between staging/production, modify as needed- The php logs path has been modified to
/var/log/php/php*.log, recommended to do similar in your server php fpm config .ec2/productionhas config samples for production only, replace$domain_namewith your domain name in file names and file contents- Replace all
$variablein.ec2/production/magento/env.phpfile with production services information .ec2/staginghas config samples for staging only, replace$domain_namewith your domain name in file names and file contents- Replace all
$variablein.ec2/staging/magento/env.phpfile with staging services information - Commit changes and push to your existing magento respository, pipeline will be skipped as it's restricted to specefic branches.
Repository for cloud
- Create a new repository preferably with
cloudsuffix to your existing repository name, examplecompany-magento-cloud - Delete default
masterbranch and create two new branches asstagingandproduction - Clone your updated existing magento repository into these two new branches
- Keep
productionbranch as default/protected,stagingbranch can be left unprotected to allow force pushes - Restrict the two gitlab runner created to this project and add
productionin tags to one andstagingin tags to another - Configure production gitlab runner to only run on pipelines triggered on protected branches for security
User for deployment
- Create a new user in gitlab with username
deployerand fullname preferably asAws Cloud - Give this user access to the new repository created for cloud
- Create two ssh keypair and add the public keys to
ssh keysin user setting namedec2 productionandec2 staging - Copy the private key of ssh kepair to respective ec2 production/staging server
~/.sshfolder and rename asgitlab - The deployer user and keypair will later be used for paswordless git operations over ssh.
4. Configure gitlab server
- Follow steps below to configure gitlab-runner user, ssh and this repository
Configure gitlab-runner user
- Setup a password for
gitlab-runneruser and add it tosudogroup, all operations in gitlab server will use this user by default - Login into gitlab server using
gitlab-runneruser and created password - Copy your vpn file to
/etc/openvpn/clientand add this entry in sudoders file for passwordless commands for openvpn
# Passwordless sudo commands
gitlab-runner ALL=NOPASSWD: /usr/sbin/openvpn, /usr/bin/pkill
Configure ssh
- Create a ssh
configfile in~/.sshand add these entries, replace$host_ipwith ssh ip of each servers and$key_namewith key name
Host production_golden
User ubuntu
HostName $host_ip
IdentityFile ~/.ssh/$key_name.pem
Host staging_golden
User ubuntu
HostName $host_ip
IdentityFile ~/.ssh/$key_name.pem
- Start the vpn using
sudo openvpn $cloud_awsand make sure vpn is connected and did not require sudo password - Ssh into each of the ssh alias created above manually firstime to cache the fingerprint, replace
$ssh_alias_namewith host alias from above
ssh $ssh_alias_name
- Once ssh into every server is working and cached, close the vpn using
sudo pkill openvpnand make sure it did not require sudo password
Configure this repository for gitlab
- Clone this repository in home folder of user
- Add some variables in
/etc/environmentfor pipeline commands alias, replace$vpn_namewith your own
# Aws Openvpn config
cloud_aws="--config /etc/openvpn/client/$vpn_name.ovpn"
# Root path
scripts_root="/home/gitlab-runner/gitlab-aws-magento2-deploy/scripts/gitlab"
- Cd into
$scripts_rootand create two .env file for staging and production from sample env file
cp -a .env.dis .env.prod
cp -a .env.dis .env.stag
- Edit each of the
.envfile and addproductionorstagingaws related details
5. Configure golden server
- Redo these steps for each golden server
productionandstaging - Follow steps below to configure mage/build root and ssh and this repository
Configure mage/build root and ssh
- Checkout the specefic instance branch
production/stagingfrom the repository created for cloud in yourmage root - Create an additional local only deploy branch named
deployin yourmage rootwhich will allow build stage to be retryed with changes - Create a ssh
configfile in~/.sshand add these entry, replace$gitlab_domainwith your own,$host_ipwith it's ip and$key_namewith key name
Host $gitlab_domain
HostName $host_ip
IdentityFile ~/.ssh/$key_name.pem
- Cd into your current
mage rootand change the git remote to ssh one instead of https, now all git commands should work through ssh - Create a new folder in
/var/www/htmlasbuildand copy over.gitand.gitignorefrom mage root - Run
composer installinbuildfolder to install all packages, make sureconfig.phpis also present inapp/etcif not already - Magento build operations can be done without any services connection so
env.phpis not required inapp/etc - Create a symbolic link for
view_preprocessedoutsidevarto non-efs folder inbuildfolder
rm -rf var/view_preprocessed
mkdir -p symlinks/view_preprocessed
cd var && ln -snf ../symlinks/view_preprocessed .
- Modify
pub/index.phpsection to use customview_preprocessedas follows
$tmpMaterializationDir = dirname(__DIR__, 1).'/symlinks/view_preprocessed/pub/static';
$params = $_SERVER;
$params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] = array_replace_recursive(
$params[Bootstrap::INIT_PARAM_FILESYSTEM_DIR_PATHS] ?? [],
[
DirectoryList::PUB => [DirectoryList::URL_PATH => ''],
DirectoryList::MEDIA => [DirectoryList::URL_PATH => 'media'],
DirectoryList::STATIC_VIEW => [DirectoryList::URL_PATH => 'static'],
DirectoryList::UPLOAD => [DirectoryList::URL_PATH => 'media/upload'],
DirectoryList::TMP_MATERIALIZATION_DIR => [DirectoryList::PATH => $tmpMaterializationDir]
]
);
- Remove these files from current
mage root, they can be left undeleted but serves no purpose in this pipeline frommage root
rm -r .ec2 .git .gitignore .gitlab-ci.yml
- Rsync your
build rootchanges tomage root
sudo rsync -a --exclude-from=".rsyncignore" $build_root/ . --delete
- Since
varandsymlinksis skipped for rsync, create a symbolic link forview_preprocessedoutsidevarto non-efs folder inmage rootas well
rm -rf var/view_preprocessed
mkdir -p symlinks/view_preprocessed
cd var && ln -snf ../symlinks/view_preprocessed .
Configure this repository for golden
- Clone this repositrory in home folder of user
- Add some variables in
/etc/environmentfor pipeline commands alias, replace$domain_namewith your project domain name
# Root path
mage_root="/var/www/html/$domain_name"
build_root="/var/www/html/build"
scripts_root="/home/ubuntu/gitlab-aws-magento2-deploy/scripts/ec2"
- Cd into
$scripts_rootand create two .env file for staging and production from sample env file
cp -a .env.dis .env.prod
cp -a .env.dis .env.stag
- Edit each of the
.envfile and addproductionorstagingaws/magento related details
6. Usage of pipeline and extra information
- After setting up everything from previous steps, make some changes in previous already existing repository, commit and push changes
- Clone the new repository for cloud in seperate isolated folder and pull changes of previous repository in one of the branches preferably
staging - Push the changes to relevant branch, the pipeline should trigger, run it's operations and complete if everything was setup up properly
- Symbolic linked
view_preprocessedinvarwill be used bystatic deploymentcommand while modifiedview_preprocessedinpub/index.phpwill be used bynginx - Admin configuration
Enable Symlinksdoes not need to be enabled, it's only needed for read operations while write operations can be done safetly with this disabled - To force application build even without changes use the web ui
run pipelineand setFORCE_APPLICATION_BUILDto1or set this variable to1during git push
git push origin $branch_name -o ci.variable="FORCE_APPLICATION_BUILD=1"