Deploying a Fastify Application on Azure

How to set up infrastructure on Azure and deploy your Fastify application

Fastify users have an easy way to deploy their applications on Azure using the Webapp service and set them up using Terraform.

In this article, we will demonstrate how to:

  • Set up an Azure Webapp infrastructure as a code
  • Set up Github Actions to deploy our application
  • Take down the infrastructure

Why should I use Azure Webapp?

The Webapp service is one of the most popular products within Azure. It offers a range of services and tools required to build enterprise-ready apps quickly, accelerating the time to market.

Besides, even though we are working with a PaaS platform, it is possible to scale your infrastructure as needed, and it's simple to do.

Additionally, it is very easy to create the infrastructure and deploy applications in many languages. In this proof of concept, we will deploy a Fastify app running on Node.js 16.

Prerequisites

Fork and clone the Github repository

Repository structure

Before we proceed with creating the infrastructure, let's understand the structure of the repository and what every important file does.

Plain Text
├── README.md
├── app          		     <- application folder       
│   ├── README.md
│   ├── index.js
│   ├── package-lock.json
│   ├── package.json
│   ├── process.json
│   └── web.config
├── main.tf                  <- primary entrypoint of Terraform
├── outputs.tf		         <- desired outputs
├── publish.profile.xml	     <- generated Azure publish profile
├── rg.tf			         <- resource group and application service plan
├── state.sh			     <- script to create storage bucket for tfstate
├── variables.tf		     <- store variables
└── webapp.tf		         <- creation of webapp

There are two important files which are critical to the application described in this article.

1. rg.tf

Every resource on Azure needs to be in a resource group . This will be created by the rg.tf file with a random name, on azurerm_resource_group block.

JavaScript
resource "azurerm_resource_group" "rg" {
  name     = "rg${random_integer.ri.result}"
  location = var.location
}

And the application service plan .

JavaScript
# Create the Linux App Service Plan
resource "azurerm_app_service_plan" "appserviceplan" {
  name                = "serviceplan${random_integer.ri.result}"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  kind = "Linux"
  reserved = true
  sku {
    tier = "Standard"
    size = "S1"
  }
}

It is on the service plan that we will define the machine type that will host your application. If you want to deploy this code to production, you can upgrade the machine tier, add multi-zone hosting and enable scaling.

For a full list of options for the application service plan , look at the Terraform documentation in this module.

2. webapp.tf

Finally, the webapp.tf file creates our Webapp.

JavaScript
# Create the web app, pass in the App Service Plan ID, and deploy code from a public GitHub repo
resource "azurerm_app_service" "webapp" {
  name                = "webapp-${random_integer.ri.result}"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  app_service_plan_id = azurerm_app_service_plan.appserviceplan.id
  site_config {
    linux_fx_version  = "NODE|16-lts"
  }
  provisioner "local-exec" {
    command = "az webapp deployment list-publishing-profiles --resource-group ${azurerm_resource_group.rg.name} --name ${azurerm_app_service.webapp.name} --xml > publish.profile.xml"
  }
}

In this sample, we are deploying a Fastify application running on Node.js 16.x. The Node version is defined on option linux_fx_version, this can be changed as needed.

There is a final block called a local-exec Azure CLI command. This command reads and generates a local publish profile file, that will be necessary to deploy the application.

The other options are self-explanatory: defining name, location, associated resource group and service plan.

Azure Webapp supports a variety of options like logging and number of workers. In this example, the goal is to keep it simple. View the documentation for a full list of options.

Building the infrastructure

After forking and cloning the Github repo, go to the cloned repository folder in your favourite terminal app.

Now you need to follow these steps:

1. Login to Azure

The first thing is to login using Azure CLI. We need to do this in order to run a script to create some objects to store in Terraform tfstate.

Plain Text
az login

You will be redirected to the browser window to complete the current login process. Once logged in, just close the tab and head back to the terminal.

2. Setup Terraform backend

On the Github repository, there is a script that will create a storage account and a storage container with a random name, which will host our tfstate file.

