Sunday, January 15, 2017

Docker and .NET on a Windows machine

It was time to take some first steps with Docker (way past time some might claim). I was moved to have a bash (pun – see later) on a Friday afternoon after seeing an intro article in issue 28 of the DNC “magazine” written by Daniel Jimenez Garcia. However I did hit the odd issue when following the article so this post follows the first steps but includes the odd tweak. I am writing this based upon a Windows 10 Pro, 64 bit host machine – valid alternate hosts exist but this is what I have and I suspect will be available to many who want to dip in a toe. The Hyper-V package must be enabled for Docker on Windows to work. The Docker for Windows installer will enable it for you, if needed. I think that Developer Mode must also be set for your Windows 10 installation in “Settings : Update and Security” but you probably already have that set.

First off, install Docker for Windows 10. Browse to https://www.docker.com/ click “Get Started” and then the offered download option. Run the install (.msi) and after the usual confirmations and a little set-up delay you will get confirmation of a successful install with the option to start Docker. Go for it.

Fire up a Command Prompt and then type the following

>docker run --rm –it microsoft/dotnet:latest

 Docker then looks for the microsoft/dotnet image and if it is not found (as this is the first use) then it will be downloaded and installed. This will take a few short minutes during which there is plenty of feedback on progress.

N.B. If you follow the DNC article you will see that the image name has been capitalised there (Microsoft/dotnet) but this is a magazine editing error.

Docker will then start a new container for the downloaded image and execute the appropriate entry point with the container attached to your Command Prompt so you can interact with it.
You should see a Linux bash prompt – something like:

root@6077575d9218:/# 

which is particularly cool if you have not previously fired up Linux on you Windows 10 installation.

Now we can create a new folder (don’t worry, as we typed –rm none of this will exist once you exit so will not clutter up your hard drive). Then create a new .NET program in that folder and run it.

root@6077575d9218:/# mkdir hellodocker
root@6077575d9218:/# cd hellodocker
root@6077575d9218:/hellodocker# dotnet new
Created new C# project in /hellodocker.
root@6077575d9218:/hellodocker# dotnet restore
log  : Restoring packages for /hellodocker/project.json...
root@6077575d9218:/hellodocker# dotnet run
Project hellodocker (.NETCoreApp,Version=v1.1) will be compiled because expected outputs are missing
Compiling hellodocker for .NETCoreApp,Version=v1.1
Compilation succeeded.
      0 Warning(s)
      0 Error(s)
Time elapsed 00:00:05.7903169
Hello World!
root@6077575d9218:/hellodocker#

We have just run a .NET Core program in a Docker instance running on a Linux virtual machine hosted by our Windows 10 PC.

Type exit to terminate the container and return to the command prompt.

We are next going to create a .NET program instance in a Windows folder. This makes use of the .Net Command Line Interface (CLI) which may not yet be installed on your machine. The simplest way to check is to try and use it with the following sequence of commands:

>mkdir hellodocker
 >cd hellodocker 
>dotnet new

And if you get an error message from the last command then you will need to install the Command Line Interface. The latest version should be available here https://www.microsoft.com/net/core#windowsvs2015

The install presupposes that you have Visual Studio 2015 installed and that it is up to date (update 3 as at January 2017). Once installed you will need to close and re-open your command prompt window as the system path has now been updated to point to dotnet.

Now typing >dotnet new will result in the response that a new C# project has been created in your folder. The folder now contains two files – Program.cs and project.json
They look like this

using System; namespace ConsoleApplication {     public class Program     {         public static void Main(string[] args)         {             Console.WriteLine("Hello World!");         }     } }
and
{ "version": "1.0.0-*", "buildOptions": {     "debugType": "portable",     "emitEntryPoint": true }, "dependencies": {}, "frameworks": {     "netcoreapp1.0": {      "dependencies": {         "Microsoft.NETCore.App": {          "type": "platform",          "version": "1.0.1"         }      },      "imports": "dnxcore50"     } } }
Now we can start a new Docker container mounting the Windows folder we just created as a volume.

 You will need to substitute your user name into the Windows path below but on my machine I typed:

docker run --rm -it -v /c/Users/mike/hellodocker:/app microsoft/ dotnet:latest

which bumped nicely into the next problem as my C: drive was not shared.

There will be a Docker icon sitting somewhere at the bottom right of your screen (could be in the “hidden” group), so right click that and select “Settings”. Click the “Shared Drives” tab and check the relevant box before the “Apply” button.

You should be prompted for your password and then Docker can implement the share. Back in our Command Prompt window, repeating the last command should see that all is now well. We can check that the Windows folder is now mounted as /app by typing the following command:

ls /app

which will list the two existing files in the .NET Core project.

Now it should be straightforward to compile and run the program with the following:

root@4c4e67eedfdc:/#  cd /app && dotnet restore && dotnet run

which in my case produced a lot of interesting output but failed to run. It looked like the two versions of .NET Core (Docker’s and the Windows CLI version just installed) were different.

The version specified in the json file I created in Windows was 1.0.1 but the Docker image was version 1.1.0. This was probably a timing issue and thus transient though I might have tried specifying a version instead of :latest in my Docker command.

The command cat project.json listed the json file and confirmed the project specified version number.

My work around was a simple text substitution in the json file:

sed -i -e 's/1.0.1/1.1.0/g' project.json

followed by a dotnet restore and dotnet run and all was well with the program compiling and executing. A quick look back at the Windows folder shows that bin and obj debug folders have been created and populated.

I can only recommend continuing with the DNC article and building some initial Docker experience – I will be next Friday. http://www.dotnetcurry.net/s/dnc-mag-28th-single

Links:

Get started with Docker for Windows https://docs.docker.com/docker-for-windows/

(Related follow up) Turning on the Windows subsystem for Linux and getting to know “Bash on Ubuntu” http://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/ with a helpful MS FAQ here https://msdn.microsoft.com/en-us/commandline/wsl/faq