github actions deploy web application with apprunner

How To Deploy Application Using GitHub Action to AWS Apprunner In 3 Steps

introduction

This walk through will teach you how to use GitHub actions to deploy your changes to Apprunner. This is especially useful if you will be using the image based deployment. So, rather than manually building the docker image and then push to the repository, before AWS Apprunner will pick it up for deployment.

We will see how with just one push to the GitHub repository, GitHub Actions will build the image, push it to ECR and then run the Apprunner to deploy the application. Also, we will see how to use this GitHub Actions works when using the Source Code method to deploy application in AWS Apprunner.

One interesting thing about working with cloud technology is the ability to automate most of the tasks. And this is just one very good use case.

PREREQUISITE

To follow this tutorial, you will need:
1. A user with permissions to ECR, Apprunner and IAM.
2. The secret and access key of the user. Which you can create from your IAM console
3. An Elastic Container Repository. You can create a quick one here
4. A GitHub repository. Follow the tutorial to create one. You can also clone the repository for this tutorial from here.

Once you have those, let’s get the ball rolling. We will begin by using the Source Code method to deploy to Apprunner using GitHub Actions. However, you can skip it to use image method to deploy the application.

NB: The web application used was developed and listed for free download at startbootstrap.com. Start Bootstrap creates free, open source, MIT license, Bootstrap themes, templates, and code snippets for you to use on any project

connect source code to github actions

We begin by first generating the Connection ARN of the Apprunner service. Here, we only need to create a connection and not configure the Service further because GitHub actions will create it. We will use the ARN of the connection in the GitHub secrets later. There is a previous post showing how to manually create the AWS Apprunner service with Source Code and Docker image.

Click Source Code Repository. Select the Add New.

Select source code repository for apprunner service settings

In the next window, use the Install Another to install the Apprunner app on your GitHub account. However, if you follow this tutorial, you probably will have one, just click the dropdown on GitHub app to select it.

Click Next. It will take you to the Service configuration window. Close the window and expand the side panel.

Create a GitHub connections for apprunner

On the side panel, select GitHub connections, and you will see the connection you create in the previous step. Take note of the ARN as you will need it later.

The GitHub connect ARN
Create IAM ROLE FOR APPRUNNER

Now, we need to create an IAM Role for the Apprunner service. We will use the Custom Trust Policy and select the sts:AssumeRole and sts:TagSession action.

For the Principal, us the ARN of the AWS user with the ECR and Apprunner permissions. You can paste in the JSON below for this policy. Click Next.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::00000000000:user/userName"
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
    ]
}
Custom IAM trust policy for apprunner service

On the next screen, attach the AWSAppRunnerFullAccess and AWSAppRunnerServicePolicyForECRAccess permissions to the role you are creating.

Click Next.

attach the AWSApprunnerFullAccess and AWSAppRunnerServicePolicyForECRAccess to deploy apprunner application with github

Add role name and review the policy and permissions attached to this role. Then click Create Role.

Name the service role for apprunner

To see more detail about the role, click on the role name. Take note of the role ARN. You will need it for the GitHub secrets later.

ARN service role
CREATE IAM POLICY FOR USER

For the role we create above to work properly, it needs to be attached to the user we will use for GitHub secrets authentication. Therefore, click on the user name, under Permissions, Click Add Permissions and select Create Inline Policy

Create User policy for IAM

Using the visual editor, select the STS service, add TagSession and AssumeRole, then under the Resources, paste the ARN of the service role you create in the previous step.

Add the Tagging and AssumeRole Actions for STS policy.

To use JSON to create the policy, add the json code below

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ],
            "Resource": "arn:aws:iam::0000000000:role/apprunner-role-for-web-app"
        }
    ]
}
ADD SECRETS TO GITHUB

Once you get that settled, you will need to add some sensitive information to authenticate and authorize GitHub action to access the Apprunner service and deploy the application. Add the Apprunner GitHub connection ARN, AWS Region, Secret and Access key of the user that has the sts policy create earlier, and the service role ARN create earlier too.

GitHub Secrets will encrypt these information and will only decrypt it only during runtime thereby the credentials are protected from unathorize access and use.

In your GitHub account, locate the Organization and the Repository containing the source code. Click the Setting > Secrets and Variables > Actions > New Repository Secret.

