Photo by Dewang Gupta on Unsplash
a tutorial the story of how one night I set out to streamline my deployment process and found myself hours later at 4am building new docker images. Hopefully it contains valuable information for those of you looking into setting up CI/CD for your Laravel app, so that you won't have to stay up all night like me.
Quite simply, that on every push to
staging phpunit tests are run automatically.
Additionally, that if all tests pass on the branch
staging the app is automatically deployed to Elastic Beanstalk.
I left the
master branch deployment to "manual" because I don't want an accidental push to deploy a new feature in production.
I'm trying to keep this concise and to the point, and for this reason it's expected that you already have the following ready (if you don't, don't worry, bookmark this article and come back later):
- A working Laravel app in your local environment, with its git repository on GitLab, and two branches:
staging(all pretty standard so far)
- Two configured and running environments on AWS Elastic Beanstalk (you probably want them inside the same Beanstalk Application, I found this guide very useful for this part)
- A IAM user in your AWS Account with Elastic Beanstalk Full Access permissions (we will need the Access/Secret Keys of this user, make sure you note them down somewhere)
- That you have installed the EB CLI and ran
If you've run
eb init you'll notice that you now have a folder named
.elasticbeanstalk. This folder is essential for GitLab, but for some reason the command also added a few lines in your
.gitignore effectively making it impossible for GitLab to do its job. If you see something like this in your
# Elastic Beanstalk Files .elasticbeanstalk/* !.elasticbeanstalk/*.cfg.yml !.elasticbeanstalk/*.global.yml
go ahead and delete those lines.
Let's start from the end of the process, just to spice things up a little bit.
After every deployment of a Laravel application (and this is true for any server setup, not just EB) we need to make sure that our remote (gitignored)
/vendor folder has all the needed packages, and that the structure of the remote database is up to date. This is done by running two commands:
$ composer install and
$ php artisan migrate.
Additionally, in our specific setup we need to tell EB that our app is served from the folder
/public, and since SSL is morally mandatory by now we also probably want to tell Apache to redirect all http requests to https.
This is a basic setup that should work well for 98% of the projects.
Now, we could ssh into the remote machine and run a few commands, but fortunately Elastic Beanstalk provides us with Configuration Files (a set of YAML files in a
.ebextensions folder that instruct the remote server on AWS to run certain commands right before and right after deployment) that suit our CI/CD workflow perfectly.
You are welcome to explore the official documentation , but again fortunately yours truly went ahead and published the needed files on GitHub for your peruse.
In the root of your project run:
$ svn export https://github.com/mjsarfatti/laravel-eb-gitlab-ci/trunk/.ebextensions
This will create a
.ebextensions folder, with four files inside. Feel free to inspect the files, and note that I went ahead and added a couple of goodies in there.
To instruct GitLab on how and what to run during deployment we need to create and commit a
.gitlab-ci.yml file. How GitLab CI works is out of the scope of this tutorial, but the file itself is pretty self-explanatory.
Add it to your project:
$ svn export https://github.com/mjsarfatti/laravel-eb-gitlab-ci/trunk/.gitlab-ci.yml
Then open up this file, and make sure to set the variable
MYSQL_DATABASE to whatever your testing database name is (you'll probably find it in your
At times you may want to deploy even if tests fail (for example if you are testing the deployment itself). Or you want to push a simple edit (like a typo in your README, or in a warning message) and you don't want to use precious CI minutes for useless testing.
.gitlab-ci.yml has a friendly rule that will skip testing if the commit message contains the phrase
[skip tests] (or a variation such as
[skip test] or
Log in to your GitLab account, and in your project's Settings > CI / CD add two variables, one named
AWS_ACCESS_KEY_ID with, you got it, your IAM user access-key-id, and one named
AWS_SECRET_ACCESS_KEY with... well you know what.
And that's it 🥳
Push away and enjoy your well deserved peace of mind.
So how is it that I spent the night building docker images, you ask?
Well, it all started when I discovered these AMAZING Docker images by Eduardo Bizarro preconfigured with PHP, Composer, Node and Yarn and available for PHP 7.1, 7.2 and 7.3: https://github.com/edbizarro/gitlab-ci-pipeline-php/
Crazy, I thought (it was still only 11pm), I'll just include those in my
.gitlab-ci.yml and call it a night.
The images don't include
eb (why would they). So I tried to install it. But
pip needs a few weird Python packages. Just
apt-get, right? Wrong.
The images don't run on the root user (I guess it's a sane default?), which means I can't install any package during CI. I knew the way to go would be to fork the project, dive into their Dockerfile and customize it to my needs. But I've barely ever used Docker before, I didn't feel like embarking on a new adventure that late at night (funny, uh?).
So I fought, and I fought, and I fought. I tried all 3 Linux distributions they come with, and I tried all different methods to install
eb, including installing all the tools in a local folder. Nothing worked.
So now it's 3am, and there I am with a simple choice: should I go to bed and rest or is this now the fight of my life?
You can imagine what happened.
I opened up https://hub.docker.com/, studied Bizarro's repo, studied the getting started and, lo and behold, an hour later I had:
- successfully reconfigured Bizarro's images to install EBCli, AWSCli and CLI53 (because why not)
- published the new image to Docker
- successfully used my first ever new Docker image to deploy my Laravel app to Elastic Beanstalk 🎉🎉🎉
So if you notice in our
.gitlab-ci.yml file we are using
Please note: this is a PHP 7.2 Debian-based image. You can't install packages. It's not thoroughly tested. But it works.
As always, I would be nowhere near where I am if it wasn't for the material, software and tutorials that accompanied me last night. In no particular order, big thanks to:
Comment below if this guide has been useful, and if you face any problem!
-- EDIT --
Added rennokki/laravel-aws-eb link