Scott Hanselman

Exploring ASP.NET Core with Docker in both Linux and Windows Containers

October 14, '16 Comments [26] Posted in ASP.NET | Docker | Open Source
Sponsored By

In May of last year doing things with ASP.NET and Docker was in its infancy. But cool stuff was afoot. I wrote a blog post showing how to publish an ASP.NET 5 (5 at the time, now Core 1.0) app to Docker. Later in December of 2015 new tools like Docker Toolbox and Kitematic made things even easier. In May of 2016 Docker for Windows Beta continued to move the ball forward nicely.

I wanted to see how things are looking with ASP.NET Core, Docker, and Windows here in October of 2016.

I installed these things:

Docker for Windows is really nice as it automates setting up Hyper-V for you and creates the Docker host OS and gets it all running. This is a big time saver.

Hyper-V manager

There's my Linux host that I don't really have to think about. I'll do everything from the command line or from Visual Studio.

I'll say File | New Project and make a new ASP.NET Core application running on .NET Core.

Then I right click and Add | Docker Support. This menu comes from the Visual Studio Tools for Docker extension. This adds a basic Dockerfile and some docker-compose files. Out of the box, I'm all setup to deploy my ASP.NET Core app to a Docker Linux container.

ASP.NET Core in a Docker Linux Container

Starting from my ASP.NET Core app, I'll make sure my base image (that's the FROM in the Dockerfile) is the base ASP.NET Core image for Linux.

FROM microsoft/aspnetcore:1.0.1
ENTRYPOINT ["dotnet", "WebApplication4.dll"]
ARG source=.
WORKDIR /app
EXPOSE 80
COPY $source .

Next, since I don't want Docker to do the building of my application yet, I'll publish it locally. Be sure to read Steve Lasker's blog post "Building Optimized Docker Images with ASP.NET Core" to learn how to have one docker container build your app and the other run it it. This optimizes server density and resource.

I'll publish, then build the images, and run it.

>dotnet publish

>docker build bin\Debug\netcoreapp1.0\publish -t aspnetcoreonlinux

>docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
aspnetcoreonlinux latest dab2bff7e4a6 28 seconds ago 276.2 MB
microsoft/aspnetcore 1.0.1 2e781d03cb22 44 hours ago 266.7 MB

>docker run -it -d -p 85:80 aspnetcoreonlinux
1cfcc8e8e7d4e6257995f8b64505ce25ae80e05fe1962d4312b2e2fe33420413

>docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1cfcc8e8e7d4 aspnetcoreonlinux "dotnet WebApplicatio" 2 seconds ago Up 1 seconds 0.0.0.0:85->80/tcp clever_archimedes

And there's my ASP.NET Core app running in Docker. So I'm running Windows, running Hyper-V, running a Linux host that is hosting Docker containers.

What else can I do?

ASP.NET Core in a Docker Windows Container running Windows Nano Server

There's Windows Server, there's Windows Server Core that removes the UI among other things and there's Windows Nano Server which gets Windows down to like hundreds of megs instead of many gigs. This means there's a lot of great choices depending on what you need for functionality and server density. Ship as little as possible.

Let me see if I can get ASP.NET Core running on Kestrel under Windows Nano Server. Certainly, since Nano is very capable, I could run IIS within the container and there's docs on that.

Michael Friis from Docker has a great blog post on building and running your first Docker Windows Server Container. With the new Docker for Windows you can just right click on it and switch between Linux and Windows Containers.

Docker switches between Mac and Windows easily

So now I'm using Docker with Windows Containers. You may not know that you likely already have Windows Containers! It was shipped inside Windows 10 Anniversary Edition. You can check for Containers in Features:

Add Containers in Windows 10

I'll change my Dockerfile to use the Windows Nano Server image. I can also control the ports that ASP.NET talks on if I like with an Environment Variable and Expose that within Docker.

FROM microsoft/dotnet:nanoserver
ENTRYPOINT ["dotnet", "WebApplication4.dll"]
ARG source=.
WORKDIR /app
ENV ASPNETCORE_URLS http://+:82
EXPOSE 82
COPY $source .

Then I'll publish and build...

>dotnet publish
>docker build bin\Debug\netcoreapp1.0\publish -t aspnetcoreonnano

Then I'll run it, mapping the ports from Windows outside to the Windows container inside!

NOTE: There's a bug as of this writing that affects how Windows 10 talks to Containers via "NAT" (Network Address Translation) such that you can't easily go http://localhost:82 like you (and I) want to. Today you have to hit the IP of the container directly. I'll report back once I hear more about this bug and how it gets fixed. It'll show up in Windows Update one day. The workaround is to get the IP address of the container from docker like this:  docker inspect -f "{{ .NetworkSettings.Networks.nat.IPAddress }}" HASH

