DEV Community

Ingun 전인건
Ingun 전인건

Posted on

Azure Function app that runs Haskell Nix package

I built a containerized Azure Function App that internlly runs a haskell program packaged with Nix.

I followed Create your first containerized functions on Azure Container Apps to make a scaffold. Runtime could be anything than can run sub process, which is everything. So I choose dotnet.

And at the end of the generated Dockerfile, I added some nix layers.

# Basic runtime to install nix
RUN apt install -y xz-utils curl
RUN bash -c "sh <(curl -L https://nixos.org/nix/install) --daemon --yes"
# Update PATH to include nix tools
ENV PATH="/home/.nix-profile/bin:/nix/var/nix/profiles/default/bin:${PATH}"
Enter fullscreen mode Exit fullscreen mode

Then I copied my haskell project.

ADD haskell-project /opt/haskell-project
Enter fullscreen mode Exit fullscreen mode

Create haskell package using cabal2nix. I call nix-collect-garbage to reduce the size of docker layer.

RUN nix-shell -p cabal2nix --run 'cabal2nix --no-check /opt/haskell-project > /opt/haskell-project/foo.nix' && nix-collect-garbage
Enter fullscreen mode Exit fullscreen mode

The default.nix would look like this. It calls the haskell package and wrap it with justStaticExecutables to leave only runtime dependencies.

let
  p = (import <nixpkgs> {}).pkgs;
in
  p.haskell.lib.compose.justStaticExecutables (p.haskellPackages.callPackage ./foo.nix {})
Enter fullscreen mode Exit fullscreen mode

Build the nix package

RUN nix-build
Enter fullscreen mode Exit fullscreen mode

In the Function implementation, run the hasell executable as a subprocess

using System.Diagnostics;

using (Process hs = new Process())
{
    hs.StartInfo.UseShellExecute = true;
    hs.StartInfo.FileName = "/opt/haskell-project/result/bin/exe";

    hs.Start();
    await hs.WaitForExitAsync();
    if (hs.ExitCode != 0)
    {
        throw new Exception($"haskell subprocess failed {hs.ExitCode}");
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)