Tuesday, July 5, 2016

Asp.Net Core APIs with Docker

Thought I do a quick blog post about developing and deploying a ASP.NET Core Web APIs using Docker, mainly because there was a bit of a dearth of info out there and there are a couple of gotcha's to navigate around that I'd thought I'd share. In this blog I'll take you as far as creating and running the container on your local docker instance.

.NET Core, as Microsoft is currently calling it (vNext, .NET 5 anyone?) is inching its way to release, and at time of writing is at RC2, and seeming a bit more settled. Good time to checkout its ability to live standalone in a Docker eco-system!

It is surprisingly easy, as the first 5 minutes of this recent dotnetConf presentation shows, to build and deploy .NET Core console apps, but when you work with web apps, such as an API, there are a few extra bits you need to take into consideration.

So here we go:
  1. Develop your ASP.NET Core web API, taking note of the version of framework you are using... currently it's 1.0.0-rc2-final
  2. Add a dockerfile to your app looking something like this:

    FROM microsoft/dotnet:1.0.0-rc2-core
    WORKDIR /app
    COPY /app /app
    EXPOSE 5000
    ENTRYPOINT dotnet YourAppProjectName.dll
    
    

  3. If you are unfamiliar with Docker then the dockerfile provides configuration for creating your container. From top to bottom, firstly we ask Docker for another image (our lightweight dotnet core framework) to base this new image on, we say where the image will go, copy our compiled app to that directory (more in step 4), expose any ports (dotnet webapps run on a Kestrel webserver on port 5000 by default) and, finally the command to start the service (your notice you have to reference the dll here, dotnet run isn't enough).
    Gotcha#1: If you are developing on Windows save your dockerfile this file using something like Sublime where you can save with UTF-8 encoding - Docker is Linux and doesn't like nasty Windows line endings and such! And don't forget everything is case sensitive!

  4. So we are all ready to compile our app..... but wait!!!!!
    Gotcha#2: Unless you have a unusual configuration you'll most likely be using the default setup whereby our standalone ASP.NET Core app runs (when you execute
    dotnet run) on the Kestrel web server which makes the website available on http://localhost:5000/ for you then to map that, usually via a web server, to a WAN should you need to. But Docker has simplified DNS so localhost would require more configuration to resolve, instead it's easier to configure the website to run on a quad-zero address (http://0.0.0.0/)
    To alter the default localhost address you need to changes the Program class's Main method in your Web API project as below:
                var host = new WebHostBuilder()
                    .UseKestrel()
                    .UseContentRoot(Directory.GetCurrentDirectory())
                    .UseIISIntegration()
                    .UseStartup<Startup>()
                    .UseUrls("http://0.0.0.0:5000")
                    .Build();
    
                host.Run();


  5. Now we can publish our app. Using a command line tool navigate to your app's directory, and publish our app. As we foretold in the dockerfile we're gonna stick it in a folder .\app
    c:\MyFolder\MyApp> dotnet publish -o .\app

  6. Now we have our app compiled and configuration ready we can build an image using docker.

    Before building that image you need to have the required resources for your app available in your Docker instance, by that I mean the image that it requires as a starting point, remember from our
    dockerfile configuration file?: -

    FROM microsoft/dotnet:1.0.0-rc2-core

    So, open your docker terminal and go get it:

    $ docker pull microsoft/dotnet:1.0.0-rc2-core

    This will go to dockers marketplace and download the image.

    Now we can create our image, so change directory to our app's location in the docker terminal and create the image (also think of an image name!):

    $ docker build -t yourdockerimagename .

    You'll see the Docker daemon read the
    dockerfile and execute its commands.
  7. Now we've created the image, but we haven't run it yet. If you do a docker ps you'll notice your image is not listed:

    CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS
                             PORTS               NAMES
    
    

    So let's run your new image locally by punching the following into Dockers terminal:

    $ docker run -t -d -p 5000:5000 yourdockerimagename

    This command tells Docker to run the
    yourdockerimagename image in detached (-d) mode and map port 5000 internally to the docker's machines 5000 port.

    So now you should be able to see your docker container up and running if you do a
    docker ps:

    CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS
                             PORTS               NAMES
    b38752b6505c        yourdockerimagename   "bin/sh -c 'dotnet Y"         52 seconds ago             Up 6 seconds
                             0.0.0.0:5000->5000/tcp         small_wilson
    
    

    This will show the image is now a running container with an associated id (in this case
    b38752b6505c).
  8. DONE

    If you've got this far you should be able to call your Containerised DotNet Core API via the docker machines IP address on port 5000 (something like http://192.168.99.100:5000/your-api-route-here) and see some lovely RESTful responses!
So, what have we learnt? Well we've utilised the power of .NET to create a DotNet Core Web API and deployed that into unix environment. Containerising our App now means we can port it to any Docker environment and know it will always run.

Now run free my little Dockers!

5 comments:

  1. Best lifetime memorable gift for your loving one. A mosaic is an image made up of several images in a single photo. It turns out that one picture is made up of several smaller pictures. Our designer team designs your photos beautifully and colorfully. Hundreds of memorable photos are displayed in one photo.

    Click here

    Click here

    Click here


    ReplyDelete
  2. Liman Restaurant

    The Liman Restaurant means port in the Turkish language, however the restaurant opens its doors to all aspects of the Mediterranean kitchen. The kitchen will be mostly focused on Mediterranean food.

    ReplyDelete