Search code examples
angulardockerconfiguration-filesasp.net-core-2.1

Hosting Angular application in Kestrel does not work with Docker


I have a angular 6 application that is hosted inside a .NET Core Server.The application works ,i can acess the pages/routes etc.
However when i put this .NETapplication inside docker and run it i get the following error:

GET http://localhost:8400/styles.3bb2a9d4949b7dc120a9.css net::ERR_ABORTED 404 (Not Found)
GET http://localhost:8400/runtime.ec2944dd8b20ec099bf3.js net::ERR_ABORTED 404 (Not Found)

In my docker image i put the Release folder of the .NET App ,and in this folder i add :

-DockerImage
   -Release folder
     - Dockerfile
     - Config `json` file (i am using `Microsoft.Extensions.Configuration`)
     - `dist` folder (angular compiled application)

Dockerfile

FROM microsoft/dotnet:2.1-aspnetcore-runtime
WORKDIR /app
ADD . /app
ENTRYPOINT [ "dotnet","Deploy.dll"]

The . root path in this case is the Release folder that has the items i mentioned in the upper section.

What is intriguing is that the NET Core depends on some files of the dist folder otherwise it would crash.And it doesn't ,it works just fine.

Startup.cs

  public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
                if (env.IsDevelopment()) {
                    app.UseDeveloperExceptionPage();
                } else
                    app.UseHsts();
                Config config = this.Configuration.GetSection("Config").Get<Config>();
                Config.Frontend frontend = this.Configuration.GetSection("Config:Frontend").Get<Config.Frontend>();

                string jsroot = Path.Combine(Directory.GetCurrentDirectory(), frontend.PhysicalRoot);
                PhysicalFileProvider provider = new PhysicalFileProvider(jsroot);

                DefaultFilesOptions options = new DefaultFilesOptions() {
                    DefaultFileNames = new List<string> { frontend.DefaultFileName },
                    FileProvider = provider,
                    RequestPath = frontend.RequestPath
                };
                app.UseDefaultFiles(options);

                app.UseStaticFiles();
                app.UseStaticFiles(new StaticFileOptions() {
                    RequestPath = frontend.RequestPath,
                    FileProvider = provider
                });
            }

Index.html (from the dist folder )

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Frontend</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="treeview/styles.3bb2a9d4949b7dc120a9.css"></head>
<body>
  <app-root></app-root>
<script type="text/javascript" src="treeview/runtime.ec2944dd8b20ec099bf3.js"></script>
    <script type="text/javascript" src="treeview/polyfills.c6871e56cb80756a5498.js"></script>
    <script type="text/javascript" src="treeview/main.a4ddb95d782e95e34c4a.js"></script>
</body>
</html>

Config file

{
  "Config": {
    "Frontend": {
      "PhysicalRoot": "./js",
      "RequestPath": "/treeview",
      "DefaultFileName": "index.html"
    },
    "Environment": {
      "ProdEnv": {
        "OwnAddress": {
          "Hostname": "0.0.0.0",
          "Port": 8400
        }
      },
      "DevEnv": {
        "OwnAddress": {
          "Hostname": "0.0.0.0",
          "Port": 8401
        }
      }
    }
  }
}

P.S The Config type in the .NET Core App is just a POCO for the Config section of the config file.

The container is started with a bash script that starts a docker-compose

Docker compoe

version: '3.3'
services:

    front:
      image: ft
      container_name: front0
      build: ./front/publish
      networks:
        - redis-net
      ports:
        - 8400:8400

Script.sh

    dotnet build -c Release ../${hostServerSrc} >>out.txt  //building the release for the `.NET Server that hosts the angular app`
    dotnet publish -c Release ../${hostServerSrc} --output $(pwd)/${hostServerDest} >>out.txt  //publshing it to the folder that will be injected in the image
    cp  ./Configs/hostConfig.json ./front/publish  //copying the config file for the `.NET App`
    cp  -r ../${ngSrc}  ./front/publish/js //copying the angular compiled app

    docker-compose up --build  -d >>out.txt

P.S 2 It seems it can not find any file in the js folder.The Request URL is: http://localhost:8400/runtime.js.

In the docker container i have all the files inside the js folder. It might be because being in docker there is no more localhost ?


Solution

  • Everything looks fine except one point for me.

    You want your container to join redis-net network:

      networks:
        - redis-net
    

    but I dont see this network defined in your docker-compose file.

    Try one of the following:

    Add network definition to docker-compose:

    version: '3.3'
    services:
        front:
          image: ft
          container_name: front0
          build: ./front/publish
          networks:
            - redis-net
          ports:
            - 8400:8400
    networks:
      redis-net:
    

    Or remove this line - docker-compose will create a default shiny bridged network for you, which works fine. If you dont plan to perform manual network manipulation, this is a great choice.

    version: '3.3'
    services:
        front:
          image: ft
          container_name: front0
          build: ./front/publish
          ports:
            - 8400:8400