Two appspec.yml files, one repo

I probably had it coming after my previous post ranting about DevOps.

Among the first tasks I had for our capstone project Asteroid Crusaders was setting up the continual deployment from our Github to our AWS cloud. The goal was to use Github Actions to make any change to the main branch automatically run on our EC2 instance. We aren’t using ECS for this particular case because as far as we can tell that would require a load balancer that we just don’t need. Hence, we were going to use AWS CodeDeploy. To use CodeDeploy you set up a named task that deploys the repo to a group of servers identified by a tag, and then CodeDeploy follows the instructions in the appspec.yml file in the repository to launch your code. You can call that task from Github Actions and give it a commit hash (once the proper IAM roles are sorted).

Aside: before your EC2 instance can use CodeDeploy, you have to ssh into the instance, install wget, then use wget to download the CodeDeploy agent and install it. Which is ridiculous.

Anyway, appspec.yml files look like this:

version: 0.0
os: linux
files:
  - source: backend/
    destination: /home/ec2-user/backend/
hooks:
  AfterInstall:
   - location: backend/deploy/setup.sh
     timeout: 300
     runas: root
  ApplicationStart:
   - location: backend/deploy/run.sh
     timeout: 300
     runas: root

The problem for this with Asteroid Crusaders is that we have two EC2 instances, one for the frontend and one for the backend, we have one git repo with folders dividing up the code for each, and CodeDeploy reads the file ‘appspec.yml’ at the root of the repo. How does one get a particular script to run on a particular server? A quick trip to StackOverflow told me the solution is to have two appspec files – e.g. appspec-frontend.yml and appspec-backend.yml – and rename the appropriate one in a job in the CD process before sending it on to the proper CodeDeploy task.

So I happily added my separate appspec files and a ‘mv backend/deploy/appspec-backend.yml appspec.yml’ into my Github action and thought I would be good to go.

Nope.

The problem with that plan is that CodeDeploy takes a commit hash and the hash that my Github action knew was the one that triggered the action – my mv command was not committed anywhere. So I had to commit after mv, and then find the hash of that commit. This is where I learned that Github actions can’t commit to a protected branch, like when you require a pull request to merge into main. So I have to mv the appspec file, then commit to an unprotected branch, then get the hash, then send that hash to CodeDeploy using the slightly obtuse Github action variable system.

Here is my final functional Github action for the backend:

name: Backend CI/CD

on:
  push:
    branches: [ main ]
    paths:
    - 'backend/**'
  pull_request:
    branches: [ main ]
    paths:
    - 'backend/**'

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:     
  setup-repo:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
    
      - name: Pick appspec file
        id: appsec-set
        run: |
          git config --global user.email "GithubCD@nowhere.com"
          git config --global user.name "GithubCD"
          git remote set-url origin https://sntwo:${{ github.token }}@github.com/sntwo/asteroidcrusaders.git
          git push -d origin auto-backend-deployment
          git checkout -b auto-backend-deployment
          mv backend/deploy/appspec-backend.yml appspec.yml
          git add appspec.yml
          git commit -m 'production backend deployment'
          git push --set-upstream origin auto-backend-deployment
          git fetch
      - name: get sha
        id: psha-set
        run: |
          echo "::set-output name=psha::$(git log origin/auto-backend-deployment | head -1 | tail -c 41)"
      
      #Push to AWS
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-west-2

      - name: Create CodeDeploy Deployment
        id: deploy
        run: |
          aws deploy create-deployment \
            --application-name backend-server-git \
            --deployment-group-name backend-server-group \
            --deployment-config-name CodeDeployDefault.OneAtATime \
            --github-location repository=${{ github.repository }},commitId=${{steps.psha-set.outputs.psha}}
Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published. Required fields are marked *