Wednesday, May 31, 2017

Creating and Debugging Docker Enabled .NET Core Project in Visual Studio 2017

In this post let’s see how you can use Visual Studio 2017 to develop .NET Core application with Docker support enabled and see what happens when you build/debug.

Let’s start off by creating a ASP.NET Core Web Application (.NET Core) and I am naming it as DockerComposeWebApp.
image
ASP.NET Core Web Application (.NET Core)
Once you clicked on OK from above, you are prompted to select application type (of course, I am sure you have done this hundred times, if not thousands).
image
Enable Docker Support
And there is a new check box presented in the dialog window, that is Enable Docker Support. You can either enable Docker support from there, or as mentioned, you can enable it later.

And I am not enabling it right now, I am clicking on OK and the solution gets created. And to enable Docker support now, you can right click on the Project, select Add and then click on Docker Support (well, you should be able to right click on any root item, and do Add –> Docker Support, but not on Solution level nor file level).
image
Enable Docker Support
Once you enabled Docker support, a Dockerfile has been added to DockerComposeWebApp project and you can see a new project that is added to the solution named docker-compose with some files.

Dockerfile
FROM microsoft/aspnetcore:1.1
ARG source
WORKDIR /app
EXPOSE 80
COPY ${source:-obj/Docker/publish} .
ENTRYPOINT ["dotnet", "DockerComposeWebApp.dll"]

image
Files View - Visual Studio
If you examine the files in the File Explorer, it looks like this.
image
Files View - File Explorer
Let’s just open up the docker-compose.dcproj file.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
  <PropertyGroup Label="Globals">
    <ProjectGuid>00832628-12a5-4b9b-b434-fcabd17c57b8</ProjectGuid>
    <DockerLaunchBrowser>True</DockerLaunchBrowser>
    <DockerServiceUrl>http://localhost:{ServicePort}</DockerServiceUrl>
    <DockerServiceName>dockercomposewebapp</DockerServiceName>
  </PropertyGroup>
  <ItemGroup>
    <None Include="docker-compose.ci.build.yml" />
    <None Include="docker-compose.override.yml">
      <DependentUpon>docker-compose.yml</DependentUpon>
    </None>
    <None Include="docker-compose.vs.debug.yml">
      <DependentUpon>docker-compose.yml</DependentUpon>
    </None>
    <None Include="docker-compose.vs.release.yml">
      <DependentUpon>docker-compose.yml</DependentUpon>
    </None>
    <None Include="docker-compose.yml" />
  </ItemGroup>
</Project>
And if you have a look at the ItemGroup, that is what it gives Visual Studio the nested view in docker-compose project items. So basically there is two main docker-compose files, one is docker-compose.ci.build.yml and the other is docker-compose.yml.

Now let’s see what happens when you debug the application. Since our main interest here is in Docker side of things, let’s set the docker-compose project as the startup project. Same time you can see that the Debug target is changed to Docker (if you debug the solution having the Web App project as the startup project it will not be debugging on Docker).

Before hitting F5, let’s see is there any Docker Containers running.
image
docker images & docker ps -a
Nothing specific to our current project (DockerComposeWebApp).

Now let’s debug. After couple of seconds, the site is working (well, it should) and what we need to focus is the Build output in Visual Studio.
------ Build started: Project: docker-compose, Configuration: Debug Any CPU ------
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.debug.yml" 
               -p dockercompose1628124139 
               config
First VS is issuing docker-compose config command to validate and view the compose file and it shows the output as below.
networks: {}
services:
  dockercomposewebapp:
    build:
      args:
        source: obj/Docker/empty/
      context: C:\Users\Jaliya\Desktop\DockerComposeWebApp\DockerComposeWebApp
      dockerfile: Dockerfile
    entrypoint: tail -f /dev/null
    environment:
      ASPNETCORE_ENVIRONMENT: Development
      DOTNET_USE_POLLING_FILE_WATCHER: '1'
    image: dockercomposewebapp:dev
    labels:
      com.microsoft.visualstudio.targetoperatingsystem: linux
    ports:
    - '80'
    volumes:
    - C:\Users\Jaliya\Desktop\DockerComposeWebApp\DockerComposeWebApp:/app:rw
    - C:\Users\Jaliya\clrdbg:/clrdbg:ro
    - C:\Users\Jaliya\.nuget\packages:/root/.nuget/packages:ro