So I'll run my ASP.NET Core app on Windows Nano Server (again, to be clear, this is running on Windows 10 and Nano Server is inside a Container!)

>docker run -it -d -p 88:82 aspnetcoreonnano
afafdbead8b04205841a81d974545f033dcc9ba7f761ff7e6cc0ec8f3ecce215

>docker inspect -f "{{ .NetworkSettings.Networks.nat.IPAddress }}" afa
172.16.240.197

Now I can hit that site with 172.16.240.197:82. Once that bug above is fixed, it'll get hit and routed like any container.

The best part about Windows Containers is that they are fast and lightweight. Once the image is downloaded and build on your machine, you're starting and stopping them in seconds with Docker.

BUT, you can also isolate Windows Containers using Docker like this:

docker run --isolation=hyperv -it -d -p 86:82 aspnetcoreonnano

So now this instance is running fully isolated within Hyper-V itself. You get the best of all worlds. Speed and convenient deployment plus optional and easy isolation.

ASP.NET Core in a Docker Windows Container running Windows Server Core 2016

I can then change the Dockerfile to use the full Windows Server Core image. This is 8 gigs so be ready as it'll take a bit to download and extract but it is really Windows. You can also choose to run this as a container or as an isolated Hyper-V container.

Here I just change the FROM to get a Windows Sever Core with .NET Core included.

FROM microsoft/dotnet:1.0.0-preview2-windowsservercore-sdk
ENTRYPOINT ["dotnet", "WebApplication4.dll"]
ARG source=.
WORKDIR /app
ENV ASPNETCORE_URLS http://+:82
EXPOSE 82
COPY $source .

NOTE: I hear it's likely that the the .NET Core on Windows Server Core images will likely go away. It makes more sense for .NET Core to run on Windows Nano Server or other lightweight images. You'll use Server Core for heavier stuff, and Server is nice because it means you can run "full" .NET Framework apps in containers! If you REALLY want to have .NET Core on Server Core you can make your own Dockerfile and easily build and image that has the things you want.

Then I'll publish, build, and run again.

>docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
aspnetcoreonnano latest 7e02d6800acf 24 minutes ago 1.113 GB
aspnetcoreonservercore latest a11d9a9ba0c2 28 minutes ago 7.751 GB

Since containers are so fast to start and stop I can have a complete web farm running with Redis in a Container, SQL in another, and my web stack in a third. Or mix and match.

>docker ps
CONTAINER ID IMAGE COMMAND PORTS NAMES
d32a981ceabb aspnetcoreonwindows "dotnet WebApplicatio" 0.0.0.0:87->82/tcp compassionate_blackwell
a179a48ca9f6 aspnetcoreonnano "dotnet WebApplicatio" 0.0.0.0:86->82/tcp determined_stallman
170a8afa1b8b aspnetcoreonnano "dotnet WebApplicatio" 0.0.0.0:89->82/tcp agitated_northcutt
afafdbead8b0 aspnetcoreonnano "dotnet WebApplicatio" 0.0.0.0:88->82/tcp naughty_ramanujan
2cf45ea2f008 a7fa77b6f1d4 "dotnet WebApplicatio" 0.0.0.0:97->82/tcp sleepy_hodgkin

Conclusion

Again, go check out Michael's article where he uses Docker Compose to bring up the ASP.NET Music Store sample with SQL Express in one Windows Container and ASP.NET Core in another as well as Steve Lasker's blog (in fact his whole blog is gold) on making optimized Docker images with ASP.NET Core.

IMAGE ID            RESPOSITORY                   TAG                 SIZE
0ec4274c5571 web optimized 276.2 MB
f9f196304c95 web single 583.8 MB
f450043e0a44 microsoft/aspnetcore 1.0.1 266.7 MB
706045865622 microsoft/aspnetcore-build 1.0.1 896.6 MB

Steve points out a number of techniques that will allow you to get the most out of Docker and ASP.NET Core.

The result of all this means (IMHO) that you can use ASP.NET Core:

  • ASP.NET Core on Linux
    • within Docker containers
    • in any Cloud
  • ASP.NET Core on Windows, Windows Server, Server Core, and Nano Server.
    • within Docker windows containers
    • within Docker isolated Hyper-V containers

This means you can choose the level of feature support and size to optimize for server density and convenience. Once all the tooling (the Docker folks with Docker for Windows and the VS folks with Visual Studio Docker Tools) is baked, we'll have nice debugging and workflows from dev to production.

