In this tutorial, you will deploy an F# script directly to an Azure Container Group. This is useful when you need to fill a gap in your solution with some quick application logic or to test scenarios on Azure before building a more complex application. We’ll cover the following steps:
Scripts are often useful for quick automation or very simple application logic. Our goal here is to create a small HTTP service - this could be used for a health check service or to bootstrap a larger application, but we’ll keep it very simple for illustrative purposes. Let’s name it main.fsx
.
#r "nuget: Suave, Version=2.6.0"
open Suave
let config = { defaultConfig with bindings = [ HttpBinding.createSimple HTTP "0.0.0.0" 8080 ] }
startWebServer config (Successful.OK "Hello Farmers!")
A container group consists of one or more containers that will run together. The container instances in the group can communicate with each other and share files over volume mounts.
Our script relies on the dotnet 5 SDK to run the script with the dotnet fsi
command, so we will run it on the dotnet/sdk:5.0
docker image which includes this SDK. Since our script creates a web listener on port 8080, we will add that as a public port and give it a DNS name so we can reach it.
open Farmer
open Farmer.Builders
let containers = containerGroup {
name "my-app"
add_instances [
containerInstance {
name "fsi"
image "mcr.microsoft.com/dotnet/sdk:5.0"
add_public_ports [ 8080us ]
}
]
public_dns "my-fsi-app" [ TCP, 8080us ]
}
The F# script will be embedded in the template as a secret_string
. This creates a file in the container group that can be mounted into the file system on any of the container instances in the group. In our case, we will mount the F# script as a file named main.fsx
in the container group and mount the directory containing that file as /src
. With this in place we can also set the dotnet fsi
command to run on container start, executing the script.
let containers = containerGroup {
name "my-app"
add_instances [
containerInstance {
name "fsi"
image "mcr.microsoft.com/dotnet/sdk:5.0"
add_public_ports [ 8080us ]
// Add a volume mount with the script source.
add_volume_mount "script-source" "/src"
// Set the command line to run 'dotnet fsi /src/main.fsx' on startup
command_line ("dotnet fsi /src/main.fsx".Split null |> List.ofArray)
}
]
public_dns "my-fsi-app" [ TCP, 8080us ]
// Read our script source when building the ARM template and embed it into the template as a secret string volume mount to attach to the container group.
add_volumes [
volume_mount.secret_string "script-source" "main.fsx" (System.IO.File.ReadAllText "main.fsx")
]
}
The resulting template contains the contents of the F# script embedded as base64 so we have a standalone template that can be deployed to ARM.
arm {
location Location.EastUS
add_resources [
containers
]
}
When the container group starts, it will execute the F# script, starting the service. This is very useful for gathering source and configuration from your local or internal environment and including it in a deployment. We are able to use this technique due to two unique features: