DEV Community

Cover image for Terraform — Deploy Nodejs Application with AWS AppRunner
Prashant Bhatasana
Prashant Bhatasana

Posted on

Terraform — Deploy Nodejs Application with AWS AppRunner

In this article, we are talking about How we can deploy Nodejs Application with AWS AppRunner service deployment using Terraform.

Terraform — Deploy Nodejs Application with AWS AppRunner

AWS App Runner is a fully managed service that makes it easy for developers to quickly deploy containerized web applications and APIs, at scale and with no prior infrastructure experience required. Start with your source code or a container image. App Runner automatically builds and deploys the web application and load balances traffic with encryption. App Runner also scales up or down automatically to meet your traffic needs. With App Runner, rather than thinking about servers or scaling, you have more time to focus on your applications.

Prerequisites

  • We require AWS IAM API keys (access key and secret key) for creating and deleting permissions for all AWS resources.
  • Github account and new repository.
  • Terraform should be installed on the machine. If Terraform does not exist you can download and install it from here.

Prepare a Demo NodeJS Application

Create a project directory named demo-application anywhere in your system and make it your current directory:

mkdir demo-application
cd demo-application
Enter fullscreen mode Exit fullscreen mode

Execute the following command within the demo-application directory to initialize your Node.js project with default settings:

npm init -y
Enter fullscreen mode Exit fullscreen mode

Set Up Express with Node.js

To use the Express framework in your application, install it as a project dependency:

npm i express
Enter fullscreen mode Exit fullscreen mode

After that package.json look like below