What have you been doing with Docker, Containers, and ASP.NET Core? Sound off in the comments.


Sponsor: Thanks to Redgate this week! Discover the world’s most trusted SQL Server comparison tool. Enjoy a free trial of SQL Compare, the industry standard for comparing and deploying SQL Server schemas.

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
Friday, 14 October 2016 21:19:23 UTC
One thing that would be nice, would be for docker on windows (linux containers) and docker for windows containers to get along better, so that I can easily launch either with the same tooling... doing so is really unclear, I've also been on the insider channel, so may have borked my configuration... upgraded from Windows 7 to 10, and haven't done a clean install of 10.

Previously, I'd just used cifs/samba shares to run in a linux vm, and ssh from windows with a gui editor, which had worked well enough. Had wanted to play with Linux Subsystem for Windows and the Docker with Windows Containers, and now neither seem to want to work right with anything else, so caveat emptor.

I do hope that in the long run, the LSW shims get to a point that docker for windows containers can also support linux containers, which will be close to the grael for me.
Michael J. Ryan
Friday, 14 October 2016 21:20:37 UTC
Totally agree. I'd like to be able to compose a hybrid system.
Scott Hanselman
Saturday, 15 October 2016 00:48:02 UTC
I think when the swarm part of docker is implemented in the Windows version we will be able to do swarm of Windows host and Linux host linked together via the docker swarm init call. It will look like one docker host and people will be able to target via tags which underlying host type they want to use.
Paul Kling
Saturday, 15 October 2016 01:31:25 UTC
What the heck is Docker? Try as I might, I can not find an article on it to ELI5.
Craig
Saturday, 15 October 2016 02:00:36 UTC
For the Windows/Linux simultaneous question; that is our goal. Getting the switch between Linux and Windows was the first step. Supporting Linux and Windows simultaneously is our next step. There are some complications for which host to call on docker build, but we believe we can get to a point where you can include labels in your docker-compoose.yml file to target the right host. Then, you can run your windows containers and Linux containers side by side for a truly hybrid environment.
Steve
Saturday, 15 October 2016 02:37:50 UTC
@craig I recorded an introduction to docker a few months back. Try watching https://channel9.msdn.com/Series/aspnetmonsters/Episode-14-Docker
Saturday, 15 October 2016 07:27:04 UTC
Microsoft's progress continues which is great to see. There is a nagging thought though, that if it really wants to put .net core "on the menu", surely this needs to work out of the box on ALL Windows 10 SKU? Anyone choosing a linux or Mac can do this out of the box, Windows 10 can't unless you have Pro or Enterprise.
Paul
Saturday, 15 October 2016 08:59:56 UTC
If we can have WSL(windows subsystem for Linux) running inside Windows server 2016 container, having powershell commands to initialize a Linux process, we could have native Linux applications running on windows containers. why? We don't want to manage Windows and Linux clusters, if we can have just one.
Bare metal is something that we have to think about!
Azure App Service now supports Linux as Host, but if you have a hybrid environment means 2 app services plans, and more costs. If they could initialize a Linux process as well, we could have a hybrid app service environment. What do you think about that?
Saturday, 15 October 2016 12:13:31 UTC
you need to run VS in Administrator mode to connect to docker!
rs38
Sunday, 16 October 2016 20:11:35 UTC
rs38,
I'm curious why you're seeing the need to run VS as Administrator to connect to Docker. This isn't the behavior we're seeing with our tools, so I'm curious what configuration you're using to require this.
Steve
Monday, 17 October 2016 08:27:47 UTC
I don't get this obsession people have with wanting to do everything on the command line, I thought the MS ecosystem and evolved in to drag and drop / point and click?
TehWardy
Monday, 17 October 2016 09:07:56 UTC
hi..
i am following this blog in around a year and i never stopped reading!
thanks ...
Monday, 17 October 2016 10:36:37 UTC
Hi Scott,

Thanks for the great post... maybe you can shed some light on when us Enterprise Windows 10 users can expect with anniversary update (via Update) so we can get container support without a full reinstall ?

Thanks,
Steve
Stephen Knott
Monday, 17 October 2016 11:07:39 UTC
wow as quality content, I'm quite looking forward to the next posts, as I follow you
Monday, 17 October 2016 12:12:38 UTC
As Docker only runs on Linux today, we need a Linux machine or VM to run Docker on our server.
Monday, 17 October 2016 14:05:27 UTC
Totally irrelevant:

