Suave.IO introduction and example - Part 5: Deploying to Azure

Suave.IO introduction and example - Part 5: Deploying to Azure

-

Here we are, the last post of the series. We now have a working Suave.IO application running on our local machine. The last thing we need to do is getting it to production.

We want to run our application in Azure. Thankfully we are not the first to do so, and this post is heavily inspired by this guide by Scott Hanselman.

If you have been following along you are probably aware that the code for our application can be found at GitHub. This is a great starting point if we want deploy to Azure, since Azure Web Apps can go grab our code from GitHub and start a deploy.

Kudu build scripts

Kudu is the tool responsible for the automatic Git deploys in Azure. We can't do a plain vanilla deploy since we depend on Paket to get our dependencies. Fortunately for us Kudu allows us to write custom deploy scripts.

The first thing we need to do is adding a Kudu script called ".deployment" to the root of our repo. In our case it's not going to contain a whole lot, actually we will just use it to call a batch file.

[config]
command = deploy.cmd

Deploy batch file

And to be perfectly honest, the deploy.cmd is more or less identical to dependencies.cmd we use to install Paket and our dependencies locally. There is one twist though, after installing our dependencies we move everything to our web root folder.

@echo off
cls

if not exist .paket (
  @echo "Installing Paket"
  mkdir .paket
  curl https://github.com/fsprojects/Paket/releases/download/1.4.0/paket.bootstrapper.exe -L --insecure -o .paket\paket.bootstrapper.exe

  .paket\paket.bootstrapper.exe prerelease
  if errorlevel 1 (
    exit /b %errorlevel%
  )
)

if not exist paket.lock (
  @echo "Installing dependencies"
  .paket\paket.exe install
) else (
  @echo "Restoring dependencies"
  .paket\paket.exe restore
)

if errorlevel 1 (
  exit /b %errorlevel%
)

@echo "Copying files to web root"
xcopy /s /y . d:\home\site\wwwroot\

I have to admit, I am 99% sure there is a much more sensible way to move this. But for now this actually solves the problem of putting together our application and adding it to our web folder.

Getting it to run

Now things are in the right place, but we still need to get it to run. To achieve this we need to do a couple of things.

Azure build script

First of all we need to add another FAKE build script that we can use to run our application in Azure. Our local build script is fairly complex and does things like reloading our application on changes. That's not necessary for running the application Azure, instead we should go for a slightly lighter script.

#r "packages/Suave/lib/net40/Suave.dll"
#r "packages/FAKE/tools/FakeLib.dll"
#load "app.fsx"
open App
open Fake
open System
open System.IO
open Suave
open Suave.Http
open Suave.Web
open Suave.Types

let serverConfig =
    let port = int (getBuildParam "port")
    { defaultConfig with
        homeFolder = Some __SOURCE_DIRECTORY__
        logger = Logging.Loggers.saneDefaultsFor Logging.LogLevel.Warn
        bindings = [ Types.HttpBinding.mk' Types.HTTP "127.0.0.1" port ] }

Target "run" (fun _ ->
    startWebServer serverConfig app
)

RunTargetOrDefault "run"

Starting it from web.config

We need some way to run our application and let it serve requests within the IIS-webserver running under the hood in our Azure Web App. Thankfully Microsoft supplies us with everything we need in the form of the HttpPlatformHandler module.

All we need to do is to add a web.config file to our application, and configure what process should run our application. We point it to FAKE, and have it run our build.azure.fsx-script.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <remove name="httpplatformhandler" />
      <add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
    </handlers>
    <httpPlatform
              stdoutLogEnabled="false" stdoutLogFile="fake.log" startupTimeLimit="20"
              processPath="%HOME%\site\wwwroot\packages\FAKE\tools\FAKE.exe"
              arguments="%HOME%\site\wwwroot\build.azure.fsx port=%HTTP_PLATFORM_PORT%" >
      <environmentVariables>
      </environmentVariables>
    </httpPlatform>
  </system.webServer>
</configuration>

Putting it together

Our project is now ready to be deployed. When we set up a new Web App through the Azure Portal and configure it to deploy from our repository, the following should happen.

  1. Azure gets a copy of our project and stores it locally
  2. Our Kudu-script runs and installs Paket and all our dependencies
  3. The entire working folder is copied to our wwwroot
  4. When we access the website IIS starts serving requests using a FAKE process and our application.

Wrapping up

We've now been through a five part introduction to creating a Suave.IO application. The posts reflect my experience when creating my first Suave.IO application, and hopefully answers some of the questions I was asking during that process.

It also poses a few new questions that I haven't answered yet. I especially feel I need to learn more about running the application in Azure to feel comfortable using Suave.IO in a real production setting. Things like

  • I need to learn more about Kudu-scripts, and leveraging Kudu to do proper deploys, rather than xcopying files to my web root. Because honestly that isn't a very stable solution.

  • I want to know why I couldn't serve static content using the "file"-WebPart when running the application in Azure.

I can see myself using Suave.IO going forward, and continue to learn about these things. I feel that Suave.IO gives me a very appealing lightweight alternative when it comes to writing web applications.

And though it might seem simplistic at first glance, the library is well-rounded, and it is just .NET, giving us access to the entire .NET ecosystem when needed. If you work with web applications and enjoy writing F# you should definitely check out Suave.IO!

Again thanks to people I've been piggybacking on, Tomas Petricek, Scott Hanselman and of course the good people behind Suave.IO!

View Comments