Running ASP.NET 5 Beta 4 in Docker with DNX runtime #aspnet5 #docker

Written on April 27, 2015

Update [2015-05-02]

As Microsoft has updated it's Dockerfile to support DNX (beta 4 as of this Update), the introduction of this post has become obsolete and you can jump directly over here (in this post).

</end of update> [2015-05-02]

Microsoft recently changed the naming for the ASP.NET 5 runtime from "K" to "DNX". With that, the following K utilities have been renamed:

  • kpm -> dnu
  • kvm -> dnvm
  • k -> dnx

When you're trying to run DNX with the current ASP.NET 5 Docker image being provided by Microsoft, you'll fail.

Based on the Dockerfile Microsoft provides here, I created a local Docker image to be able to run ASP.NET 5 Beta 4 with the new DNX runtime.

The Dockerfile for the base ASP.NET 5 image goes here:

Update [2015-05-01]

You don't have to do the following step, there's also a working Microsoft Dockerfile, just jump to here (in this post), to read the instructions how to use it.

FROM mono:3.12

# Get build dependencies, download/build/install mono 4.1.0
RUN apt-get update -qq \
    && apt-get install -qqy git autoconf libtool automake build-essential mono-devel gettext unzip \
    && git clone https://github.com/mono/mono.git \
    && cd mono \
    && git reset --hard 53dc56ee39a8e3b013231957aca4671b202c6410 \
    && ./autogen.sh --prefix="/usr/local" \
    && make \
    && make install \
    && cd .. \
    && rm mono -r

# Install aspnet 1.0.0-beta4
ENV DNX_FEED https://www.myget.org/F/aspnetmaster/api/v2
ENV DNX_USER_HOME /opt/dnx

RUN curl -sSL https://raw.githubusercontent.com/aspnet/Home/7d6f78ed7a59594ce7cdb54a026f09cb0cbecb2a/dnvminstall.sh | DNX_BRANCH=master sh
RUN bash -c "source $DNX_USER_HOME/dnvm/dnvm.sh \
    && dnvm install 1.0.0-beta4 -a default \
    && dnvm alias default | xargs -i ln -s $DNX_USER_HOME/runtimes/{} $DNX_USER_HOME/runtimes/default"

# Install libuv for Kestrel from source code (binary is not in wheezy and one in jessie is still too old)
RUN LIBUV_VERSION=1.4.2 \
    && curl -sSL https://github.com/libuv/libuv/archive/v${LIBUV_VERSION}.tar.gz | tar zxfv - -C /usr/local/src \
    && cd /usr/local/src/libuv-$LIBUV_VERSION \
    && sh autogen.sh && ./configure && make && make install \
    && rm -rf /usr/local/src/libuv-$LIBUV_VERSION \
    && ldconfig

# Update NuGet feeds

RUN mkdir -p ~/.config/NuGet/
RUN curl -o ~/.config/NuGet/NuGet.Config -sSL https://gist.githubusercontent.com/AlexZeitler/a3412a4d4eeee60f8ce8/raw/45b0b5312845099cdf5da560829e75949d44d65f/NuGet.config

ENV PATH $PATH:$DNX_USER_HOME/runtimes/default/bin

Now lets build the base image:

sudo docker build -t pdmlab/aspnet:1.0.0 .

Based on that, lets create a Dockerfile for our ASP.NET 5 Beta 4 DNX web application:

FROM pdmlab/aspnet:1.0.0
ADD . /app
WORKDIR /app
RUN ["dnu", "restore"]

EXPOSE 5004
ENTRYPOINT ["dnx", "./src/HelloMvc6", "kestrel"]

Update [2015-05-01]

You can also use this Dockerfile using the Microsoft Beta 4 base Image:

FROM microsoft/aspnet:vs-1.0.0-beta4
ADD . /app
WORKDIR /app
RUN ["dnu", "restore"]

EXPOSE 5004
ENTRYPOINT ["dnx", "./src/HelloMvc6", "kestrel"]

</end of update> [2015-05-01]

Update [2015-05-02]

You can use this Dockerfile using the Microsoft DNX Beta 4 base Image:

FROM microsoft/aspnet:1.0.0-beta4
ADD . /app
WORKDIR /app
RUN ["dnu", "restore"]

EXPOSE 5004
ENTRYPOINT ["dnx", "./src/HelloMvc6", "kestrel"]

</end of update> [2015-05-02]

After that, we need to build or application image:

sudo docker build -t aspnet5beta4dnx

With that done, we can run our container:

sudo docker run -t -d -p 80:5004 aspnet5beta4dnx

If erverything went well, you should be able to browse http://localhost/api/values on your host.

The source for the HelloMvc6 application comes here:

project.json:

{
  "webroot": "wwwroot",
  "version": "1.0.0-*",

  "dependencies": {
    "Kestrel": "1.0.0-beta4",
    "Microsoft.AspNet.Mvc": "6.0.0-beta4",
    "Microsoft.AspNet.Server.IIS": "1.0.0-beta4",
    "Microsoft.AspNet.Server.WebListener": "1.0.0-beta4",
    "Microsoft.AspNet.StaticFiles": "1.0.0-beta4"
  },

  "commands": {
    "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000",
    "kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5004"
  },

  "frameworks": {
    "dnx451": { },
    "dnxcore50": { }
  },

  "exclude": [
    "wwwroot",
    "node_modules",
    "bower_components"
  ],
  "publishExclude": [
    "node_modules",
    "bower_components",
    "**.xproj",
    "**.user",
    "**.vspscc"
  ]
}

Startup.cs:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.DependencyInjection;

namespace HelloMvc6
{
    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
        }

        // This method gets called by a runtime.
        // Use this method to add services to the container
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            // Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers.
            // You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json.
            // services.AddWebApiConventions();
        }

        // Configure is called after ConfigureServices is called.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            // Configure the HTTP request pipeline.
            app.UseStaticFiles();

            // Add MVC to the request pipeline.
            app.UseMvc();
            // Add the following route for porting Web API 2 controllers.
            // routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
        }
    }
}

ValuesController.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;

namespace HelloMvc6.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        // GET: api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}