Running .NET on Google Cloud Functions

This is a sample application running a .NET Cloud Function as an HTTP Trigger. While GCF (Google Cloud Functions) currently only supports NodeJS, there are some techniques you can use to launch different language runtimes and delegate control of the socket to that runtime. This article and code linked from it at the bottom describes one technique to run .NET on GCF.

Disclaimer: This is not an official Google product. It is not and will not be maintained by Google, and is not part of Google Cloud Functions project. There is no guarantee of any kind, including that it will work or continue to work, or that it will supported in any way.

The basic flow of this application initially starts GCF as node application (you have to), then delegates control of the listen socket to your target runtime (.NET in this case).

On application startup:

  1. Initialize NodeJS GCF entrypoint (index.js on port :8080)
  2. NodeJS launches (gyp add-on cpp binary (execer.cc)
  3. execer binary scans NodeJS’s socket file descriptors
  4. execer binary launches .NET binary (bin/mainapp) and passes the listener socket to .NET
  5. .NET application “takes control” of the listening socket.
  6. .NET application now receives user-requests directly as a GCF function
Wait…so how are you able to run .NET on GCF without coreCLR installed?

Well, while the full coreCLR isn’t installed, all that is needed to run a simple .NET binary *is* uploaded during the deployment.

In this case, during build time, the Makefile acquires all the shared_objects (.so) files for .NET, compiles the sample application into a binary for linux, then uploads it.

So, when you stage the build files for deployment, the following folders get generated:

  • ~/bin/ contains the the .NET binary to execute and supporting .dll
  • ~/lib contains all the .so files required to run coreCLR
  • ~/node_modules contains the NodeJS files to launch the intermediate execer.cc add-on module

If you want to try this out, you the easiest way is to run it through Google Cloud Shell (described below). You’ll need to have a Google Cloud Platform Project setup (ofcourse) as well as enable GCF

There are several ways you can build and run these samples:

  1. Build+Run entirely within Google Cloud Shell.
  2. Build+Run locally with docker (requires GNU Make, docker)
  3. Develop+Build+Run locally with dotnet and docker (requires GNU Make, docker, dotnet)

If you want to get started, just build+run within cloud shell.

Note, the .NET cloud function application must target dotnet 2.0.0-preview1+ (previous versions of dotnet does not include the required Kestrel webserver options)


Quickstart: Build+Run with Cloud Shell

  1. Enable Cloud Functions API on your project.
  2. Open up Cloud Shell and install docker 17+ (for multi-stage builds):

3. Get the repo

git clone https://github.com/salrashid123/cloud-functions-dotnet.git

4. Build and stage the files (this will take sometime)

cd cloud-functions-dotnet
make all
make check_deploy

5. Deploy Remember to specify the staging GCS bucket.

gcloud beta functions deploy gcfdotnet --stage-bucket your_staging_bucket --trigger-http

6. Verify Deployment by invoking the endpoint URL (this may take sometime to initialize first time ~mins)

curl -v https://us-central1-your_project.cloudfunctions.net/gcfdotnet

Writing a cloud function and running locally

For this mode, you need to have dotnet, docker and gnu make as described above installed locally

Edit Startup.cs file to add on your HTTP Trigger function to the following endpoint:

Startup.cs

then run the dotnet application as normal (note, you must target 2.0.0-preview1+):

dotnet restore
dotnet run

To simulate deployment and the nodeJS module passing control, run

$ make test_with_container

which does the following:

  1. Runs temp container to acquire the .so files needed for .NET and copies them to lib/
  2. Runs temp container to build the .NET executable and copies them to bin/
  3. Runs temp container to build node_modules and copies them to the hosts node_modules/ folder
  4. Launches node webserver within a container and listens on :8080
  5. Passes the socket file descriptors from node to .NET
  6. .NET takes over the sockets from Node.
Note: Application Default Credentials will not work unless you pass though GOOGLE_CLOUD_PROJECT and GOOGLE_APPLICATION_CREDENTIALS env variable plus the json certificate file (shown in the Makefile)

Deploying

If you have coreclr/dotnet installed locally, build all the dependencies and acquire the binary locally (bin_from_local)

make node_modules lib bin_from_local

if you do not wish to generate the binary locally, you can instruct the build system to generate it from _within_ a container (bin_from_container)

make node_modules lib bin_from_container

then check if all the necessary files exist to deploy

$ make check_deploy

Finally, upload as an HTTP Trigger as described here:

gcloud beta functions deploy gcfdotnet --stage-bucket your_staging_bucket --trigger-http

it takes quite sometime to generate all the lib/ and node_modules/ dependencies so once they are already built using ‘make all’ you can selectively recreate the .NET binary using ‘make bin_from_local’ or ‘make bin_from_container’ and directly deploy using gcloud.

NOTE
This is a unofficial port to .NET of cloud-functions-go sample
You can find the main git repository for this application here:
https://github.com/salrashid123/cloud-functions-dotnet