Exploring the Future of Serverless with Sheen Brisals: Why It's Becoming the New Norm
Azure functions or the Azure Function App is the function as a service offering from Microsoft Azure. Even though comparable to Lambda, Azure does things notably different from the pioneer of serverless functions. One of the fundamental differences lies in the fact that, unlike Lambda, individual functions aren’t always completely isolated from each other.
Since the Function App acts as an umbrella for all its underlying functions, they will all share the same runtime, configurations, environment variables, and other resources. There can be up to 100 Function Apps in a Consumption plan. All functions under a Function App will be accessible via the Function App’s endpoint. Eg., myFnApp.azurewebsites.net/myFn01
Azure Functions can be invoked via triggers and bindings which seamlessly integrate to a multitude of Azure services including Storage Queues, Azure Service Bus, Cosmos DB, etc.
- A list of all the available bindings hand be found https://docs.microsoft.com/en-us/azure/azure-functions/functions-triggers-bindings?tabs=csharp#supported-bindings “List of supported bindings”” target=”_blank”>here
In this post, we will see how to set up, locally test, deploy and monitor Azure functions part of a Function App.
Setup
One way to create a Function App is via the Azure portal. The pre-requisites, like for any other Azure service, includes a Resource Group and a Storage Account. It is possible to set them up on the fly, as we create the Function App, through the Azure portal. You have to specify the runtime stack, node.js in our case, the version we want to use, and the Azure region to deploy the service in.
We can also specify hosting options like the operating system (Linux / Windows) and the hosting plan. We will go with Linux and the pay-per-use Consumption plan.
Once created the Function App dashboard allows us to configure and monitor everything including Access Control, Custom Domains, Application Insights, logs, and metric among other things.
Working with Azure functions
One of the things I found helpful when working with Azure functions is the Azure Functions extension from the Azure Tools extension pack for VSCode. Install the extension, connect your Azure account and you are good to go.
It allows us to create Azure functions of any binding type with a couple of clicks and generates the template with the default configurations for us. This can also be achieved via the Azure CLI.
The httpTrigger
binding type can be used similarly to a Lambda connected to an API Gateway. The function.json holds all the function-specific configurations including allowed HTTP methods.
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
Let’s create a simple function which takes the name from the request body and sends Hello <name>
as the response.
module.exports = async function (context, req) {
try {
context.log("req", req);
let { name } = req.body;
context.res = {
body: `Hello ${name}`
};
context.done();
} catch (err) {
context.log("errors: ", errors);
context.res = {
status: 400,
body: errors
};
context.done();
}
};
To test the function locally, we can either use the native VSCode debugger or the Azure CLI command:
func host start --javascript
The value property of local.settings.json
can be used to store and access environment variables when developing in the local environment.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"API_KEY": "abcd"
},
"Host": {
"LocalHttpPort": 7071,
"CORS": "*"
}
}
Once deployed these env variables will have to be added to applications settings for the Function App. This can be done via the Azure Functions extension as well.
Deploying the function
The Azure Functions extension and the CLI enable us to directly deploy the functions to our Azure Function App. But this will overwrite the whole Function App every time with no source control. Instead, we will be using GitHub actions to help us deploy the Function App when changes are pushed.
Let’s start by creating a workflow YAML file that will hold the deployment config under the .github/workflows/
directory. The steps run by the workflow involves setting up the node environment, installing the dependencies specified, building the Function App, and finally deployment. The Publish Profile of the Function App which can be found in the Function App dashboard must be added as a secret to the GitHub account that hosts the repository.
- Refer this article to know more about using GitHub actions with Azure Function App.
# .github/workflows/fnDeploy.yml
name: Deploy Node.js project to Azure Function App
on:
[push]
env:
AZURE_FUNCTIONAPP_NAME: abcdFnApp # set this to your application's name
AZURE_FUNCTIONAPP_PACKAGE_PATH: "." # set this to the path to your web app project, defaults to the repository root
NODE_VERSION: "12.x" # set this to the node version to use (supports 8.x, 10.x, 12.x)
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: "Checkout GitHub Action"
uses: actions/checkout@master
- name: "Login via Azure CLI"
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Setup Node ${{ env.NODE_VERSION }} Environment
uses: actions/setup-node@v1
with:
node-version: ${{ env.NODE_VERSION }}
- name: "Resolve Project Dependencies Using Npm"
shell: bash
run: |
pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}'
npm install
npm run build --if-present
npm run test --if-present
popd
- name: "Run Azure Functions Action"
uses: Azure/functions-action@v1
id: fa
with:
app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
publish-profile: ${{ secrets.SCM_CREDENTIALS }}
Once deployed the function endpoint can be found in the Azure function dashboard
Logs and monitoring
Invocation logs can be found under the monitor section of the function dashboard. One issue that I always faced when working with Azure functions is the time it takes for the logs to appear in the invocation tab. It usually takes about 5 minutes before the log shows up which can be frustrating when trying to debug in real-time.
One alternative to this though is the ability to connect to the log streams/application insights. Once connected we will be able to see real-time logs to help debug and monitor. But this, even though works well for the most part, at times can be unreliable. Sometimes the logs will be partial while during others there wouldn’t be any that shows up even after being connected to the stream.
References
For questions and suggestions, feel free to reach out to us on Twitter