-
Notifications
You must be signed in to change notification settings - Fork 160
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds tutorial for deploying F# script with ACI
- Loading branch information
1 parent
870fda2
commit 4c93076
Showing
2 changed files
with
126 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
--- | ||
title: "F# Script in a Container Group" | ||
date: 2021-02-10 | ||
draft: false | ||
weight: 5 | ||
--- | ||
|
||
#### Introduction | ||
|
||
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: | ||
|
||
1. Create a brief F# script. | ||
1. Create a container instance. | ||
1. Include the script on a volume that will be attached to the container when started. | ||
|
||
#### Create the F# Script | ||
|
||
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`. | ||
|
||
```fsharp | ||
#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!") | ||
``` | ||
|
||
#### Create the Container Group | ||
|
||
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. | ||
|
||
```fsharp | ||
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 ] | ||
} | ||
``` | ||
|
||
#### Include the script in the deployment | ||
|
||
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. | ||
|
||
```fsharp | ||
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. | ||
|
||
```fsharp | ||
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: | ||
|
||
* Farmer is an "embedded" DSL - rather than simply a friendly version of the ARM template language, it brings the full feature set of .NET when building a template. This makes reading a script from the file system, converting to base64, and embedding in the template a simple process. | ||
* ARM templates are not executed locally like Azure CLI scripts - they are a specification for ARM to deploy the infrastructure on your behalf. Once the F# script on your local machine is embedded into the template, ARM is able to pass it to your infrastructure securely over Azure's control plane. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#r "nuget: Farmer" | ||
|
||
let script = """ | ||
#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!") | ||
""" | ||
|
||
open Farmer | ||
open Farmer.Builders | ||
|
||
let containers = containerGroup { | ||
name "my-app" | ||
add_instances [ | ||
containerInstance { | ||
name "fsi" | ||
image "mcr.microsoft.com/dotnet/sdk:5.0" | ||
command_line ("dotnet fsi /src/main.fsx".Split null |> List.ofArray) | ||
add_volume_mount "script-source" "/src" | ||
add_public_ports [ 8080us ] | ||
cpu_cores 0.2 | ||
memory 0.5<Gb> | ||
} | ||
] | ||
public_dns "my-app-fsi-suave" [ TCP, 8080us ] | ||
add_volumes [ | ||
volume_mount.secret_string "script-source" "main.fsx" script | ||
] | ||
} | ||
arm { | ||
location Location.EastUS | ||
add_resources [ | ||
containers | ||
] | ||
} |> Writer.quickWrite "aci-fsharp" |