version: '2.0'
volumes: {}
Basically this is a consolidation of docker-compose.yml, docker-compose.override.yml and docker-compose.vs.debug.yml files.

Next Visual Studio is executing docker ps command setting up some filter options to see if there is already a Container related to our project.
docker  ps --filter "status=running" --filter "name=dockercompose1628124139_dockercomposewebapp_" --format {{.ID}} -n 1
And there is no output. But still above command follows couple of docker-compose kill and docker-compose down commands using docker-compose release and debug yml files.
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.release.yml" 
               -p dockercompose1628124139 
                kill
 
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.release.yml" 
               -p dockercompose1628124139 
               down 
               --rmi local 
               --remove-orphans
 
Removing network dockercompose1628124139_default
Network dockercompose1628124139_default not found.
 
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.debug.yml" 
               -p dockercompose1628124139 
               kill
 
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.debug.yml" 
               -p dockercompose1628124139 
               down 
               --rmi local 
               --remove-orphans
 
Removing network dockercompose1628124139_default
Network dockercompose1628124139_default not found.
And finally docker-compose up command with build argument is being executed.
docker-compose -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.override.yml" 
               -f "C:\Users\Jaliya\Desktop\DockerComposeWebApp\docker-compose.vs.debug.yml" 
               -p dockercompose1628124139 
               up 
               -d 
               --build
 
Creating network "dockercompose1628124139_default" with the default driver
Building dockercomposewebapp
Step 1/6 : FROM microsoft/aspnetcore:1.1
 ---> e57f6d3fac0a
Step 2/6 : ARG source
 ---> Running in 1d44520ba0ff
 ---> 3b1eab823df1
Removing intermediate container 1d44520ba0ff
Step 3/6 : WORKDIR /app
 ---> 2f8078c67f8b
Removing intermediate container 8e3775dc753a
Step 4/6 : EXPOSE 80
 ---> Running in ee30aa3b3287
 ---> 38ea46a28cd0
Removing intermediate container ee30aa3b3287
Step 5/6 : COPY ${source:-obj/Docker/publish} .
 ---> 441f4a61d8ee
Removing intermediate container 7426260a8476
Step 6/6 : ENTRYPOINT dotnet DockerComposeWebApp.dll
 ---> Running in 471fb962159c
 ---> e756ed44b5f7
Removing intermediate container 471fb962159c
Successfully built e756ed44b5f7
Creating dockercompose1628124139_dockercomposewebapp_1
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
And now if I examine Images and currently running Containers, I can see an Image is created and a Container is running related to our project.
image
docker images & docker ps
And that’s it for this post. You definitely will like to see what happens/what commands gets executed if we stop the Debugger and start back. And I will leave it with you to find it out.

Note: I have not gone through all the theoretical things related to Docker Compose as Docker maintains a rich documentation over those.

Happy Coding.

Regards,
Jaliya

Friday, May 19, 2017

Running and Exploring a Docker Linux Container

Sometimes the best way to troubleshoot and understand how a Docker Container works, is by exploring the Container. While I believe there are couple of ways to explore, one of the ways I really found useful is docker exec. Basically docker exec let’s you run commands inside a Container, and for a Linux Container we can use docker exec to bash in and run shell commands.

But to bash in of course, you need to have the Container in running state. Here in this post, I have explained how you can setup your own Container, specifically a Linux Container with ASP.NET Core MVC Application running inside.

So let’s proceed.

Currently I have no Containers running.
image
docker ps -a
And I have following set of Images.
image
docker images
Here the dockerwebapp is the Image that I am planning of creating and running a Container from. I can run the Container by issuing  docker run.
# Runs in the foreground
# Even if pressed Ctrl+C, Container is still running
PS C:\WINDOWS\system32> docker run dockerwebapp
 
# Runs in the background/detached
PS C:\WINDOWS\system32> docker run -d dockerwebapp
 
# Runs in the foreground
# If pressed Ctrl+C, Container will stop running
# Container will be displayed in docker ps -a
PS C:\WINDOWS\system32> docker run -it dockerwebapp
 