I see on the main page of LinqPad (https://www.linqpad.net/) this quote:

“Fantastic Learning Tool”
- Scott Hanselman, Principal Program Manager, Microsoft


I am using LinqPad everyday and I can tell you with great certainty that LinqPad is a replacement for PowerShell, not a learning tool. If it was a learning tool, it would be a terrible one, since the free version doesn't even have intellisense.
I have been working for years with .NET and I cannot live without this tool. So, definitely nothing to do with learning tools...

As for Docker and Linux, despite the fact that I would like to have my site running on Linux, so that I won't have to pay MS any money for the server OS, it would be MUCH better if you improved your OS and just throw Linux away. Your OS code might be a bit messy, but the Linux people have their heads messed up, so no benefit moving there...
Well... unless you could make your own version of Linux and call it something different (so that our stomach doesn't get sick) and which would work in the literal sense of the word and not like mainstream, free Linux "works".
DJ
Monday, 17 October 2016 14:21:53 UTC
There is something container-related that I'm having a hard time finding info on that I hope one of the Scotts or somebody could help me with. I've done a few of these tutorials- I've spun up docker host, published a container, ran ASP.NET on Linux in a container. Cool, I see how that's nice. Now I want that host to be something secure that I can let 10-20 developers in an enterprise publish and run containers in, but nobody else.

How is one supposed to go about ensuring only certain people can publish and run containers on a host? In the tutorials I've seen (this one included), I don't see where there are any credentials, certificates, etc. required to "docker publish" or "docker run". When I stood up a linux host and did some tutorials, I was able to publish and run without entering a password for the linux box. Again, I'm assuming I'm being dumb here, but any help showing me how these things are supposed to happen in the real world would be much appreciated.
Monday, 17 October 2016 16:53:45 UTC
This is awesome!

Except, ugh:
NOTE: I hear it's likely that the the .NET Core on Windows Server Core images will likely go away. It makes more sense for .NET Core to run on Windows Nano Server or other lightweight images. You'll use Server Core for heavier stuff. If you REALLY want to have .NET Core on Server Core you can make your own Dockerfile and easily build and image that has the things you want.


Whoever is in charge of Naming Stuff needs to be shot! It's extremely unfortunate that <Application Platform> "Core" is not going to be recommended to be used with <Operating System> "Core".

Clearly the fix is to rename .NET Core to .NET Nano Server! :D
Rob H
Tuesday, 18 October 2016 06:08:07 UTC
Thanks Scott once again for the nice article. I was just following it step by step and tumbled upon on this error!

dotnet : The term 'dotnet' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
dotnet publish
CategoryInfo : ObjectNotFound: (dotnet:String) [], CommandNotFoundException
FullyQualifiedErrorId : CommandNotFoundException


Isn't dotnetcore stable enough? Because the installation went well, I even did a repair, but no luck.

Docker is working great though.

Thanks.
Tuesday, 18 October 2016 06:27:05 UTC
Apology! Commented too soon. Just needed to restart the powershell. Apart from that, needed to install bower to publish the app.

Cheers
Wednesday, 19 October 2016 03:27:07 UTC
I regularly use VMware Workstation so I can't have my computer configured for Hyper-V all the time. Restarting just to switch modes sucks.

I've found that running docker in isolation=process mode works fine for Windows 10 Pro (anniversary edition).

> docker run --isolation=process -it microsoft/nanoserver cmd


For some reason setting the default exec-opt to isolation mode and make it the default is blocked. I hope that the Windows team will support using the more normal, lightweight, process mode for Docker instead of continuing to rely on Hyper-V.
Nathan Brown
Thursday, 20 October 2016 09:49:33 UTC
@Nathan Brown,

Thank you!!! That has been one of the biggest annoyances for me as well. That's a great tip!
Rob H
Thursday, 20 October 2016 11:07:31 UTC
Docker for Windows and Visual Studio Tools for Docker wont't work for us, because we have Oracle Virtual Box running on our dev machines. Kinda sucks
b
Tuesday, 01 November 2016 18:14:57 UTC
nice blog thanks for sharing this article
Sunday, 06 November 2016 15:20:04 UTC
How is this going to work with licensing? Its very easy to spin up containers. With Linux you don't worry about licensing costs, but how about Windows containers? Are those free on Windows Server 2016 Data Center edition?
If not, what would be a reason to use Windows (Nano) containers for our .NET Core apps, instead of Linux?
Saturday, 12 November 2016 23:00:44 UTC
Can I use windows container on Windows 10 to run application that I want to try but dont fully trust? Like the kind of application I would normally run in VM.
urza
Comments are closed.

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