Create new repository secrets to authenticate GitHub action for Apprunner service

Type AWS_CONNECTION_SOURCE_ARN in the Name* box, and then paste in the Apprunner GitHub connection in the Secret* box. Click on Add Secret.

Add new GitHub secret

Repeat the step above for AWS_ACCESS_KEY_ID (put the user access key ID), AWS_REGION (add the region you want Github Actions to deploy Apprunner service), AWS_SECRET_ACCESS_KEY (the secret key of the user), and ROLE_ARN (the service role ARN created earlier)

List of GitHub secrets
CREATE THE .GITHUB/WORKFLOWS DIRECTORY AND ADD APPRUNNER YAML FILE

The next step and final step to complete the configuration for GitHub Actions to deploy your web application to AWS AppCenter is to add the GitHub Action configuration file.

The configuration file is a yaml file that contains the steps and commands that GitHub will run on our behalf without any further input from us. GutHub Actions will pick up the credentials from the secrets, decode it, temporarily access our AWS account, deploy the application to Apprunner, and then sign out of the account.

Using the GitHub dashboard, click the New Folder button, the create .github/workflows directory. Create an apprunner.yml file in the .github/workflows directory. Then add the yaml configuration to it.

Create the apprunner yaml file for Github deploy

Using a command-line, run

sudo mkdir .github && sudo mkdir .github/workflows
sudo nano .github/workflows/appcenter.yml
make .github/workflows directory command line
name: Deploy to App Runner
on:
  push:
    branches: [main] # Trigger workflow on git push to main branch
  workflow_dispatch: # Allow manual invocation of the workflow

jobs:
  deploy:
    runs-on: ubuntu-latest
    # These permissions are needed to interact with GitHub's OIDC Token endpoint.
    permissions:
      id-token: write
      contents: read

    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1-node16
        with:
          # Use GitHub OIDC provider
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          role-to-assume: ${{ secrets.ROLE_ARN }}
          aws-region: ${{ secrets.AWS_REGION }}
          role-duration-seconds: 1200

      - name: Deploy to App Runner
        id: deploy-apprunner
        uses: awslabs/amazon-app-runner-deploy@main
        env:
          SERVER_PORT: 3000
        with:
          service: app-runner-git-deploy-service
          source-connection-arn: ${{ secrets.AWS_CONNECTION_SOURCE_ARN }}
          repo: https://github.com/${{ github.repository }}
          branch: ${{ github.ref }}
          runtime: NODEJS_16
          build-command: npm install
          start-command: npm start
          port: 3000
          region: ${{ secrets.AWS_REGION }}
          cpu : 1
          memory : 2
          # Deprecated: wait-for-service-stability: true
          # The new way to control service stability timeout
          wait-for-service-stability-seconds: 600
          copy-env-vars: |
            SERVER_PORT
#          tags: >
#            { "env": "test" }

      - name: App Runner URL
        run: echo "App runner URL ${{ steps.deploy-apprunner.outputs.service-url }}"

IMPORTANT: Take note of the PORT, runtime, and the commands. Modify them to suite your environment.

Once you are done, commit the file to GitHub repository.

git add .
git commit -m "commit message"
git push

Click on the Actions tab in your GitHub repository to see the job running in GitHub. After a while, you will see the check showing that the Action run successfully.

Success deploy application from Github to Apprunner
CHECK THE APPRUNNER SERVICE TO CONFIRM DEPLOYMENT

Go back into you AWS Console, in the Apprunner service, you will find the newly deployed application from GitHub. Click the service name to reveal the details including the Default domain to access your application.

apprunner url

Well done coming so far. Now you will only do one push, and Github Actions will update and deploy your web application in your AWS Apprunner service

USE IMAGE TO DEPLOY TO APPRUNNER USING GITHUB ACTIONS

Let’s use a docker image for the same process of letting GitHub Actions deploy our web application to AWS Apprunner service. Remember to create your AWS Elastic Container Registry to use this method.

CREATE AWS ELASTIC CONTAINER REGISTRY

Once you create the registry and repository on AWS ECR, click on the name and take note of the repository name and the image tag. You will need to add them in the GitHub Actions yaml configuration file.

aws ecr details
create iam role and attach user policy for docker

You will create the IAM Trusted Entity service role for the Apprunner service and also attach an sts policy to the user just like for the Source Code method above.

