Developing Azure Functions in a Docker Container

Article summary

Of late, I’ve become enamored with using Docker containers for anything and everything (I recently posted about doing development in a Docker container). So when I needed to do some work on a small Azure Functions project, the first thing I investigated was whether or not I could do my development/testing in a Docker container running on my MacBook Pro.

I was pleasantly surprised to find out that I could! As of Version 2 of the Azure Functions Runtime, it is cross-platform (thanks to .NET core), with support for Windows, Mac, and Linux.

There’s even some official Microsoft documentation that shows how to configure a Docker container to run a Node.js based Azure Functions project:

ENV AzureWebJobsScriptRoot=/home/site/wwwroot
COPY . /home/site/wwwroot

or for a C# project, Mark Heath provides an example:

FROM microsoft/azure-functions-dotnet-core2.0:2.0
ENV AzureWebJobsScriptRoot=/home/site/wwwroot
COPY ./bin/Release/netstandard2.0 /home/site/wwwroot

Development Environment

Those containers are great for running the app. But I wanted to use a container that would allow me to edit the code in the container and run the server without having to rebuild the container every single time (as I described in the post I mentioned earlier).

I pieced together the necessary Linux installation instructions from various web pages and was able to come up with a Dockerfile that has all of the necessary .NET and Azure Functions parts:

FROM ubuntu:18.04

RUN apt-get update && apt-get install -y \
  curl \
  gnupg \
  git \
  vim \

RUN curl | gpg --dearmor > microsoft.gpg \
  && mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg \
  && echo "deb [arch=amd64]$(lsb_release -cs)-prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list

RUN apt-get update && apt-get install -y \
  azure-functions-core-tools \

# Development environment utilities
RUN apt-get install -y \
  telnet \
  net-tools \
  iputils-ping \
  htop \
  bash-completion \

RUN groupadd -g 1000 dev && \
    adduser --uid 1000 --gid 1000 --disabled-password dev

USER dev
RUN mkdir -p /home/dev/app
WORKDIR /home/dev/app

You can easily change the version of the dotnet-sdk to whatever you need.

With this as a starting point, you simply need to get the source code into your running container (clone the repository, ideally). From there, you should be able to run func start --build to run the app. As noted in my earlier post, it’s a good idea to mount a named volume so when you check out the source code it won’t get blown away when the container is recreated.