It's possible to use a local tfstate file, but this option isn’t recommended, because the management of our infrastructure will depend on a file on your local machine.

Run the script:

Plain Text
sh state.sh

After the storage container creation, your main.tf  file will be automatically populated with the updated information.

JavaScript
# Configure the Azure provider
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 2.65"
    }
  }
    required_version = ">= 1.0.0"
    backend "azurerm" {
        resource_group_name  = "tfstate"
        storage_account_name = "tfstate11111"
        container_name       = "tfstate"
        key                  = "terraform.tfstate"
    }
}
provider "azurerm" {
  features {}
}

3. Create Services

To build everything, just apply the terraform scripts:

Plain Text
$ terraform apply
Acquiring state lock. This may take a few moments...

When terraform finishes the plan, review the resources that will be created and confirm by typing yes .

After a few minutes, you will receive an output like the following, with a different hostname:

Plain Text
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:

hostname = "webapp-11111.azurewebsites.net"

Take a note because this is the address of our application. To confirm everything is fine, make a quick test accessing https://.azurewebsites.net

You will see a website like this:

This means that your infrastructure is up and running, just waiting for an application deployment.

Deploying the application

In this article, we are deploying a sample hello world Fastify application. The source code is located on the ./app folder of the repository.

You just need to do two steps on your own Github repository to deploy the app on Azure Webapp service.

Understanding Publish Profile

The application deployment on Azure Webapp depends on the publish profile to authorise access to the service. Every time you create a Webapp, a new publish profile will be created for this app.

In this case, the publish profile is generated by our webapp.tf   terraform file, under the block:

JavaScript
provisioner "local-exec" {
    command = "az webapp deployment list-publishing-profiles --resource-group ${azurerm_resource_group.rg.name} --name ${azurerm_app_service.webapp.name} --xml > publish.profile.xml"
  }

Every time you create an infrastructure, a new publish.profile.xml file is created.

Setup secrets

On Github web, go to your repository, then in Settings -> Secrets click Actions

Click on the New Repository Secret button:

Create a secret named AZURE_WEBAPP_PUBLISH_PROFILE . The content of this secret will be the content of the file publish.profile.xml , under the infrastructure repository.

Fill in the fields like in this sample and click Add secret .

Go to the Actions tab:

And click the button to enable actions.

Change webapp name.

In the repository, there is a file under ./github/workflows called workflow.yml .

We need to edit this file and change the variable AZURE_WEBAPP_NAME to the name of our app. This name is a prefix of the generated URL on Terraform outputs, where webapp-11111.azurewebsites.net is the full URL and webapp-11111 is the app name.

Bash
env:
  AZURE_WEBAPP_NAME: webapp-11111      # set this to your application's name  
  AZURE_WEBAPP_PACKAGE_PATH: './app'   # set this to the path to your web app project, defaults to the repository root
  NODE_VERSION: '16.x'                 # set this to the node version to use

When deploying a custom application, feel free to change the NODE_VERSION if needed. This is the Node image that will run the build job.

Now, just push the changes to your repository and let's see the magic.

Viewing the workflow's activity

On the Github web application, go to your repository and click on the Actions tab.

Click on the current workflow to follow up deployment.

Check to see if all steps are complete.

Access your application again: https://.azurewebsites.net

And see your deployed code.

Now our application is up and running, with CI/CD. When you make any changes, just push into your Github repository and Github Actions deploys it.

Bring down the infrastructure.

When you don’t need this infrastructure anymore, just go to your local folder containing the infrastructure repository and run:

Plain Text
$ terraform destroy
Acquiring state lock. This may take a few moments...

Review the changes and type yes. When you need to set up everything again, just repeat the steps in this article. Related Read: Getting DevSecOps Right in Azure

Conclusion

Azure Webapp is a pretty simple way to host our application with low infrastructure management. You can easily develop your idea using the free tier + Github and stay free until you need to scale up.

Using Fastify, we have a better handle on the resources of our infrastructure, because it’s a performance-focused framework. This can help developers keep hosting fees at free/low cost tiers.

Insight, imagination and expertly engineered solutions to accelerate and sustain progress.

Contact