This sample application shows how to:
- Compile a Spring Boot application using GraalVM
- Deploy and run that application on Azure Functions
This will use GitHub Actions to do all the heavy work: as we are creating a native image, it needs to be built on a Linux machine with GraalVM installed.
- An Azure account with an active subscription. Create an account for free.
- The Azure CLI must be installed. Install the Azure CLI.
- Terraform must be installed. Install Terraform.
To check if Azure is correctly set up, login using the CLI by running az login
.
All compilation and deployment will be done using GitHub Actions, so you need your own repository for this.
The easiest way is to fork this repository to your own GitHub account, using the fork
button on the top right-hand corner of this page.
You need to configure the following environment variables:
export TF_VAR_AZ_LOCATION=westeurope
export TF_VAR_AZ_RESOURCE_GROUP=azure-native-spring-function
export TF_VAR_AZ_FUNCTION_NAME_APP=<your-unique-name>
export TF_VAR_AZ_STORAGE_NAME=<your-unique-name>
TF_VAR_AZ_LOCATION
: The name of the Azure location to use. Useaz account list-locations
to list available locations. Common values areeastus
,westus
,westeurope
.TF_VAR_AZ_RESOURCE_GROUP
: The resource group in which you will work. It should be unique in your subscription, so you can probably keep the defaultazure-native-spring-function
.TF_VAR_AZ_FUNCTION_NAME_APP
: Functions will run into an application, and its name should be unique across Azure. It must contain only alphanumeric characters and dashes and up to 60 characters in length.TF_VAR_AZ_STORAGE_NAME
: Functions binaries and configuration will be stored inside a storage account. Its name should also be unique across Azure. It must be between 3 and 24 characters in length and may contain numbers and lowercase letters only.
In order not to type those values again, you can store them in a .env
file at the root of this project:
- This
.env
file will be ignored by Git (so it will remain on your local machine and won't be shared). - You will be able to configure those environment variables by running
source .env
.
Go to the terraform
directory and run:
terraform init
to initialize your Terraform environmentterraform apply --auto-approve
to create all the necessary Azure resources
This will create the following Azure resources:
- A resource group that will store all resources (just delete this resource group to remove everything)
- An Azure Functions plan. This is a consumption plan, running on Linux: you will only be billed for your usage, with a generous free tier. Here is the full pricing documentation.
- An Azure Functions application, that will use the plan described in the point above.
- An Azure Storage account, which will be used to store your function's data (the binary and the configuration files).
The GitHub Actions workflow that we will use is available in .github/workflows/build-and-deploy.yml.
This GitHub Action will need to use some variables, for this go to your project fork and select "Settings", then "Secrets".
The AZ_FUNCTION_NAME_APP
is the name of your function application. It is the same as the TF_VAR_AZ_FUNCTION_NAME_APP
environment variable that we configured earlier with Terraform.
Create a new secret called AZ_FUNCTION_NAME_APP
, paste the value in it, and click "Add secret".
The AZURE_CREDENTIALS
will allow the GitHub Actions workflow to log in your Azure account, and deploy the application.
This is a JSON payload that we will get by executing the following command:
RESOURCE_ID=$(az group show --name $TF_VAR_AZ_RESOURCE_GROUP --query id -o tsv)
SPNAME="sp-$(az functionapp list --resource-group $TF_VAR_AZ_RESOURCE_GROUP --query '[].name' -o tsv)"
az ad sp create-for-rbac --name "${SPNAME}" --role contributor --scopes "$RESOURCE_ID" --sdk-auth
Create a new secret called AZURE_CREDENTIALS
, paste the JSON payload in it, and click "Add secret".
Now that everything is set up, your application will be automatically built as a GraalVM native image, and deployed to Azure Functions.
You can change some code, or force a commit to trigger such a build:
git commit -m "force build" --allow-empty && git push
You will be able to monitor that process in the "Actions" tab of your fork of the project.
Once the function is deployed, you can access it though the Azure Portal. You will there be able to monitor it and test it.
- Select your resource group
- Select the Azure Functions application you created (its type is "App Service")
- In "Functions", find the function that you have just deployed
- Select "Code + Test"
- You can click on "Test/Run": select a "POST" method, and enter
Azure
as body. You should have the following output:{"message": "Hello, Azure!\n"}
As you will want to test the performance of this function, still on the "Code + Test" screen, select "Get function URL". Use that function URL to test the performance of your function:
time curl <YOUR-FUNCTION-URL> -d 'Azure' -H "Content-Type: application/json"
For monitoring your function, you can also select the "Monitor" tab and create an Azure Applications Insight instance, which will be able to give you detailed metrics (like RAM usage) of your function.
The function configuration is in src/main/function
:
- The name of the directory should be the same as the name of the function. That's how Azure Functions can apply the configuration.
- Documentation for the
host.json
andfunction.json
files can be found at Azure Functions custom handlers.
The application used here is very simple, and comes from https://github.com/spring-projects-experimental/spring-graalvm-native/tree/master/spring-graalvm-native-samples/function-netty.
If you want to work on this function or run it locally, the https://github.com/spring-projects-experimental/spring-graalvm-native project gives all the necessary documentation.