# Runs in the foreground
# If pressed Ctrl+C, Container will stop running and will get deleted
PS C:\WINDOWS\system32> docker run -it –-rm dockerwebapp
In this case, I am going to run docker run –d dockerwebapp as I want the Container to be running in the background, so for next docker commands, I don’t want to open up another PowerShell window.
image
docker run -d dockerwebapp
Now I can see that my container is running, it’s time to explore the image.
PS C:\WINDOWS\system32> docker exec -i -t blissful_roentgen /bin/bash
 
# -i -t can be use together like follows
PS C:\WINDOWS\system32> docker exec -it blissful_roentgen /bin/bash
image
docker exec
You can see that I am now in a Linux shell and I can use shell commands to explore the image. For instance to see the file system.
image
ls
Hope this helps.

Happy Coding.

Regards,
Jaliya

Thursday, May 18, 2017

Running ASP.NET Core MVC Application inside a Docker Linux Container from Windows

I have been having some quality time with Docker recently and wanted to get an ASP.NET Core application running in a Docker Linux Container which will run inside my Windows machine. Was having some hard time getting it to work initially, but with some great help and guidance from a fellow MVP, Alex Thissen (@alexthissen), managed to get it up and running.

Here in this post, I assume you have some basic knowledge on Docker, Docker Images/Containers. And for some of the commands, I might not be explaining what each arguments of the command does, hoping you will do --help on those.

So let’s start.

So on my machine, I have Docker for Windows installed, and there under settings, I have my local C:\ drive shared with Containers.
image
Shared Drives
Now let’s create a folder (I am creating on my Desktop, make sure the drive you are creating the folder in, is shared like above) and I am naming it as a DockerWebApp.

Open up a PowerShell window and change the directory to DockerWebApp folder.
PS C:\Users\Jaliya\Desktop\DockerWebApp> dotnet new mvc
PS C:\Users\Jaliya\Desktop\DockerWebApp> dotnet restore
PS C:\Users\Jaliya\Desktop\DockerWebApp> code .
Now the project will get opened in Visual Studio Code. I have Docker extension for VS Code installed. If you haven’t installed, I suggest you do so, so we can create Docker related files pretty easily. So using the extension, I am creating a Dockerfile as follows.
Dockerfile
Docker for VS Code - Adding Dockerfile
So my Dockerfile looks like this.
FROM microsoft/aspnetcore:1.0.1
LABEL Name=dockerwebapp Version=0.0.1
ARG source=.
WORKDIR /app
EXPOSE 30000
COPY $source .
ENTRYPOINT dotnet dockerwebapp.dll
For now, I am not going to do any changes here, but I am going to delete the other Docker files which got created inside the project which are docker-compose.debug.yml and docker-compose.yml to make things not confusing.

Now let’s publish our application.
PS C:\Users\Jaliya\Desktop\DockerWebApp> dotnet publish -c Release
And since I haven’t specify any specific output path, application will get published to bin\Release\netcoreapp1.1\publish folder.
image
Publish folder
Now let’s move to back to our Dockerfile and do following changes.
FROM microsoft/aspnetcore:1.0.1
LABEL Name=dockerwebapp Version=0.0.1
ARG source
WORKDIR /app
EXPOSE 30000
COPY ${source:-bin/Release/netcoreapp1.1/publish} .
ENTRYPOINT dotnet DockerWebApp.dll
Here first what I have done is, I don’t want to copy the whole project folder to my Image, I am just copying the publish folder. Then I have renamed the dll name in the ENTRYPOINT as in the file name in the publish folder (well I have spent quite sometime figuring out an issue because of this name mismatch).

Now let’s build the Docker Image, so I can create a Container out of it.

