In this article I will build a simple CI/CD flow which will have the following steps:
- push code to master branch and trigger Github Action to start
- run composer install
- run any tests or static analysis tools you have, for this example I will just run PHPStan
- if everything goes OK wrap all in a zip file and deploy it to an existing AWS ElasticBeanstalk environment.
- update database as a postdeploy step
I use Github Secrets for storing AWS key access but for the other parameters from .env that I want to override I store them directly in the AWS ElasticBeanstalk > Environment > Configuration > Software.
Example of using secrets parameters in yaml config file:
aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
In order to get started with Github Actions add to the root of your project a folder called ".github" and inside of it another one called "workflows" and finally a file with a name for example "my_workflow.yml".
.github/workflows/my_workflow.yml
In my example the Symfony project is in a subdirectory of the repository so I have to set a working directory and also pass it as parameter for composer.
# This is a basic workflow to help you get started with Actions
name: Build and test
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
pull_request:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
php-unit-and-functional-tests:
runs-on: ubuntu-20.04
defaults:
run:
working-directory: ./html
strategy:
fail-fast: true
matrix:
php-versions: ['7.4']
steps:
# —— Setup Github actions —————————————————————————————————————————————
# https://github.com/actions/checkout (official)
- name: Git checkout placeholder-service
uses: actions/checkout@v2
# https://github.com/shivammathur/setup-php (community)
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
coverage: none
tools: composer:v2
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, dom, filter, gd, iconv, json, mbstring, pdo
env:
update: true
- name: Check PHP Version
run: php -v
# --- Install backend dependencies (Composer) ----------------
- uses: "ramsey/composer-install@v1"
with:
composer-options: "--ignore-platform-reqs --working-dir=html"
# —— Symfony ——————————————————————————————————————————————————————————
- name: Check the Symfony console
run: bin/console -V
# —— PHPStan --------------------------
- name: PHPstan
run: composer phpstan
- name: Generate deployment package
run: zip -r deploy.zip . -x '*.git*'
- name: Deploy to EB
uses: einaregilsson/beanstalk-deploy@v16
with:
aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
application_name: MyApp
environment_name: MyApp-env
version_label: ${{ github.sha }}
region: us-west-2
deployment_package: ./html/deploy.zip
After pushing a commit to master branch you can go your Github account and check the Actions tab to see the result.
In order to update database after deploy you will need to add a postdeploy step (this is a AWS ElasticBeanstalk feature). Create in your project the following folders structure:
.platform/hooks/postdeploy/01-database_update.sh
In my case this is inside the html folder because I deploy only the content of that folder. The file 01-database_update.sh looks like this:
#!/bin/bash
#Create a copy of the environment variable file to be accessible for other CLI scripts
cp /opt/elasticbeanstalk/deployment/env /opt/elasticbeanstalk/deployment/custom_env_var
#Set permissions to the custom_env_var file so this file can be accessed by any user on the instance. You can restrict permissions as per your requirements.
chmod 644 /opt/elasticbeanstalk/deployment/custom_env_var
#Remove duplicate files upon deployment.
rm -f /opt/elasticbeanstalk/deployment/*.bak
#export env vars and update database
export $(cat /opt/elasticbeanstalk/deployment/env | xargs) && php bin/console doctrine:schema:update --force
There is an extra effort to make available to the script the environment variables (the one I setted in AWS ElasticBeanstalk > Environment > Configuration > Software) as I do not store them in git repository and they are specific for this environment.
Extra
Fine tune your ElasticBeanstalk environment using .ebextensions folder. These extensions are executed in the order of the files names so it's a good practice to call them "01-my_extension.config" "02-my_other_action.config". Make sure to have the extension ".config".
For example you may want to set the right public directory (you can do this action also from AWS web interface). We will add a file called "01-environment.conf"
option_settings:
"aws:elasticbeanstalk:container:php:phpini":
document_root: /public
memory_limit: 512M
Check AWS docs on how to tweak this here: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_PHP.container.html
And now you can just sit back and enjoy your state of art build and deploy flow.