.NET Core Docker Image for SPA Applications

Viewed 15251

What is the correct Docker image to use when creating a new ASP.NET Core MVC app, specifically with the React/Redux (or other Node.js required) template? If not a specific image, what commands or process should be followed in the Dockerfile for a Node.js app backed by ASP.NET Core MVC?

I don't require the SDK version of the framework for anything other than running the backing MVC site.

dotnet new reactredux

The runtime image does not have Node.js installed, and will error when trying to run the container.

Dockerfile:

FROM microsoft/aspnetcore:latest

ARG source=./bin/Debug/netcoreapp2.0/publish/
WORKDIR /app
COPY $source .

EXPOSE 80
ENTRYPOINT ["dotnet", "Project.dll"]

Error:

Unhandled Exception: System.AggregateException: One or more errors occurred. (Failed to start Node process. To resolve this:.

[1] Ensure that Node.js is installed and can be found in one of the PATH directories.
    Current PATH enviroment variable is: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    Make sure the Node executable is in one of those directories, or update your PATH.

The project I am working with is being upgraded from ASP.NET MVC for .NET Standard 1.1 (standalone), to a new .NET Standard 2.0 React/Redux project.

6 Answers

Based on @Daniels answer above, running Visual Studio 2017 v15.4 and ASP.NET Core 2.0 on Docker, here are the changes you need to make to allow correct Production and Development behavior for SPA applications (in my case I'm using Angular):

  • Add a new Dockerfile to your project which is a copy of the original. Lets call it Dockerfile.Development. Modify as follows:

    FROM microsoft/aspnetcore:2.0
    ARG source
    
    # BEGIN MODIFICATION - Node is needed for development (but not production)
    RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -
    RUN apt-get install --assume-yes nodejs
    # END MODIFICATION
    
    WORKDIR /app
    EXPOSE 80
    COPY ${source:-obj/Docker/publish} .
    ENTRYPOINT ["dotnet", "MyService.dll"]
    
  • Modify the docker-compose.override.yml file in your solution to use this new dockerfile in development. It'll look something like this:

    version: '3'
    
    services:
      myservice:
        environment:
          - ASPNETCORE_ENVIRONMENT=Development
        ports:
          - "80"
        build:
          dockerfile: Dockerfile.Development
    
  • Modify the webpack.config.js file in your project to enable watching for changes, as follows:

    const clientBundleConfig = merge(sharedConfig, {
      entry: { 'main-client': './ClientApp/boot.browser.ts' },
      output: { path: path.join(__dirname, clientBundleOutputDir) },
      // BEGIN MODIFICATION
      watch: isDevBuild,
      watchOptions: {
        poll: isDevBuild ? 1000 : false
      },
      // END MODIFICATION
      plugins: [
        new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require('./wwwroot/dist/vendor-manifest.json')
        })
      ].concat(isDevBuild ? [
    

I got the Angular example template to work simply by installing nodejs into the base:

FROM microsoft/aspnetcore:2.0 AS base
RUN apt-get update && \
    apt-get install -y wget && \
    apt-get install -y gnupg2 && \
    wget -qO- https://deb.nodesource.com/setup_6.x | bash - && \
    apt-get install -y build-essential nodejs
WORKDIR /app
EXPOSE 80
... rest of Dockerfile ...

Everything else (Webpack Hot swap) didn't throw an error.

Even if you're running ASP.NET Core 3.0 the base images from Microsoft still does not contain NodeJS. You must install NodeJS by yourself. Luckily it's not that hard.

Here's how I solved it recently. Please note the Dockerfile is more like pseudo-code than fully functional, I stripped away most noise. It's installing version 10 of NodeJS, you can of course change that. Here are different node distributions you can install.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build

# Install NodeJS 10
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
RUN apt-get install -y nodejs

RUN npm install
RUN npm run test-docker
RUN npm run build

RUN dotnet restore...

RUN dotnet test...

FROM build AS publish
RUN dotnet publish "Collector.Forms.Autogiro.Web.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Your.Web.dll"]

Here an easy way to containerize SPA applications:

First, we have to comment this two lines in csproj file in your application because it force us to install NodeJS in a docker container.

<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />

Next, inside container, you only need ASP.NET Core runtime for running your application. However a Node Docker image is used for compile React client application. So you need a Dockerfile like this:

FROM node as build-node
WORKDIR /ClientApp
# ClientApp folder contains all your react code
COPY MyApp/ClientApp/package.json .
COPY MyApp/ClientApp/package-lock.json .
RUN npm install
COPY MyApp/ClientApp/ . 
# This command will generate build folder
RUN npm run build

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app
ENV ASPNETCORE_ENVIRONMENT=Production
COPY *.sln .

# In next step you'll get an error if you didn't comment two lines mentioned above in csproj file
COPY MyApp/MyApp.csproj ./MyApp 
RUN dotnet restore
COPY MyApp/. ./MyApp
WORKDIR /app/MyApp
RUN dotnet publish -c Release -o out

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS runtime
WORKDIR /app

# Here we get compile result from .net core application
COPY --from=build /app/MyApp/out ./

# Here we  get compile result for React app
COPY --from=build-node /ClientApp/build ./ClientApp/build

# Application port
EXPOSE 5000
ENTRYPOINT ["dotnet", "MyApp.dll"]
Related