For that I am running the following command.
PS C:\Users\Jaliya\Desktop\DockerWebApp> docker build -t dockerwebapp .
I am seeing the following output.
image
docker build -t dockerwebapp .
All seem to be good, there is a warning at the end, we can basically ignore that for now for the sake of this demo. Now let’s run the following command to confirm whether our image is created.
PS C:\Users\Jaliya\Desktop\DockerWebApp> docker images
SNAGHTML82e020a
docker images
Yes, it is created, now let’s try to run it.
PS C:\Users\Jaliya\Desktop\DockerWebApp> docker run dockerwebapp
Now I am getting an error “The specified framework 'Microsoft.NETCore.App', version '1.1.2' was not found.”.
image
docker run dockerwebapp
Of course, I have been using an older aspnetcore image, I am changing the Dockerfile as follows.
FROM microsoft/aspnetcore:1.1.2
LABEL Name=dockerwebapp Version=0.0.1
ARG source
WORKDIR /app
EXPOSE 30000
COPY ${source:-bin/Release/netcoreapp1.1/publish} .
ENTRYPOINT dotnet DockerWebApp.dll
Here is the link where you can find the list ASP.NET Core Docker image information.
https://hub.docker.com/r/microsoft/aspnetcore/

Now let’s run a docker build again.
PS C:\Users\Jaliya\Desktop\DockerWebApp> docker build -t dockerwebapp .
image
docker build -t dockerwebapp .
Now let’s run the image again.
image
docker run dockerwebapp
Yes, it seem to be working. Let’s run the following command in a new PowerShell Window to see the status of all the running Containers.
PS C:\Users\Jaliya> docker ps
Here note that I am running the command from another directory. You can run docker ps from sitting inside any directory.
image
docker ps -a
Now from let’s try to access to site http://localhost:30000 from a browser.
image
Site can't be reached
That’s because I haven’t mapped Container ports and host machines ports. I can easily to fix it by running docker run specifying port mappings.
PS C:\Users\Jaliya\Desktop\DockerWebApp> docker run -p 30000:80 dockerwebapp
image
docker run -p 30000:80 dockerwebapp
And now if I check for running Containers, I can see the ports are mapped.
image
docker ps
Now let’s browse to http://localhost:30000 back again. And this time, it works!
image
Site is running
In this post, I have used following commands in the background.
# List running containers
docker ps
 
# List all containers
docker ps -a
 
# List all images
docker images
 
# Stop given container
docker stop {container_name}
 
# Delete given container
docker rm {container_name}
 
# Delete given image
docker rmi {image_id}
 
# Delete all containers
docker rm $(docker ps -a -q)
 
# Delete all images
docker rmi $(docker images -q)
Hope you find this post helpful.

Again huge thanks goes out to Alex Thissen (@alexthissen) for all his help.

More reads,
Running and Exploring a Docker Linux Container

Happy Coding.

Regards,
Jaliya

Wednesday, May 17, 2017

Visual C# Technical Guru - April 2017

Another month as a judge in Microsoft TechNet Guru Awards under Visual C# category. The TechNet Guru Awards celebrate the technical articles on Microsoft TechNet.

Post in WikiNinjas Official Blog,
https://blogs.technet.microsoft.com/wikininjas/2017/05/16/april-2017-technet-guru-winners/
image
Visual C# Technical Guru - April 2017
Happy Coding.

Regards,
Jaliya

Tuesday, May 9, 2017

Windows Subsystem for Linux

With Windows 10 Creators Update one of the features that got released publicly is Windows Subsystem for Linux (WSL). But it was available for Windows 10 Insiders for almost like a year now and was initially announced at Build 2016. WSL basically let’s you run Linux on Windows. If you are thinking about a VM, No, it’s not a Virtual Machine.

Configuring WSL on Windows shouldn’t take more than 10 minutes, by following these steps you can configure WSL pretty easily. Once you have configured WSL, you should be able use Bash on Ubuntu, just by opening up the Command Prompt/PowerShell and running bash command.
image
WSL
Or you can Search for Bash in Windows, and there should be a desktop app named Bash on Ubuntu on Windows.
image
Bash On Ubuntu On Windows
Currently under WSL only Ubuntu is supported, may be in the future Microsoft might support different flavors of Linux.

On WSL, one of the things that fascinates me more is the File System that is already mounted for you.
image
File System
And through the bash I can just run mkdir and the folder will be appearing inside Windows Explorer the same time.

And most importantly I can run .NET Core Apps on WSL. I have installed .NET Core on my WSL, (again it’s pretty easy, just follow the relevant steps described here) and created an ASP.NET Core HelloWorld application.
image
.NET Core on WSL
And I can just browse the site from a Web Browser in my Windows OS. Isn’t that just great?

Happy Coding.

Regards,
Jaliya