28 Jan 2021
Hello! Today I would like to share Github Actions configuration and usage experience. I was interested in this tool for a while. As soon as I use CI/CD, docker containers etc. for commercial projects, but not for my personal/own pet projects
Main use cases:
Initially I configured Github Actions for this blog. Then I also made it for one of my open source projects - placeholder-service. Idea behind is to make it more clear and share all configs.
Firstly I dockerized app for local development environment using this tutorial.
Main advantages:
Finally, I have suchdocker-compose.yml.
version: '3'
services:
php-fpm:
build:
context: ./docker/php-fpm
environment:
- DOCKER_ENVIRONMENT=true
- APP_SECRET=${APP_SECRET}
volumes:
- ./:/var/www
nginx:
build:
context: ./docker/nginx
volumes:
- ./:/var/www
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./docker/nginx/sites/:/etc/nginx/sites-available
- ./docker/nginx/conf.d/:/etc/nginx/conf.d
- ./docker/logs:/var/log
depends_on:
- php-fpm
ports:
- "16880:80"
- "16843:443"
Then I moved some commands to composer scripts to make it easier for remember and usage.
So, I have such composer.json.
{
"name": "antonshell/placeholder-service",
"description": "There is a self hosted service for images placeholders generation",
...
"scripts": {
...
"test": [
"php bin/phpunit"
],
...
}
}
For example, for run tests I execute composer test
instead of php bin/phpunit
.
In github actions we are going to use shortcuts.
For tests configuration I used this tutorial.
I created .github/workflows/
directory and added tests.yml
file in the repository.
Tests.yml file looks like that:
name: Tests
on: [push]
jobs:
php-unit-and-functional-tests:
runs-on: ubuntu-20.04
strategy:
fail-fast: true
matrix:
php-versions: ['7.4', '8.0']
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
# —— Composer —————————————————————————————————————————————————————————
- name: Validate composer.json and composer.lock
run: composer validate
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache composer dependencies
uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
run: composer install
# —— Symfony ——————————————————————————————————————————————————————————
- name: Check Symfony requirements
run: vendor/bin/requirements-checker
- name: Check the Symfony console
run: bin/console -V
# —— Code style —— (Based on this package: https://github.com/OskarStark/php-cs-fixer-ga)
- name: PHP-CS-Fixer
uses: docker://oskarstark/php-cs-fixer-ga
with:
args: --config=.php_cs.dist --diff --dry-run
## —— Tests ———————————————————————————————————————————————————————————
- name: Run functionnal and unit tests
run: |
cp .env.ci .env.test
cp .env.ci .env
cp phpunit.ci.xml phpunit.xml
composer test
Each file in workflows directory describes some process. There is a workflow name, operational system(ubuntu 20.04), and when to run it(on push). There is also sequence of actions for preparing environment - setup PHP, clone a repository, setup dependencies etc.
When environment is ready, we are checking codestyle and run tests. Tests workflow triggered every time we are pushing changes to repository.
For deploy configuration I used this tutorial and this action.
1 . Created separate workflow - ssh_deploy.yml.
name: SSH Deploy
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v1
# Install PHP
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.0'
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)
- name: Validate composer.json and composer.lock
run: composer validate
- name: Get composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
- name: Cache composer dependencies
uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-
- name: Install Composer dependencies
run: composer install
# Prepare .env file for production
- name: Make production envfile
uses: SpicyPizza/create-envfile@v1
with:
envkey_APP_ENV: prod
envkey_APP_DEBUG: false
envkey_APP_SECRET: ${{ secrets.APP_SECRET }}
file_name: .env
# Copying files and artifacts via SSH
- name: Copying files to server
uses: appleboy/scp-action@master
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
passphrase: ''
rm: true
source: "./"
target: ${{ secrets.REMOTE_TARGET }}
# Run commands on production
- name: Executing remote ssh commands
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
passphrase: ''
script: rsync -a --exclude={'var','temp'} --delete ${{ secrets.REMOTE_TARGET }} ${{ secrets.REMOTE_TARGET_DEPLOY }}
Project build on a temporary server, then copied with ssh to main server.
2 . I used Github Secrets for storing secret data like server address, ssh key, passwords etc. There are more details about Github Secrets. Secret variables values can be used like that:
host: ${{ secrets.REMOTE_HOST }}
username: ${{ secrets.REMOTE_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
3 . Created ssh key for deployment user and added it to Github Secrets.
Saved id_rsa
file content to SERVER_SSH_KEY
variable.
ssh-keygen -m PEM -t rsa -b 4096 -f ./id_rsa
cat id_rsa
cat id_rsa.pub
4 . Creted separate user on remote server and added ssh key.
Added id_rsa.pub
file content to /home/deployment/.ssh/authorized_keys
.
adduser deployment
usermod -aG www-data deployment
mkdir /home/deployment/.ssh/
nano /home/deployment/.ssh/authorized_keys
chown deployment:deployment /home/deployment/.ssh/authorized_keys
chmod 600 /home/deployment/.ssh/authorized_keys
5 . Checked login for deployment user. This also might be useful for debug deployment process and run commands as a deployment user.
ssh -i ./id_rsa deployment@{{remote_server_ip}}
6 . Created directories needed for deploy process. Firstly project copied to temporary directory. Then copied to web directory.
cd /var/www
sudo mkdir /var/www/deployment/
sudo mkdir /var/www/deployment/placeholder-service
sudo chown -R deployment:deployment /var/www/deployment/
sudo chmod -R 775 /var/www/deployment/
sudo mkdir /var/www/placeholder-service
sudo chown -R deployment:deployment /var/www/placeholder-service
sudo chmod -R 775 /var/www/placeholder-service
7 . Deployment triggered manually from "Actions" tab.
There are some useful, or just interesting extensions for Github Actions.
It also would be interesting to visit Github Actions Marketplace and check extensions for PHP projects. Finally, I recommend reviewing this list: https://github.com/sdras/awesome-actions.
Demo project is available on github. That's all for today. Thank you for your attention!