Scott Hanselman

How to set up Kubernetes on Windows 10 with Docker for Windows and run ASP.NET Core

January 30, '18 Comments [17] Posted in DotNetCore | Kubernetes | Open Source
Sponsored By

Docker for Windows is really coming along nicely. They have both a Stable and Edge channel and the Edge (beta, experimental) one just included a lovely new feature - Kubernetes support. Per their docs, Kubernetes is only available in Docker for Windows 18.02 CE Edge. They set most everything up nicely and put Kubectl into your path and setup a context. If you use kubectl for other things - like your own Raspberry Pi Kubernetes Cluster, then you'll need to be aware of switching contexts. Same thing applies if you have one in the cloud, like the Kubernetes Cluster I made in Azure AKS.

Got Docker for Windows? If you have not yet installed Docker for Windows, see Install Docker for Windows for an explanation of stable and edge channels, system requirements, and download/install information.

It's easy to get started, just click "Enable Kubernetes" and Docker for Windows will download and start the images you need. I clicked "show system containers" because I like to see what's hidden from me, but you decide for yourself. Do be aware - there's a TON.

Enabling Kubernetes in Docker for Windows

By default, you won't get the Kubernetes Dashboard - of which I'm a fan - so you may want to install that. If you follow the default instructions (and you're a noob like me) then you'll likely end up with a Dashboard that is pretty locked down. It can be somewhat frustrating to get access to your own development dashboard, so I use the alternative (read: totally insecure) dashboard, like this:

C:\> kubectl apply -f

I also like charts and graphs so I added these as well:

C:\> kubectl create -f
C:\> kubectl create -f
C:\> kubectl create -f

I can access the dashboard by default by running "kubectl proxy" then visiting this http://localhost:8001/ui and I'll get redirected to the dashboard:

Kuberenetes Dashboard

Now I can run through all the cool Kubernetes tutorials like the Guestbook Kubernetes Sample Application from the convenience of my Windows 10 machine. (I'm running a SurfaceBook 2 on the current non-Beta Windows 10.)

There are a lot of nice samples on running .NET Core and ASP.NET Core apps with Docker up at

I made a quick ASP.NET Core app called kubeaspnetapp:

C:\Users\scott\Desktop>dotnet new razor -o kubeaspnetapp
The template "ASP.NET Core Web App" was created successfully.
Restore succeeded.

Then added a two-stage build DockerFile that looks like this:

FROM microsoft/aspnetcore-build:2.0 AS build-env

# 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 microsoft/aspnetcore:2.0
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "kubeaspnetapp.dll"]

And built and tagged the image with:

C:\Users\scott\Desktop\kubeaspnetapp>docker build -t kubeaspnetapp:v1 .

Then I create a quick Deployment that manages a Pod that runs the Container:

C:\Users\scott\Desktop\kubeaspnetapp>kubectl run kubeaspnetapp --image=kubeaspnetapp:v1 --port=80
deployment "kubeaspnetapp" created

Now I'll expose it to the "outside." Again, this is usually done with .yaml files but it's a good learning exercise and it's all local.

C:\Users\scott\Desktop\kubeaspnetapp>kubectl get deployments
kubeaspnetapp   1         1         1            1           1m

C:\Users\scott\Desktop\kubeaspnetapp>kubectl get pods
NAME                             READY     STATUS    RESTARTS   AGE
kubeaspnetapp-778f6d49bd-rct59   1/1       Running   0          1m

C:\Users\scott\Desktop\kubeaspnetapp>kubectl expose deployment kubeaspnetapp --type=NodePort
service "kubeaspnetapp" exposed

C:\Users\scott\Desktop\kubeaspnetapp>kubectl get services
NAME            TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubeaspnetapp   LoadBalancer   <pending>     80:31756/TCP     5s
kubernetes      ClusterIP      <none>        443/TCP          1d

Then I'll hit in my browser...note how that port is brokering to the internal port 80 where the app listens...and there's my ASP.NET Core app running locally on Kubernetes, set up with Docker for Windows. Nice.

My ASP.NET Core app running in Kubernetes local on my Windows 10 machine

Here's me getting the startup logs from that pod:

C:\Users\scott\>kubectl get pods
NAME                             READY     STATUS    RESTARTS   AGE
kubeaspnetapp-7fd7f7ffb9-8gnzd   1/1       Running   0          6m

C:\Users\scott\Dropbox\k8s for pi\aspnetcoreapp>kubectl logs kubeaspnetapp-7fd7f7ffb9-8gnzd
Hosting environment: Production
Content root path: /app
Now listening on: http://[::]:80
Application started. Press Ctrl+C to shut down.

Pretty cool. As all the tooling and things across Windows, Docker, Kubernetes, Visual Studio (all flavors) continues to get better and better, I can only imagine this experience will get better and better. I look forward to a time when I can freely mix containers from different OSs and easily push them all en masse to Azure.

Sponsor: Get the latest JetBrains Rider for debugging third-party .NET code, Smart Step Into, more debugger improvements, C# Interactive, new project wizard, and formatting code in columns.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

ASP.NET Single Page Applications Angular Release Candidate

January 8, '18 Comments [28] Posted in DotNetCore | Javascript
Sponsored By

I was doing some Angular then remembered that the ASP.NET "Angular Project Template" has a release candidate and is scheduled to release sometime soon in 2018.

Starting with just a .NET Core 2.0 install plus Node v6 or later, I installed the updated angular template. Note that this isn't the angular/react/redux templates that came with .NET Core's base install.

I'll start by adding the updated SPA (single page application) template:

dotnet new --install Microsoft.DotNet.Web.Spa.ProjectTemplates::2.0.0-rc1-final

Then from a new directory, just

dotnet new angular

Then I can open it in either VSCode or Visual Studio Community (free for Open Source). If you're interested in the internals, open up the .csproj project file and note the checks for ensuring node is install, running npm, and running WebPack.

If you've got the Angular "ng" command line tool installed you can do the usual ng related stuff, but you don't need to run "ng serve" because ASP.NET Core will run it automatically for you.

I set development mode with "SET ASPNETCORE_Environment=Development" then do a "dotnet build." It will also restore your npm dependencies as part of the build. The client side app lives in ./ClientApp.

C:\Users\scott\Desktop\my-new-app> dotnet build
Microsoft (R) Build Engine version 15.5 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

Restore completed in 73.16 ms for C:\Users\scott\Desktop\my-new-app\my-new-app.csproj.
Restore completed in 99.72 ms for C:\Users\scott\Desktop\my-new-app\my-new-app.csproj.
my-new-app -> C:\Users\scott\Desktop\my-new-app\bin\Debug\netcoreapp2.0\my-new-app.dll
Restoring dependencies using 'npm'. This may take several minutes...

"dotnet run" then starts the ng development server and ASP.NET all at once.

My ASP.NET Angular Application

If we look at the "Fetch Data" menu item, you can see and example of how Angular and open source ASP.NET Core work together. Here's the Weather Forecast *client-side* template:

<p *ngIf="!forecasts"><em>Loading...</em></p>

<table class='table' *ngIf="forecasts">
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<tr *ngFor="let forecast of forecasts">
<td>{{ forecast.dateFormatted }}</td>
<td>{{ forecast.temperatureC }}</td>
<td>{{ forecast.temperatureF }}</td>
<td>{{ forecast.summary }}</td>

And the TypeScript:

import { Component, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';

selector: 'app-fetch-data',
templateUrl: './fetch-data.component.html'
export class FetchDataComponent {
public forecasts: WeatherForecast[];

constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
this.forecasts = result;
}, error => console.error(error));

interface WeatherForecast {
dateFormatted: string;
temperatureC: number;
temperatureF: number;
summary: string;

Note the URL. Here's the back-end. The request is serviced by ASP.NET Core. Note the interface as well as the TemperatureF server-side conversion.

public class SampleDataController : Controller
private static string[] Summaries = new[]
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"

public IEnumerable<WeatherForecast> WeatherForecasts()
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
DateFormatted = DateTime.Now.AddDays(index).ToString("d"),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]

public class WeatherForecast
public string DateFormatted { get; set; }
public int TemperatureC { get; set; }
public string Summary { get; set; }

public int TemperatureF
return 32 + (int)(TemperatureC / 0.5556);

Pretty clean and straightforward. Not sure about the Date.Now, but for the most part I understand this and can see how to extend this. Check out the docs on this release candidate and also note that this included updated React and Redux templates as well!

Sponsor: Scale your Python for big data & big science with Intel® Distribution for Python. Near-native code speed. Use with NumPy, SciPy & scikit-learn. Get it Today!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Accelerated 3D VR, sure, but impress me with a nice ASCII progress bar or spinner

December 4, '17 Comments [13] Posted in DotNetCore
Sponsored By

I'm glad you have a 1080p 60fps accelerated graphics setup, but I'm old school. Impress me with a really nice polished ASCII progress bar or spinner!

I received two tips this week about cool .NET Core ready progress bars so I thought I'd try them out.

ShellProgressBar by Martijn Laarman

This one is super cool. It even supports child progress bars for async stuff happening in parallel! It's very easy to use. I was able to get a nice looking progress bar going in minutes.

static void Main(string[] args)
const int totalTicks = 100;
var options = new ProgressBarOptions
ForegroundColor = ConsoleColor.Yellow,
ForegroundColorDone = ConsoleColor.DarkGreen,
BackgroundColor = ConsoleColor.DarkGray,
BackgroundCharacter = '\u2593'
using (var pbar = new ProgressBar(totalTicks, "Initial message", options))
pbar.Tick(); //will advance pbar to 1 out of 10.
//we can also advance and update the progressbar text
pbar.Tick("Step 2 of 10");
TickToCompletion(pbar, totalTicks, sleep: 50);


Cool ASCII Progress Bars in .NET Core

Be sure to check out the examples for ShellProgressBar, specifically ExampleBase.cs where he has some helper stuff like TickToCompletion() that isn't initially obvious.

Kurukuru by Mayuki Sawatari

Another nice progress system that is in active development for .NET Core (like super active...I can see they updated code an hour ago!) is called Kurukuru. This code is less about progress bars and more about spinners. It's smart about Unicode vs. non-Unicode as there's a lot of cool characters you could use in a Unicode-aware console that make for attractive spinners.

What a lovely ASCII Spinner in .NET Core!

Kurukuru is also super easy to use and integrated into your code. It also uses the "using" disposable pattern in a clever way. Wrap your work and if you throw an exception, it will show a failed spinner.

Spinner.Start("Processing...", () =>
Thread.Sleep(1000 * 3);

// MEMO: If you want to show as failed, throw a exception here.
// throw new Exception("Something went wrong!");

Spinner.Start("Stage 1...", spinner =>
Thread.Sleep(1000 * 3);
spinner.Text = "Stage 2...";
Thread.Sleep(1000 * 3);
spinner.Fail("Something went wrong!");

TIP: If your .NET Core console app wants to use an async Main (like I did) and call Kurukuru's async methods, you'll want to indicate you want to use the latest C# 7.1 features by adding this to your project's *.csproj file:


This allowed me to do this:

public static async Task Main(string[] args)
Console.WriteLine("Hello World!");
await Spinner.StartAsync("Stage 1...", async spinner =>
await Task.Delay(1000 * 3);
spinner.Text = "Stage 2...";
await Task.Delay(1000 * 3);
spinner.Fail("Something went wrong!");

Did I miss some? I'm sure I did. What nice ASCII progress bars and spinners make YOU happy?

And again, as with all Open Source, I encourage you to HELP OUT! I know the authors would appreciate it.

Sponsor: Check out JetBrains Rider: a new cross-platform .NET IDE. Edit, refactor, test and debug ASP.NET, .NET Framework, .NET Core, Xamarin or Unity applications. Learn more and download a 30-day trial!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Writing smarter cross-platform .NET Core apps with the API Analyzer and Windows Compatibility Pack

November 25, '17 Comments [12] Posted in DotNetCore
Sponsored By

.NET Core is Open Source and Cross PlatformThere's a couple of great utilities that have come out in the last few weeks in the .NET Core world that you should be aware of. They are deeply useful when porting/writing cross-platform code.

.NET API Analyzer

First is the API Analyzer. As you know, APIs sometimes get deprecated, or you'll use a method on Windows and find it doesn't work on Linux. The API Analyzer is a Roslyn (remember Roslyn is the name of the C#/.NET compiler) analyzer that's easily added to your project as a NuGet package. All you have to do is add it and you'll immediately start getting warnings and/or squiggles calling out APIs that might be a problem.

Check out this quick example. I'll make a quick console app, then add the analyzer. Note the version is current as of the time of this post. It'll change.

C:\supercrossplatapp> dotnet new console
C:\supercrossplatapp> dotnet add package Microsoft.DotNet.Analyzers.Compatibility --version 0.1.2-alpha

Then I'll use an API that only works on Windows. However, I still want my app to run everywhere.

static void Main(string[] args)
Console.WriteLine("Hello World!");

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
var w = Console.WindowWidth;
Console.WriteLine($"Console Width is {w}");

Then I'll "dotnet build" (or run, which implies build) and I get a nice warning that one API doesn't work everywhere.

C:\supercrossplatapp> dotnet build

Program.cs(14,33): warning PC001: Console.WindowWidth isn't supported on Linux, MacOSX [C:\Users\scott\Desktop\supercr
supercrossplatapp -> C:\supercrossplatapp\bin\Debug\netcoreapp2.0\supercrossplatapp.dll

Build succeeded.

Olia from the .NET Team did a great YouTube video where she shows off the API Analyzer and how it works. The code for the API Analyzer up here on GitHub. Please leave an issue if you find one!

Windows Compatibility Pack for .NET Core

Second, the Windows Compatibility Pack for .NET Core is a nice piece of tech. When .NET Core 2.0 come out and the .NET Standard 2.0 was finalized, it included over 32k APIs that made it extremely compatible with existing .NET Framework code. In fact, it's so compatible, I was able to easily take a 15 year old .NET app and port it over to .NET Core 2.0 without any trouble at all.

They have more than doubled the set of available APIs from 13k in .NET Standard 1.6 to 32k in .NET Standard 2.0.

.NET Standard 2.0 is cool because it's supported on the following platforms:

  • .NET Framework 4.6.1
  • .NET Core 2.0
  • Mono 5.4
  • Xamarin.iOS 10.14
  • Xamarin.Mac 3.8
  • Xamarin.Android 7.5

When you're porting code over to .NET Core that has lots of Windows-specific dependencies, you might find yourself bumping into APIs that aren't a part of .NET Standard 2.0. So, there's a new (preview) Microsoft.Windows.Compatibility NuGet package that "provides access to APIs that were previously available only for .NET Framework."

There will be two kinds of APIs in the Compatibility Pack. APIs that were a part of Windows originally but can work cross-platform, and APIs that will always be Windows only, because they are super OS-specific. APIs calls to the Windows Registry will always be Windows-specific, for example. But the System.DirectoryServices or System.Drawing APIs could be written in a way that works anywhere. The Windows Compatibility Pack adds over 20,000 more APIs, on top of what's already available in .NET Core. Check out the great video that Immo shot on the compat pack.

The point is, if the API that is blocking you from using .NET Core is now available in this compat pack, yay! But you should also know WHY you are pointing to .NET Core. Work continues on both .NET Core and .NET (Full) Framework on Windows. If your app works great today, there's no need to port unless you need a .NET Core specific feature. Here's a great list of rules of thumb from the docs:

Use .NET Core for your server application when:+

  • You have cross-platform needs.
  • You are targeting microservices.
  • You are using Docker containers.
  • You need high-performance and scalable systems.
  • You need side-by-side .NET versions per application.

Use .NET Framework for your server application when:

  • Your app currently uses .NET Framework (recommendation is to extend instead of migrating).
  • Your app uses third-party .NET libraries or NuGet packages not available for .NET Core.
  • Your app uses .NET technologies that aren't available for .NET Core.
  • Your app uses a platform that doesn’t support .NET Core.

Finally, it's worth pointing out a few other tools that can aid you in using the right APIs for the job.


Sponsor: Get the latest JetBrains Rider preview for .NET Core 2.0 support, Value Tracking and Call Tracking, MSTest runner, new code inspections and refactorings, and the Parallel Stacks view in debugger.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Trying out new .NET Core Alpine Docker Images

November 22, '17 Comments [20] Posted in Docker | DotNetCore | Open Source
Sponsored By

Docker ContainersI blogged recently about optimizing .NET and ASP.NET Docker files sizes. .NET Core 2.0 has previously been built on a Debian image but today there is preview image with .NET Core 2.1 nightlies using Alpine. You can read about the announcement here about this new Alpine preview image. There's also a good rollup post on .NET and Docker.

They have added two new images:

  • 2.1-runtime-alpine
  • 2.1-runtime-deps-alpine

Alpine support is part of the .NET Core 2.1 release. .NET Core 2.1 images are currently provided at the microsoft/dotnet-nightly repo, including the new Alpine images. .NET Core 2.1 images will be promoted to the microsoft/dotnet repo when released in 2018.

NOTE: The -runtime-deps- image contains the dependancies needed for a .NET Core application, but NOT the .NET Core runtime itself. This is the image you'd use if your app was a self-contained application that included a copy of the .NET Core runtime. This is apps published with -r [runtimeid]. Most folks will use the -runtime- image that included the full .NET Core runtime. To be clear:

- The runtime image contains the .NET Core runtime and is intended to run Framework-Dependent Deployed applications - see sample

- The runtime-deps image contains just the native dependencies needed by .NET Core and is intended to run Self-Contained Deployed applications - see sample

It's best with .NET Core to use multi-stage build files, so you have one container that builds your app and one that contains the results of that build. That way you don't end up shipping an image with a bunch of SDKs and compilers you don't need.

NOTE: Read this to learn more about image versions in Dockerfiles so you can pick the right tag and digest for your needs. Ideally you'll pick a docker file that rolls forward to include the latest servicing patches.

Given this docker file, we build with the SDK image, then publish, and the result is about 219megs.

FROM microsoft/dotnet:2.0-sdk as builder  

RUN mkdir -p /root/src/app/dockertest
WORKDIR /root/src/app/dockertest

COPY dockertest.csproj .
RUN dotnet restore ./dockertest.csproj

COPY . .
RUN dotnet publish -c release -o published

FROM microsoft/dotnet:2.0.0-runtime

WORKDIR /root/
COPY --from=builder /root/src/app/dockertest/published .
EXPOSE 5000/tcp
CMD ["dotnet", "./dockertest.dll"]

Then I'll save this as Dockerfile.debian and build like this:

> docker build . -t shanselman/dockertestdeb:0.1 -f dockerfile.debian

With a standard ASP.NET app this image ends up being 219 megs.

Now I'll just change one line, and use the 2.1 alpine runtime

FROM microsoft/dotnet-nightly:2.1-runtime-alpine

And build like this:

> docker build . -t shanselman/dockertestalp:0.1 -f dockerfile.alpine

and compare the two:

> docker images | find /i "dockertest"
shanselman/dockertestalp 0.1 3f2595a6833d 16 minutes ago 82.8MB
shanselman/dockertestdeb 0.1 0d62455c4944 30 minutes ago 219MB

Nice. About 83 megs now rather than 219 megs for a Hello World web app. Now the idea of a microservice is more feasible!

Please do head over to the GitHub issue here and offer your thoughts and results as you test these Alpine images. Also, are you interested in a "-debian-slim?" It would be halfway to Alpine but not as heavy as just -debian.

Lots of great stuff happening around .NET and Docker. Be sure to also check out Jeff Fritz's post on creating a minimal ASP.NET Core Windows Container to see how you can squish .(full) Framework applications running on Windows containers as well. For example, the Windows Nano Server images are just 93 megs compressed.

Sponsor: Get the latest JetBrains Rider preview for .NET Core 2.0 support, Value Tracking and Call Tracking, MSTest runner, new code inspections and refactorings, and the Parallel Stacks view in debugger.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Page 1 of 9 in the DotNetCore category Next Page

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.