So, follow the steps outlined in Create IAM ROLE FOR APPRUNNER, CREATE IAM POLICY FOR USER, and ADD SECRETS TO GITHUB above.

For IAM ROLE FOR APPRUNNER there is a slight change in the principal. Use the "Service": "build.apprunner.amazon.com" as the principal.

Just like in JSON configuration below. Remember to attach the AWSAppRunnerFullAccess and AWSAppRunnerServicePolicyForECRAccess permissions too.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Statement1",
            "Effect": "Allow",
            "Principal": {
                "Service": "build.apprunner.amazonaws.com",
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
    ]
}

The other two configurations remain the same as what is used in the Source Code Method.

ADD DOCKERFILE TO YOUR PROJECT

Since you will deploy the application from GitHub Actions to Apprunner using image, it is expected we have a Dockerfile in the root of your project source code.

Dockerfile at root of project directory

Create a Dockerfile and paste the configuration there. sudo nano Dockerfile

FROM node:16-alpine AS build

WORKDIR /app

RUN chmod -R 755 /app

COPY package.json /app

RUN npm install

COPY . .

FROM nginx AS runner

WORKDIR /usr/share/nginx/html

COPY --from=build /app/dist/ /usr/share/nginx/html

EXPOSE 80
ADD THE YAML CONFIGURATION FOR IMAGE DEPLOYMENT

Once you added the Dockerfile, the next step is to create the yaml configuration file that GitHub will use to build and push the application to ECR and then deploy it to AWS Apprunner. See the steps on CREATE THE .GITHUB/WORKFLOWS DIRECTORY AND ADD APPRUNNER YAML FILE in the steps above to create the directory and add it to .github/workflow/ directory.

Add the configuration to your dockerapprunner.yaml file.

name: Deploy to App Runner - Image based # Name of the workflow
on:
  push:
    branches: [ main ] # Trigger workflow on git push to main branch
  workflow_dispatch: # Allow manual invocation of the workflow
jobs:  
  deploy:
    runs-on: ubuntu-latest
    
    steps:      
      - name: Checkout
        uses: actions/checkout@v2
        with:
          persist-credentials: false
          
      - name: Configure AWS credentials
        id: 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: ${{ secrets.AWS_REGION }}     

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1        

      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: nodejs
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"  
          
      - name: Deploy to App Runner
        id: deploy-apprunner
        uses: awslabs/amazon-app-runner-deploy@main        
        with:
          service: app-runner-image-deploy-service
          image: ${{ steps.build-image.outputs.image }}          
          access-role-arn: ${{ secrets.ROLE_ARN }}
          runtime: NODEJS_12          
          region: ${{ secrets.AWS_REGION }}
          cpu : 1
          memory : 2
          port: 8080
          wait-for-service-stability: true
      
      - name: App Runner output
        run: echo "App runner output ${{ steps.deploy-apprunner.outputs.service-id }}" 

Add, commit and push your changes to GitHub.

Git add commit and push the app to github to deploy to apprunner service

The GitHub actions successfully.

successful deploy of the app to apprunner from github actions
CONFRIM DEPLOYMENT WITH IMAGE

Go to the AWS Apprunner service in your console to confirm that GitHub Actions correctly deploy the web application.

application url in aws apprunner console

Grab the default domain and paste in your web browser to see the web application deployed with GitHub Actions to AWS Apprunner.

the application github action deploy to apprunner service.
use custom domain

It is not enough to use the default domain as your production URL to your customers, therefore, I recommend you create a CNAME or Alias Name record for the default domain to redirect to your custom domain and secure it with a SSL certificate. With that, your application will carry your business identity on the internet.

troubleshooting apprunner deployment using github actions
  1. ERROR: ***username is not authorized to perform: sts:TagSession on resource:
    ***username is not authorized to perform: sts:AssumeRole on resource:
    SOLUTION: Add the STS inline policy (sts:AssumeRole and sts:TagSession) to the user that uses the secret and access key connected to GitHub secrets.
  2. ERROR: Error: The requested DurationSeconds exceeds the MaxSessionDuration set for this role
    SOLUTION: Add the role-duration-seconds to the YAML file. Or increase the timeout of the max session duration in the yml file to 1200 seconds.
    role-duration-seconds: 1200

Posted

in

by

Tags:

Comments

Leave a Reply

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