How to deploy ASP.NET Core 3.x to Google App Engine

Saverio Terracciano
Google Cloud - Community
8 min readApr 7, 2020
You were the chosen one!

Following on from my previous article about deploying an ASP.NET Core 3.x application to Google Cloud Engine (https://medium.com/google-cloud/how-to-deploy-asp-net-core-3-x-to-google-compute-engine-iis-dc4d614000f9), it’s App Engine’s turn.

App Engine with its Flex environment should offer an easy and straightforward deployment experience and in most cases, it’s my goto when I want to quickly have something running on GCP.

Sadly, as of now, this is not the case for the applications leveraging the latest incarnations of the .NET Core framework.

If you don’t have time, and you just want a pointer in the correct direction…

TL;DR

App Engine Flex environment has an “aspnetcore” runtime, but it doesn’t support (yet) version 3.x applications.

You need to provide a custom runtime specifying a Dockerfile, using a base image that includes the latest framework.

There are a few points to be careful of, in particular, that your application listens and exposes port 8080 to be able to communicate with GAE’s frontend.

If you’re interested not only in the “What”, but also in the “How”, I’ll guide you to create a simple Asp.Net Core application, deploy it via CLI to GAE in the normal way (which currently won’t work) and show you how to create a custom runtime for DotNetCore 3.x so that it will work.

Disclaimer: The problem encountered when deploying to the aspnetcore runtime will likely be fixed in future updates, in which case I will try to get back to this and make a note of it to avoid confusion, but generally, this article should still be useful on how to get started in deploying an ASP.NET Core App to GAE.

Requirements

Before getting started, I assume you have installed on your machine:

and have basic familiarity with GCP, .NET Core & Docker, with a GCP account to use.

Even if we’re going to use Dockerfiles you won’t be required to have it installed on your machine (but it could be useful to test locally).

Let’s get started!

Creating the ASP.NET Core Web Application

First of all, we need an application, a default MVC template can be a good example as that will allow us to have quick visual feedback.

We can either create it through Visual Studio:

Or equivalently, from the command prompt we can use the CLI (https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-new):

dotnet new mvc -n "CoreOnGAE"

from here onwards we’ll assume our project is named “CoreOnGAE”.

To check that everything was initialised and restored correctly we can try to build & launch our project in Visual Studio pressing F5 (Build & Start Debugging) which will also open a browser window, or from the CLI we can navigate to the folder of the project and then execute:

dotnet run

as we can see the application is listening on localhost on the port 5001 for HTTPS and 5000 for HTTP, let’s use a browser and navigate to either:

you can choose to customise this page at “ \Views\Home\Index.cshtml”, otherwise, we are good.

Deploying the Web Application

We need a project to contain our App Engine instance(s).
You might choose to use one you already have or to create a new one.

If needed, create a project at https://console.cloud.google.com/, in my example, I called it “dotnet-core-testing”.

Alternatively, you can create it from the CLI (https://cloud.google.com/sdk/gcloud/reference/projects/create):

gcloud projects create "dotnet-core-testing" --set-as-default
The — set-as-default flag is used to set the new project as the current one

or set an existing project as in use
( https://cloud.google.com/sdk/gcloud/reference/config/set ):

gcloud config set project dotnet-core-testing

We then need to initialise an Application in App Engine, which we can either do through the console

or via CLI ( https://cloud.google.com/sdk/gcloud/reference/app/create ):

gcloud app create --project=dotnet-core-testing

To push your application to GAE, you need to specify which environment and runtime it’s going to use. To do that, you need to add an app.yaml file to your application.

In a perfect world scenario, we’d just need to specify that we’re going to use the Flex environment and the AspNetCore runtime:

runtime: aspnetcore
env: flex

[Bonus Tip] On Window’s command prompt, you can create a new app.yaml in one line:

(echo runtime: aspnetcore & echo env: flex) > app.yaml

the app.yaml file will have to be copied over to the destination folder when you start the publishing process.
You can include the file to the output through Visual Studio or editing the *.csproj file:

<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Include="app.yaml" CopyToOutputDirectory="Always" />
</ItemGroup>
</Project>

You can then publish the Release version in VS or CLI (https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish):

dotnet publish -c Release
Make sure that the app.yaml is present in the output directory

Ideally, we would now be ready to push our Asp.Net Core application to App Engine.

We could do that through the Google Cloud Tools for Visual Studio (check my previous article *here* to know how to install & configure them) right-clicking on the project from the Solution Explorer and select “Publish to Google Cloud…” and then “App Engine Flex”:

Or with just one command on the CLI, in its simplest form (https://cloud.google.com/sdk/gcloud/reference/app/deploy):

gcloud app deploy .\bin\Release\netcoreapp3.1\publish\app.yaml

As you can see from the screenshot…it didn’t work.

The error is informative enough to point us in the right direction, as the aspnetcore runtime doesn’t support 3.x applications, but if we want to drill down in the details in a more organised way, we can access the build logs on Cloud Build using the URL provided or through the console (https://console.cloud.google.com/cloud-build/)

I am sure this will change in the coming months, and the operation will bring a successful result, but for now, we need an alternative way.

Deploying to GAE with a Custom Runtime

Luckily we can supply a custom runtime that will make possible to run Asp.Net Core 3.x applications in GAE.

To do that, we have to start by editing our app.yaml, changing the runtime:

runtime: customenv: flex

We then need to specify a Dockerfile (https://docs.docker.com/engine/reference/builder/) for our application.

While that will largely depend on what you’re trying to accomplish, you can use the following template as a reference:

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build-envWORKDIR /app# Copy csproj and restore as distinct layersCOPY *.csproj ./RUN dotnet restore# Copy everything else and buildCOPY . ./RUN dotnet publish -c Release -o out# Build runtime imageFROM mcr.microsoft.com/dotnet/core/aspnet:3.1WORKDIR /appCOPY --from=build-env /app/out .EXPOSE 8080ENV ASPNETCORE_URLS=http://*:8080ENTRYPOINT ["dotnet", "CoreOnGAE.dll"]

A few notes on our Dockerfile:

  • As of now, there are no images tagged with 3.1 on http://gcr.io/google-appengine/aspnetcore:3.1 so we will use an official one from Microsoft’s repository, which includes the 3.1 Framework.
    Alternatively, we could push a custom one to our private Container Registry and use that.
No readily available image on Google Container Registry with 3.1 Framework
  • Make sure you’re exposing and listening on the port 8080 as that is where the App Engine frontend will route incoming requests. If you don’t, your application will be deployed, run, but once you try to access it you will get back an HTTP 502 Bad Gateway error.

[Bonus Tip] To reduce the size of your application’s image, you can create a .dockerignore file that will indicate which paths to exclude.
Generally, that would mean to exclude the bin and obj folders, which you can specify like this

bin\
obj\

We’re ready to push everything to App Engine (this time targetting the app.yaml file in the root of the project, and not the published version):

gcloud app deploy app.yaml
Deployed correctly!
Cloud Build confirms the successful operation

If we try to navigate to the website provided (https://<PROJECT_ID>.appspot.com) on the browser, or through the CLI:

gcloud app browse

We can see it works!

[Bonus Tip] We can monitor the output of our application either on Google Logging (ex Stackdriver) https://console.cloud.google.com/logs/

or streamed directly through the CLI (https://cloud.google.com/sdk/gcloud/reference/app/logs/tail):

gcloud app logs tail -s default

Parting words

I expect in the next future the aspnetcore runtime for GAE to be upgraded so that we can target that directly, but in the meantime using a Dockerfile can be a useful exercise also if you want to deploy your application to GKE or Cloud Run, as we will see in the next articles.

We haven’t used Docker in our local machine to deploy, but having it installed and experimenting/testing with it, can be useful to make sure your image building pipeline works before pushing it to GAE.

Most of the commands used in this article are in their simplest, barebone form, which I wouldn’t advise for production environments, as an example, you should tag your deployed versions with a proper label or you should specify the resources and scaling details you wish to use in your app.yaml file.

I hope I was able to help you with this article, but if you have further doubts or feedback, I’ll be glad to chat with you on Twitter, DMs are open (https://twitter.com/TetsuoRyuu)

--

--

Saverio Terracciano
Google Cloud - Community

Lead Organiser of @GDGCloud Software Engineer @TIWGroup, Gamer, Voracious consumer of Tv shows, Movies, Gunpla, Mangas…oh & food! Contact me at @tetsuoryuu