The best way to describe Cloud Run is to quote Google (almost verbatim)
About Google Cloud Run
Cloud Run is a managed compute platform that enables you to run containers that are invocable via requests or events. Cloud Run is serverless: it abstracts away all infrastructure management, so you can focus on what matters most — building great applications.
It allows you to develop and deploy highly scalable containerized applications on a fully managed serverless platform.
It allows you to write code your way using your favorite language
It is built upon the container and Knative open standards, enabling portability of your applications
Cloud Run automatically and horizontally scales out your container image to handle the received requests, then scales in when demand decreases. You only pay for the CPU, memory, and networking consumed during request handling.
In this guide, we will need to perform tasks in the Visual Studio environment as well as in the Google Cloud platform.
Setting Up Your Environment
Install Visual Studio 2022
If you do not already have Visual Studio 2022 installed, you can heard over to the link below, select your preferred version and install it:
Setup Google Cloud Environment
Follow the steps below to create and setup you Google Cloud Environment.
Obtain a Google Cloud account. If you do not already have a Google Cloud Account, you can heard over to the link below to obtain an account, Google may still have a $300 credit to get started:
In this example we will be using the gcloud-cli (installed by the SDK); there's no need to install the optional App Engine components (see step 5 of the instructions for installing the SDK). Since we will be using docker to push out images to the Google Cloud platform, we will need the gcloud-cli to authorize access and perform other cloud-based functions.
Of most interest to us are the following gcloud commands used to initialize the cli and to set it to handle authorization requests:
gcloud init
gcloud auth login
Follow the directions at the link below to initialize gcloud and have it handle cloud authorization for Docker.
Run gcloud auth configure-docker. Since we'll be using docker, configure docker to use gcloud to provide credentials for Google Cloud. Instructions are provided here:
NOTE: The Google Cloud SDK gets a lot of updates, so it is a good idea to check the referenced url's since the instructions may have been updated.
Suggested Naming Convention
Before going any further, I suggest you come up with a naming convention for the various components we'll be using in the Cloud Run platform.
Project Name
Docker Image Name
Artifactory Repository Name
Service Name
If you (or your team) is working on several projects you'll find this to be very helpful. I am naming the VS WebAPI project WeatherForecastAPI. The names that I chose for this guide are:
Project Name: WeatherForecastAPI-proj -- Google will generate a Project ID from this.
If you are not already there, navigate to the Google Cloud Console and create a new project.
The project name is up to you, but if you want to follow along with this blog, we are naming the project WeatherForecastAPI-proj
Once the project is created, note the Project ID, you will need it to interact with the platform. Note that the ID is generated automatically, and may be different from what you expect.
4. Create an Artifact Repository
The next step is to create a repository to hold your containers (images). On the console, search for and select Artifact Registry.
If prompted, enable the API.
The next step is to add a repository to hold your container images. In this sample we will be hosting a docker image.
Provide the repo details as shown below and click CREATE.
If you run into an error like shown below, ignore it; it takes a few minutes for the repository to be propagated.
4 Create the Visual Studio 2022 Project
Start Visual Studio and create an ASP.Net Core WebAPI app. In this example, I am naming my project WeatherForecastAPI
When you click "Next" be sure to provide the additional information as shown in the image below.
After Visual Studio completes the setup, run the app (Ctrl-F5) to make sure it works.
For our purposes we are going to make some changes.
1) Replace the code in Program.cs with the following:
var builder = WebApplication.CreateBuilder(args);
int hostPort = Int16.Parse(builder.Configuration["Host:Port"]);
builder.WebHost.UseKestrel(options =>
{
options.Listen(System.Net.IPAddress.Any, hostPort);
});
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseRouting();
app.UseSwagger();
app.UseSwaggerUI();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
context.Response.Redirect("swagger");
});
});
//app.UseHttpsRedirection();
//app.UseAuthorization();
app.MapControllers();
app.Run();
In the above code, note the following:
I have commented out app.UseHttpsRedirection() - an explanation will be provided later in this blog.
I have also commented out app.UseAuthorization — it is not the focus of this sample
I am defaulting to show the swagger UI in all the environments (Dev, Staging, Production), by design, not just for the Dev environment.
By default, Kestrel binds to ports 5000 and 5001. In the above code, I have generalized the code (lines 3-9), to use the port specified in appsettings.json. This allows you to easily change the port to any acceptable value. We will need this value when we configure the service in Google CloudRun.
I have also made some changes to the WeatherForecastController to make it a little more interesting.
Why not Use Https Redirection in the Net Core App?
As was stated earlier, we are not using app.UseHttpsRedirection in the pipeline. This is because Cloud Run redirects all HTTP requests to HTTPS but terminates TLS before they reach your web service
If you use it (UseHttpsRedirection), Kestrel will re-redirect to https. This will create a circularity resulting in a "Too many Redirects" error.
Preparing the App for Google CloudRun
The steps are:
Publish the app
Create a Docker image of the app
Tag the image
Push the image to Cloud Run
Publish The App
For this step, we'll use the usual Visual Studio publish steps. I am publishing to a output folder in the application directory (C:\Sample\WeatherForecastAPI\output) and setting the target framework to linux-x64
Why Target Linux-x64 Runtime?
Well.... you can target one of the windows variants instead. Just be aware that When you create an on-demand Windows Server instance on Compute Engine, Google includes the cost of the license with the cost of the instance.
Source: Microsoft Licensing FAQ
I have simplified the auto-generated Dockerfile by letting Visual Studio do the build. Docker then just picks up the VS build output and creates the image from there.
Create the docker image
Using Powershell, switch to the application directory, and create the docker image for the project,
Tag the image
docker tag weatherforecastapi-image us-east1-docker.pkg.dev/weatherforecastapi-proj/weatherforecastapi-repo/weatherforecastapi-image:v1.0
You can tag the image version according to your needs or just use latest.
The syntax of the push command is:
docker push REGION-docker.pkg.dev/PROJECT_ID/REPOSITORY_NAME/TAGGED_IMAGE_NAME
For our purposes these are
REGION: us-east1
PROJECT_ID: weatherforecastapi-proj
Unless they are the same, make sure it's the project_ID and not the project_NAME.
REPOSITORY_NAME: weatherforecastapi-repo
TAGGED_IMAGE_NAME: weatherforecastapi-image:v1.0
Your Artifact Registry Docker images are stored in specific regions In this sample, we are using us-east1
A full list of regionscan be found at: Geography and Regions
Create a Service
Once the image has been pushed to the Artifact Registry, go to the cloud console and select your Project - -> Cloud Run - -> Create Service
On the Create Service screen enter the values as indicated in the sample below.
To specify the container image for the service, click the SELECT - -> ARTIFACT REGISTRY, and then select the image version you pushed to the repo.
Enter the rest of the service parameters as shown in the sample below.
Note: In the example, I am allowing unauthenticated traffic. If authentication is required by your app, you'll set that up in the Kestrel pipeline in Program.cs.
Once you click the CREATE button, the process for creating and configuring the service will start.
If you are following along with this example, you will receive an error similar to this:
As of this writing, you'll always get this error unless you set your Kestrel port to 8080. To fix this error edit and re-deploy the service; changing the container port to 5175, the Kestrel listening port we used in Program.cs.
Hey! Google
....... if you are listening, please have the Cloud Run team include the Container Port in the Create Service UI. This will obviate this error and the manual correction step. As of the time of this writing the Container Port entry shows up only in the edit step; not the create step.
You can also edit the YAML file to specify the correct port; if you do this, you'll also have to update the revision property.
Unfortunately, as of the date of this writing, the UI for edititing the YAML file is a little kludgy; you can't scroll through it, you can't "Select All", you can't copy/paste -- even in Chrome; you can't download/edit and upload a replacement. Hopefully, the Cloud Run team will fix this.
In any case, this is not a show-stopper; you can always use the EDIT AND DEPLOY NEW REVISION button at the top of the screen.
Service Deployed
Once you update the container port and re-deploy, the service deployment should be successful. You'll see a screen similar to this:
Click on the service to take you to the details page
About the URL generated by Cloud Run
Note that Cloud Run generates a URL for the service automatically. Cloud Run also generates a Certificate for the service and ensures only https access. The certificate expires in a little less than 90 days. Since Cloud Run is fully managed, the Certificate will be automatically renewed prior to expiration.
Clicking on the generated URL takes you to the Swagger UI, shown earlier when the app was tested in the development environment.
You can test the service through the Swagger UI, or by appending the URL fragments (/weatherforecast, /weatherforecast/hot), as shown earlier.
Note that the redirection to https is handled by the platform, and occurs before the Kestrel pipeline.
Using a Custom Domain
In case you prefer to use your own domain instead of the generated one, click on Manage Custom Domains, and then Add Mappings as shown below.
Follow the prompts to select the service to map and the custom domain to use.
In this example, I have elected to map the service to a new subdomain of this blog site (alumdb.com). After clicking the continue button Cloud Run will provide you information needed to update your DNS records as shown below.
Once the service has been updated to use the custom domain the service screen will look like this:
You can now access the service using the custom domain as shown in the examples below:
weather.alumdb.com
weather.alumdb.com/weatherforecast
weather.alumdb.com/weatherforecast/hot
Note: These links are publicly available, feel free to try them out.
Note: Even after you setup your custom domain, the platform-generated service url is still available and functional. If you click the information icon (Show Info on Service URL's) you'll see both urls for the service:
Summary
This post has provided a step-by-step guide to implementing and deploying an ASP.NET Core 6 WebAPI to Google Cloud Run. If you are new to Cloud Run, I hope this helps you over the rough edges.
Subscribe to Technical Blogs
Get the latest posts delivered right to your inbox
You've successfully subscribed to Technical Blogs!
Subscribe to Technical Blogs
Stay up to date! Get all the latest & greatest posts delivered straight to your inbox