Deploy using GitHub Actions¶
This section will describe how to set up your CI/CD pipeline using GitHub Actions including some examples.
GitHub Actions is the preferred CI/CD platform for MACH composer
While any CI/CD platform can run MACH composer, our examples and tooling will focus around GitHub Actions, as this is the preferred platform for many of our clients, and provides the best developer experience.
In case you use a different CI/CD solution, take the below pipelines as examples. Essentially, a CI/CD pipeline should run a combination of the `mach-composer plan` and `mach-composer apply` commands.
MACH stack deployment¶
This page describes how to deploy your MACH composer configuration to your cloud provider. We recommend to use a PR workflow whereby changes are done via a PR which allows additional rules (e.g. approval flows).
Log outputs¶
Mach Composer can be configured to output logs in a more Github-friendly way. This can be done by adding the --github
flag to the mach-composer plan
and mach-composer apply
commands. Terraform outputs will then be grouped in
accordions in the Github Actions logs.
Authenticating with your cloud provider¶
For deploying to a cloud provider (e.g. AWS, Azure or GCP) as we recommend to use OpenID Connect. See how this works with GitHub at security hardening your deployments
Example¶
name: Deploy Test
on:
pull_request:
types: [opened, synchronize, closed]
paths:
- 'main.yml'
concurrency: test
env:
TF_PLUGIN_CACHE_DIR: ${{ github.workspace }}/.terraform.d/plugin-cache
MACH_COMPOSER_VERSION: 2.5.4
AWS_DEPLOY_ROLE: arn:aws:iam::<AWS_ACCOUNT_ID>:role/mach-deploy-role
AWS_DEPLOY_REGION: "eu-west-1"
AWS_PLAN_BUCKET: "bucket name to store terraform plans"
CONFIG_FILE: "main.yml"
jobs:
plan:
runs-on: ubuntu-latest
if: github.event.pull_request.merged != true && github.base_ref == 'main'
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
pull-requests: write
steps:
- uses: actions/checkout@v3
- name: Prepare credentials
run: |
git config --global url."https://oauth2:${{ secrets.ORG_REPO_TOKEN }}@github.com".insteadOf https://github.com
- name: Install terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.1.7
- name: Create Terraform Plugins Cache Dir
run: mkdir --parents $TF_PLUGIN_CACHE_DIR
- name: Cache Terraform Plugins
uses: actions/cache@v2
with:
path: ${{ env.TF_PLUGIN_CACHE_DIR }}
key: ${{ runner.os }}-terraform-${{ hashFiles('**/.terraform.lock.hcl') }}
- name: Install MACH composer
uses: mach-composer/setup-mach-composer@main
with:
version: ${{ env.MACH_COMPOSER_VERSION }}
- name: Install sops
uses: mdgreenwald/mozilla-sops-action@v1.4.1
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.AWS_DEPLOY_ROLE }}
aws-region: ${{ env.AWS_DEPLOY_REGION }}
- name: MACH composer plan
uses: mach-composer/plan-action@main
with:
filename: ${{ env.CONFIG_FILE }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Store terraform plan
run: aws s3 cp --sse AES256 --recursive --exclude '*' --include "deployments/*/terraform.plan" . s3://${{ env.AWS_PLAN_BUCKET }}/${{ github.event.pull_request.number }}/
deploy:
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true && github.base_ref == 'main'
environment:
name: test
url: "<your env url>"
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
steps:
- uses: actions/checkout@v3
- name: Prepare credentials
run: |
git config --global url."https://oauth2:${{ secrets.ORG_REPO_TOKEN }}@github.com".insteadOf https://github.com
- name: Install terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.1.7
- name: Create Terraform Plugins Cache Dir
run: mkdir --parents $TF_PLUGIN_CACHE_DIR
- name: Cache Terraform Plugins
uses: actions/cache@v2
with:
path: ${{ env.TF_PLUGIN_CACHE_DIR }}
key: ${{ runner.os }}-terraform-${{ hashFiles('**/.terraform.lock.hcl') }}
- name: Install MACH Composer
uses: mach-composer/setup-mach-composer@main
with:
version: ${{ env.MACH_COMPOSER_VERSION }}
- name: Install sops
uses: mdgreenwald/mozilla-sops-action@v1.4.1
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ env.AWS_DEPLOY_ROLE }}
aws-region: ${{ env.AWS_DEPLOY_REGION }}
- name: Retrieve terraform plan
run: aws s3 cp --sse AES256 --recursive s3://${{ env.AWS_PLAN_BUCKET }}/${{ github.event.pull_request.number }}/ .
- name: Run MACH Composer apply
run: mach-composer apply --auto-approve -f ${{ env.CONFIG_FILE }}
- name: Cleanup terraform plan
run: aws s3 rm --recursive s3://${{ env.AWS_PLAN_BUCKET }}/${{ github.event.pull_request.number }}/
Component deployment¶
For the component CI pipeline we need to be able to test, package and upload the function app ZIP file.
Example¶
Example GitHub Action to package and deploy a component on AWS.
name: Package and upload
on:
push:
branches:
- main
env:
PACKAGE_NAME: my-component
AWS_BUCKET_NAME: my-lambda-bucket
jobs:
package:
name: Package Lambda function
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Artifact Name
id: artifact-name
run: echo "::set-output name=artifact::$(echo $PACKAGE_NAME-${GITHUB_SHA:0:7}.zip)"
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Cache modules
uses: actions/cache@v2
with:
path: '**/node_modules'
key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }}
- name: Install dependencies
run: yarn
- name: Package
uses: dragonraid/sls-action@v1.2
with:
args: --stage prod package
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.MACH_ARTIFACT_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.MACH_ARTIFACT_AWS_SECRET_ACCESS_KEY }}
aws-region: eu-central-1
- name: Upload
run: aws s3 cp .serverless/${{ env.PACKAGE_NAME }}.zip s3://${{ env.AWS_BUCKET_NAME }}/${{ steps.artifact-name.outputs.artifact }}