Deploying Azure Functions using NestJS and Docker

2 min. read

We love serverless platforms for their ability to build scalable applications using less code, which not only saves our developers time but also saves our clients money. We're fortunate to have test-driven multiple vendors, and Azure Functions ranks high on our list for ease of deployment and robust management tools.

On a recent project, we took a serverless approach for a particular client who was running on Azure Cloud with databases provided by MongoDB Atlas, and utilized the Azure AKS Kubernetes platform for serving their APIs.

Azure Functions seemed like the natural fit for some of this client's less frequently used, but resource-intensive tasks. While this is a great combination of technologies, we encountered a few challenges, and we wanted to share our experience in this article.  

Challenges with this client's current environment:

  • Connection issues. The Azure functions Consumption plan running on Linux is unable to connect to the MongoDB Database in Atlas over the private connection.
  • Intricate container distribution. We wanted to stick with one operating system between Kubernetes and Serverless so we chose to run Linux in Docker.

Getting Started

To enable Azure Functions to access MongoDB private endpoints, we need to get our APIs running on a standard or premium plan. For Linux, this means running in Docker.

Instead of building standalone functions, we see more value in using our favorite Node/Typescript backend framework NestJS.

To accomplish this task, start by installing Azure Function Core Tools.

brew tap azure/functions
brew install azure-functions-core-tools@4

We start by creating our NestJS app. Once created we use the add-on provided by the NestJS team that helps get things scaffolded for use in Azure Functions.*

*This process has to be done before the initialization of the container since NestJS needs some specific settings that are different from the defaults generated by the Azure Function Core Tools container initialization process.

nest new nest-docker-func
cd nest-docker-func
nest add @nestjs/azure-func-http

Next, modify the newly created NestJS app to set a global prefix of api in the main.ts to match what is expected for running serverless and makes for easier testing when not running via func start or in docker.

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.setGlobalPrefix('api'); // <--- add this to match the default route for azure functions
  await app.listen(3000);

With NestJS now set up, we can shift gears and initialize a new function container.

func init --worker-runtime node --language typescript --docker

Then, we test our function to ensure it's working properly.

func start

Next, attempt to access the newly created NestJS app http://localhost:7071/api/.

Assuming you've completed the last step successfully, it is time to test the Docker container.

Test the Docker container

First, we start by building our Docker container. Once built, try running the newly created container.

docker build --tag tevpro/azurefunctionsimage:v1.0.0 .
docker run -p 8080:80 -it tevpro/azurefunctionsimage:v1.0.0

Finally, test the app via the container to ensure everything is working from the Docker container http://localhost:8080/api/.

Final thoughts

There are countless benefits to serverless computing and it's not about "if" but "when" you'll need to make the transition.  Fortunately, Tevpro specializes in enterprise data integration and data management solutions and we'd love to hear from you. Feel free to reach out with any questions,

Be sure to follow us on Twitter and subscribe to the Tevpro blog for insights, new content updates, and tutorial articles.

Keith Kikta

NestJS • C# • AWS • Azure • Integration • EPM • CPM