Hello and welcome! My name is Cecilia, and in this amazing project, I will demonstrate how to use GitHub Actions to deploy a sample application in App Runner as both a source code and an image-based service.
AWS App Runner is a fully-managed service that makes it easy for developers to quickly deploy containerized web applications and APIs at scale! App Runner can automatically build, scale, and secure the web application in the AWS Cloud. The GitHub Action amazon-app-runner-deploy
uses the App Runner API to build and deploy the application using the App Runner service with the specified configuration.
Let's get started by ensuring that our computer system is up-to-date with the latest tools and software needed for this project.
PRE-REQUISITES
- New or existing GitHub account
- Create a new GitHub repository and then clone it to your local environment. For this example, create a repository called
github-actions-with-app-runner
- Create a new GitHub repository and then clone it to your local environment. For this example, create a repository called
- Install AWS Command Line Interface (AWS CLI) locally. PLEASE NOTE: Alternatively, you may use AWS Cloud9 as your integrated development environment (IDE), AWS CLI is pre-installed.
- Install
node
andnpm
in your local environment. See Node.js & npm for more detailed steps. - An AWS user with access keys. See AWS Access/Secret keys.
- For source-based deployment, the App Runner service requires access to the source image repository. See documentation.
- Set up App Runner service permissions. See IAM Policies & Roles.
In this section, we will create a service role and then associate the AWSAppRunnerServicePolicyForECRAccess
policy with permissions.
- Create
trust-policy.json
file using thetouch
command, then write the following into the trust policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "build.apprunner.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
- Create new role
app-runner-service-role
withtrust-policy.json
:
$ aws iam create-role --role-name app-runner-service-role \
--assume-role-policy-document file://trust-policy.json
- Attach
AWSAppRunnerServicePolicyForECRAccess
IAM policy toapp-runner-service-role
IAM role:
$ aws iam attach-role-policy \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess \
--role-name app-runner-service-role
In order to access your AWS account, the GitHub Actions CI/CD pipeline requires AWS credentials. For security purposes, the credentials must include AWS Identity and Access Management (IAM) policies that provide access to App Runner and IAM resources.
These credentials are stored as GitHub secrets within your GitHub repository, which is located at the Settings > Secrets section.
Create the following secrets
in your GitHub repository:
- Create two secrets named:
AWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
and enter the corresponding key values.
These key values can be located at the IAM service on the AWS management console. Navigate to the IAM user, and locate the Access Keys
section.
PLEASE NOTE It is recommended to follow IAM best practices for the AWS credentials used in GitHub Actions workflows, including:
-
Do not store credentials in your repository code. Use GitHub Actions secrets to store credentials and redact credentials from GitHub Actions workflow logs.
-
Create an individual IAM user with an access key for use in GitHub Actions workflows, preferably one per repository. Do not use the AWS account root user access key.
Next, create an OpenID Connect (OIDC) identity provider in your AWS Account. This will connect AWS and GitHub, so they can exchange tokens.
- Navigate to the IAM console > Identity providers
- Click
Add new provider
- Select OpenID Connect
- Provider URL: https://token.actions.githubusercontent.com
- Click
Get Thumbprint
- Audience:
sts.amazonaws.com
- Click
Add Provider
Next, create a role that GitHub will be able to assume, in order to access the resources it needs to control.
- Go back to IAM and select
Roles
, then clickCreate role
.
- Chose Web Identity, select the Identity provider you created in the previous step, and its audience.
- Click
Next
to add permissions. - Click
Review
, then add a name/description for the role. - Click
Create role
at the bottom of the screen.
Great job! Next, we must edit the trust policy of the role to reduce its scope to your repository.
-
Navigate to the IAM Roles and select the created Role. Choose Trust Relationships and Edit Trust Relationship.
-
Paste the following into the JSON text editor.
IMPORTANT: Remember to replace AwsAccountNumber
with the actual AWS Account number:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "apprunner:*",
"Resource": "*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action":[
"iam:PassRole",
"iam:CreateServiceLinkedRole"
],
"Resource": "*"
},
{
"Sid": "VisualEditor2",
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::<AWSAccountNumber>:role/app-runner-service-role"
},
{
"Sid": "VisualEditor3",
"Effect": "Allow",
"Action": [
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:BatchCheckLayerAvailability",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:GetAuthorizationToken"
],
"Resource": "*"
}
]
}
PLEASE NOTE: To ensure best security practices, it is important to regularly perform the following tasks:
- Rotate the credentials used in GitHub Actions workflows regularly.
- Monitor the activity of the credentials used in GitHub Actions workflows.
Next, on GitHub, create three additional secrets:
AWS_REGION
: enter the Region where the App Runner service needs to be created.AWS_CONNECTION_SOURCE_ARN
: enter the Amazon Resource Name (ARN) of the source code connector in App Runner.ROLE_ARN
: enter the ARN of the IAM role that grants access to the source image repository.
PLEASE NOTE
To locate the ROLE_ARN
, navigate to the IAM service on the AWS management console. Copy the ARN of the app runner service role that was created in the previous steps.
To locate the AWS_CONNECTION_SOURCE_ARN
, navigate to the AWS App Runner
service on the AWS management console. Create a new App Runner service and follow the prompts. Once completed, copy the ARN from the GitHub connections page:
This GitHub Action supports two types of App Runner services:
- source code-based
- container image-based.
In this section, I will demonstrate how we can use these different methods to deploy the sample application in App Runner.
- Begin by create a package.json inside the root directory file by running the
npm init
command. Accept all the default values by pressingEnter
on your keyboard.
$ npm init
- Next, add the
Express
dependency by running the following command:
$ npm install express
- Using your code-editor of choice, access the
package.json
file and add the following "start" script.
"scripts": {
"start": "node index.js"
}
- Remove the default
test
line from thescripts
definition. Save and close the file when complete.
-
Next, create an
index.js
file inside the same directory and add the following code:const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Running on AWS App Runner Service !'); }); const PORT = process.env.PORT || 8080; app.listen(PORT, () => { console.log(`Server listening on port ${PORT}...`); });
- To start the application, run the following command:
$ npm start
- Open the browser and navigate to http://localhost:8080
Excellent work! Now we will deploy the sample application.
- First, create a new directory
.github/workflows
under the root directory - Next, create a new file
pipeline.yml
under the.github/workflows
. - Edit the pipeline.yml file and add the following:
name: Deploy to App Runner - Source # 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: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 # Configure with AWS Credentials 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: Deploy to App Runner id: deploy-apprunner uses: awslabs/amazon-app-runner-deploy@main # Deploy app runner service 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_12 build-command: npm install start-command: npm start port: 18000 region: ${{ secrets.AWS_REGION }} cpu : 1 memory : 2 wait-for-service-stability: true - name: App Runner output run: echo "App runner output ${{ steps.deploy-apprunner.outputs.service-id }}"
This configuration triggers the GitHub Actions CI/CD pipeline when code is pushed to the main branch!
- Next, create
.gitignore
file under git root directory and addnode_modules
to the list of excluded folders. - Lastly, add all the files to your local git repository, commit the changes, and push to GitHub by running the following command from the root directory:
$ git add .
$ git commit -am "Initial commit with pipline"
$ git push
Once the files are pushed to GitHub on the main branch, this automatically triggers the GitHub Actions workflow as configured in the pipeline.yml
file.
You can check the status of the workflow on the AWS App Runner service of the AWS management console.
Upon completion, the App Runner service will be created in the specified AWS Region successfully!
- Great job! You can now examine the newly created service with the
app-runner-git-deploy-service
name configured.
- Next, open your web browser and navigate to the URL mentioned following the
Default domain
section. You should see the service up and running!
In this section, I will demonstrate how we can build the Docker image and push the generated image to Amazon ECR using the aws-actions/amazon-ecr-login@v1
action.
Once the image is available in Amazon ECR, awslabs/amazon-app-runner-deploy@main
will create a new App Runner service and deploy the application inside the container.
- Begin by creating a Dockerfile inside the root directory and add the following lines to the file:
FROM node:12-slim
WORKDIR /usr/src/app
COPY package*.json ./
COPY index.js ./
RUN npm ci
COPY . .
EXPOSE 8080
CMD [ "node", "index.js" ]
- Next, run the following command to create an Amazon ECR repository
$ aws ecr create-repository --repository-name nodejs
IMPORTANT Before proceeding to next step, remove the following files/folders:
node_modules
.github/workflow/pipeline.yml
Next, create a file under .github/workflow
with the name: image-pipeline.yml
- Add the following contents to the
image-pipeline.yml
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 }}"
PLEASE NOTE: Please ensure that the appropriate values are set for the following GitHub Secrets:
-
AWS_ACCESS_KEY_ID
-
AWS_SECRET_ACCESS_KEY
-
AWS_REGION
-
ROLE_ARN
-
Next, add all the files to your local git repository, commit the changes, and push to GitHub
$ git add .
$ git commit -am "Initial commit with image pipline"
$ git push
Once the files are pushed to GitHub on the main branch, this automatically triggers the GitHub Actions workflow as configured in the image-pipeline.yml
file.
Once again, the pipeline execution will take couple of minutes to complete.
Upon completion, the App Runner service will be created in the specified AWS Region successfully!
- Log in to the App Runner console, and you should see a new service with the
app-runner-image-deploy-service
name configured!
- Open the browser and navigate to URL mentioned following the
Default domain
section in the console. You should see the service up and running.
Great job! We have successfully created 2 services in our App Runner deployment.
To avoid incurring future charges, delete all of the resources!
- Log in to the App Runner console, select the
app-runner-image-deploy-service
service, and select Actions → Delete. Repeat the same forapp-runner-git-deploy-service
service, as well.
- Delete the Amazon ECR repository by running the following command:
$ aws ecr delete-repository \ --repository-name nodejs \ --force
-
Next, delete the
IAM role
by running the following commands:Detach IAM policy
$ aws iam detach-role-policy \-policy-arn arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess \-role-name app-runner-service-role
Delete IAM role
$ aws iam delete-role --role-name app-runner-service-role
- Delete the existing “GitHub connection” on the App Runner service.
- Deactivate and remove the IAM user's AWS access key and AWS secrets
Wonderful job! Thank you for viewing my project and following along. We learned how organizations using GitHub as a source code repository can use GitHub Actions to deploy their applications on App Runner.
I hope you enjoyed it! For more details on similar projects and more, please visit my GitHub portfolio: https://github.com/ceciliacloud