Sunday, December 03, 2017

Docker Tip : Workaround for accessing localhost on Mac for ASP.NET Core Multi-container app

Background

Recently I was working on a demo for building multi-container application using Docker and ASP.Net Core 2.0. The application is the same one I had used for my demo during Microsoft Azure meetup group to demonstrate the scaling features of Docker Swarm using Azure Container Service (AKS). The source code is available on Github. The two main parts of the solution are the MVC core application which acts as front end and there is a ASP.Net Core Web API which provides some static key value pairs.

Problem communicating between MVC App & Web API

I am using Mac Book Pro 2016 model to develop and test this application. The web application and the Api both were running successfully when they are run using the dotnet run command. Within the web application there is a provision to provide the url for the webapi and the search can be made dynamically referring to a valid instance of running web api. Below is the screenshot of API Keyvalue controller result. it is running on port 50114 which is dynamically generated by dotnet cli command.

api without container

Next we see the MVC app working by referencing the webapi

mvc without container

Once my test were successful locally, I moved on to containerize the MVC app and web Api as Docker images. I am not going to list each and every command here. If you wish to know the set of commands used to publish and build the images refer to the mark down file for more detail. Running the two images individually also worked fine using the commands shown below

docker run –d –p 80:80 coremvc

docker run –d p 8080:80 corewebapi

The last step before I publish the images to Docker registry like Dockerhub was to test the web api by invoking a method from within a container image. As seen from the above command, I am mapping the 8080 command on docker host which is my Mac to the web api container port on 80. If I use http://localhost:8080/api/KeyValue, I should get a result similar to what is shown above. Unfortunately this is not what is happening. I get an error saying couldn’t connect to server.

localhost-error

I tried to access the API keyValue controller by directly hitting the browser and bypassing the call through web application and it is giving me the correct response. Why is that the MVC application running inside the container not able to connect to it?

Docker Networking for Mac

The reason for this is to do with the way Docker for Mac handles networking. When we say localhost, the container tries to connect to services within the container image. In the MVC contianer, there is no web api running. The Web api is a separate container. We need a way to route the call through the host and redirect the traffic via host port 8080.

without localhost

It turns out that there is a special way of accessing localhost while running docker for mac. instead of directly referring localhost, we need to use docker.for.mac.localhost followed by the port number. So the complete url in our case will be  http://docker.for.mac.localhost:8080. After making this adjustment we get the expected result.

with localhost

docker-for-mac-localhost

As an alternative, we can also use ip address which is 192.168.65.1. Replacing docker.for.mac.localhost with the this ip gives the same result.

Conclusion

Docker is a wonderful technology to develop and test things quickly. I hope this post was helpful if you are working with multi container applications using ASP.Net Core and Docker. This problem of accessing other containers using localhost happens only while testing locally. When I provided the fully qualified API url after deploying the containers to Docker Swarm on Azure Container Service, I di not face the issue. I will post similar tips and tricks related to Docker and Azure which I am currently exploring.

Until next time Happy Programming.

No comments:

Post a Comment

Migrate DotNet Core Docker image to Alpine based distribution

Background Recently I had been using Docker and related technologies like Docker Swarm to play around with DotNet Core 2.0. I also used Azur...