{
  "name": "demo-application",
  "version": "1.0.0",
  "description": "demo-application",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "express",
    "hello-world"
  ],
  "author": "Prashant_B",
  "license": "MIT",
  "dependencies": {
    "express": "^4.15.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Then, create the entry point of the application, a file named index.js:

touch index.js
Enter fullscreen mode Exit fullscreen mode

Add following code in index.js file.

var express = require('express')
var app = express() 
app.get('/', function (req, res) {
  res.send('Hello World!')
}) 
app.listen(3000, function () {
  console.log('Listening on port 3000...')
})
Enter fullscreen mode Exit fullscreen mode

This app starts a server and listens on port 3000 for connections. The app responds with “Hello World!” for requests to the root URL (/) or route. For every other path, it will respond with a 404 Not Found.

Our demo application was ready now goto GitHub, create new repository and push application source code to GitHub repository.
Let’s move to Terraform
version

To build AWS App Runner, you need to meet the following versions:

  • Terraform v0.12 or higher
  • Latest version of AWS provider (3.42.0) Configuring App Runner in the Terraform AWS Provider

This time I built it with the following version.

$ terraform version
Terraform v1.0.0
on linux_amd64
Enter fullscreen mode Exit fullscreen mode

Amazon Resources Created Using Terraform

A Terraform module is a set of Terraform configuration files in a single directory. Even a simple configuration consisting of a single directory with one or more .tf files is a module. When you run Terraform commands directly from such a directory, it is considered the root module

  1. IAM Module
  • IAM Role and policy
  1. AppRunner Module
  • Auto scaling configuration
  • AWS Apprunner service
  • AWS Apprunner github connection

Create an IAM role to grant to App Runner

Following code create IAM role and policy for Build AWS App Runner service.

The key build.apprunner.amazonaws.com is tasks.apprunner.amazonaws.com to specify and for the service to which AssumeRole is assigned.

After that, AWS has prepared a policy for App Runner, so attach it to the IAM role.

resource "aws_iam_role" "role" {
   name = "test-role"
   assume_role_policy = <<EOF 
{
   "Version": "2012-10-17",
   "Statement": [
     {
       "Action": "sts:AssumeRole",
       "Principal": {
         "Service": [
           "build.apprunner.amazonaws.com",
           "tasks.apprunner.amazonaws.com"
         ]
       },
       "Effect": "Allow",
       "Sid": ""
     }
   ]
 } EOF 
}
resource "aws_iam_role_policy_attachment" "test-attach" {
   role       = aws_iam_role.role.name
   policy_arn = "arn:aws:iam::aws:policy/service-role/AWSAppRunnerServicePolicyForECRAccess"
 }
Enter fullscreen mode Exit fullscreen mode

Create an App Runner

Finally, create an App Runner resource in Terraform.

There are some App Runner related resources, but they are the main resources for actually creating App Runner aws_apprunner_service,
source_configuration

We have 2 ways to deploy App Runner with ECR repository.

  • Deploy App Runner with ECR private repository
  • Deploy App Runner with ECR public repository

Deploy App Runner with ECR private repository

resource "aws_apprunner_auto_scaling_configuration_version" "ngnix-apprunner-autoscaling" {
  auto_scaling_configuration_name = "demo_auto_scalling"
  max_concurrency = 100
  max_size        = 5
  min_size        = 1

  tags = {
    Name = "demo_auto_scalling"
  }
}

resource "aws_apprunner_service" "ngnix-apprunner-service-ecr" {
  service_name = "demo_apprunner"

  source_configuration {
    image_repository {
      image_configuration {
        port = "80"
      }
      image_identifier      = "XXXXX.dkr.ecr.us-east-2.amazonaws.com/nginx-web:latest"
      image_repository_type = "ECR"
    }
    authentication_configuration{
      access_role_arn = aws_iam_role.role.arn
    }
    auto_deployments_enabled = true
  }

  auto_scaling_configuration_arn = aws_apprunner_auto_scaling_configuration_version.ngnix-apprunner-autoscaling.arn

  health_check_configuration {
          healthy_threshold   = 1
          interval            = 10
          path                = "/"
          protocol            = "TCP"
          timeout             = 5
          unhealthy_threshold = 5
        }

  tags = {
    Name = "demo_apprunner"
  }
}
Enter fullscreen mode Exit fullscreen mode

Deploy App Runner with ECR public repository

Note: In this approach we don't need IAM role.

resource "aws_apprunner_auto_scaling_configuration_version" "ngnix-apprunner-autoscaling" {
  auto_scaling_configuration_name = "demo_auto_scalling"
  max_concurrency = 100
  max_size        = 5
  min_size        = 1

  tags = {
    Name = "demo_auto_scalling"
  }
}

resource "aws_apprunner_service" "ngnix-apprunner-service-ecr-public" {
  service_name = "demo_apprunner"

  source_configuration {
    image_repository {
      image_configuration {
        port = var.port
      }
      image_identifier      = "public.ecr.aws/nginx/nginx:latest"
      image_repository_type = "ECR_PUBLIC"
    }
    auto_deployments_enabled = false
  }

  auto_scaling_configuration_arn = aws_apprunner_auto_scaling_configuration_version.ngnix-apprunner-autoscaling.arn

  health_check_configuration {
          healthy_threshold   = 1
          interval            = 10
          path                = "/"
          protocol            = "TCP"
          timeout             = 5
          unhealthy_threshold = 5
        }

  tags = {
    Name = "demo_apprunner"
  }
}
Enter fullscreen mode Exit fullscreen mode

Check the URL of App Runner created by applying

I want to check the URL of the created App Runner as the execution result of the apply command, so output set.

output "app_runner_url" {
  value = aws_apprunner_service.example.service_url
}
Enter fullscreen mode Exit fullscreen mode

After that, just run the following commands.

terraform init
terraform plan
terraform apply

it will take 2 to 3 minutes to complete the execution.
When the execution is completed, the URL will be displayed as shown below, so let’s access it.

app_runner_url = "xxxxx.us-east-2.awsapprunner.com/"
Enter fullscreen mode Exit fullscreen mode

Thank you for reading, if you have anything to add please send a response or add a note!

Top comments (1)

Collapse
 
deantray profile image
Dean Hiller

assume_role_policy = <<EOF

gives an error


│ Error: Invalid expression

│ on app_runner.tf line 3, in resource "aws_iam_role" "role":
│ 3: assume_role_policy = <<EOF

│ Expected the start of an expression, but found an invalid expression token.