Skip to content

Instantly share code, notes, and snippets.

@mitchazj
Last active September 17, 2019 06:45
Show Gist options
  • Save mitchazj/61076abe427220c1057bd3db8aef061a to your computer and use it in GitHub Desktop.
Save mitchazj/61076abe427220c1057bd3db8aef061a to your computer and use it in GitHub Desktop.
Quickstart Guide: Nancy with .NET Core + Docker, on Google Cloud Run πŸš€οΈπŸš€οΈπŸš€οΈ

Quickstart Guide: Nancy with .NET Core + Docker, on Google Cloud Run

Initial Setup

In an empty folder (eg, hello_world), run the following:

dotnet new web
dotnet add package Nancy --version 2.0.0-clinteastwood
dotnet add package Microsoft.AspNetCore.Owin

Why 2.0.0-clinteastwood? The latest Nancy module is incompatible with the .NET core ecosystem (at present), which will hopefully be resolved in a future release.

If you encounter conflict errors running dotnet restore, you may need to add the following:

dotnet add package Microsoft.AspNetCore.Http
dotnet add package Microsoft.AspNetCore.Http.Abstractions
dotnet add package Microsoft.AspNetCore.Http.Features
dotnet add package Microsoft.AspNetCore.WebUtilities
dotnet add package Microsoft.Extensions.DependencyInjection.Abstractions
dotnet add package Microsoft.Extensions.ObjectPool
dotnet add package Microsoft.Extensions.Options
dotnet add package Microsoft.Extensions.Primitives
dotnet add package Microsoft.Net.Http.Headers

Helpful other libraries:

dotnet add package FaunaDB.Client --version 2.5.0

Configure Nancy

Modify Startup.cs to look like the following:

...
using Nancy.Owin;
namespace hello_world {
    public class Startup {
        ...
        public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
            // Development Errors
            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();
            }
            // Use Nancy via Owin
            // Not working? Make sure you've imported Nancy.Owin as above.
            app.UseOwin(b => b.UseNancy());
        }
    }
}

Modify Program.cs to look like the following:

namespace hello_world {
    public class Program {
        public static void Main(string[] args) {
            CreateWebHostBuilder(args).Build().Run();
        }
        public static IWebHostBuilder CreateWebHostBuilder(string[] args) {
            // Use port settings expected by Google Cloud Run
            string port = Environment.GetEnvironmentVariable("PORT") ?? "8080";
            string url = String.Concat("http://0.0.0.0:", port);
            // Return WebHostBuilder
            return WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().UseUrls(url);
        }
    }
}

Finally, create a default route class under api\MainModule.cs (note: location or name don't actually matter, anything works as long as your classes inherit NancyModule)

using Nancy;
namespace hello_world {
  public class MainModule : NancyModule {
    public MainModule() {
      Get("/", args => "Hello World, it's Nancy on .NET Core");
    }
  }
}

Checkpoint #1: Test Nancy Locally

In the root directory of your project, run

dotnet run

to compile and run your application. It should be visible at http://localhost:8080/

Dockerize

Create a Dockerfile at root level with the following:

FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build-env
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2
WORKDIR /app
COPY --from=build-env /app/out .

# IMPORTANT!
# Remember to update 'hello_world' below to the name of your app.
ENTRYPOINT ["dotnet", "hello_world.dll"]

and a .dockerignore with the following:

Dockerfile
**/obj/
**/bin/

Checkpoint #2: Test your Docker container

In the root directory of your project, run the following to build your application image.

docker build -t hello_world .

if you run into errors with dotnet restore within the docker build, try:

docker build --network=host -t backend .

Once completed, run

docker run -d -p 8080:8080 --name hw_demo hello_world

to test your image inside a container. It should be visible at http://localhost:8080/. Once you are done, be sure to clear up the container with:

docker kill hw_demo

Push your app to Google Cloud Run

In the root directory of your project, run

gcloud builds submit --tag gcr.io/PROJECT-ID/hello_world

Note that PROJECT-ID is the name of your GCP project that you are deploying to. Make sure that you have enabled Google Cloud Run and Container Registry.

To deploy:

gcloud beta run deploy --image gcr.io/PROJECT-ID/hello_world --platform managed

Be sure to choose us-central1 as your region (for now), and choose y when allowing unauthenticated invocations if you are building an external API.

Next steps

TBC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment