0
votes

I have a reverse proxy (nginx) in one container and a .net core api in another container. When running docker-compose build and docker-compose up in powershell this works as expected. The api is only reachable through the reverse proxy (at http://localhost:80).

I have set up docker-compose with visual studio and when running in visual studio with the same dockerfiles, docker-compose.yml, docker-compose.override.yml this does not work. I do not get an error and both container start up. But when trying to reach the api through the reverse proxy I get following error in the docker logs of the reverse proxy

2020/04/01 15:49:30 [error] 6#6: *8 connect() failed (111: Connection refused) while 
connecting to upstream, client: 172.20.0.1, server: , request: "GET /api/health HTTP/1.1", 
upstream: "http://172.20.0.2:5000/api/health", host: "localhost"
172.20.0.1 - - [01/Apr/2020:15:49:30 +0000] "GET /api/health HTTP/1.1" 502 559 "-" 
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) 
Chrome/80.0.3987.149 Safari/537.36"

This is my folder structure:

  • ....
  • RestApi (project folder folder)
    • Dockerfile
  • docker-compose.yml
  • docker-compose.override.yml
  • ReverseProxy (folder)
    • Dockerfile
    • nginx.conf
  • ...

These are the files I use:

Dockerfile for .net core api:

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

FROM mcr.microsoft.com/dotnet/core/sdk:2.1-stretch AS build
WORKDIR /src
COPY ["RestApi/RestApi.csproj", "RestApi/"]
COPY ["Services/Services.csproj", "Services/"]
COPY ["DataServices/DataServices.csproj", "DataServices/"]
COPY ["Entities/Entities.csproj", "Entities/"]
RUN dotnet restore "RestApi/RestApi.csproj"
COPY . .
WORKDIR "/src/RestApi"
RUN dotnet build "RestApi.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "RestApi.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

ENV ASPNETCORE_URLS http://+:5000
EXPOSE 5000

ENTRYPOINT ["dotnet", "RestApi.dll"]

Dockerfile for reverse proxy:

FROM nginx
COPY nginx.conf /etc/nginx/nginx.conf

ngingx conf file reverse proxy:

worker_processes 4;

events { worker_connections 1024; }

http {
    sendfile on;

    upstream app_servers {
        server restapi:5000;
    }

    server {
        listen 80;

        location / {
            proxy_pass         http://app_servers;
            proxy_redirect     off;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $server_name;
        }
    }
}

docker-compose.yml:

version: '3.7'
services:
  restapi:
    build:
      context: .
      dockerfile: RestApi/Dockerfile
    container_name: restapi
    image: restapi:latest
    expose:
      - "5000"
  reverseproxy:
    build:
      context: ./ReverseProxy
      dockerfile: Dockerfile
    container_name: reverseproxy
    image: reverseproxy:latest
    ports:
      - "80:80"
    links :
      - restapi

docker-compose.override.yml:

version: '3.7'

services:
  restapi:
    volumes:
      - ${USERPROFILE}/.aws:/root/.aws
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - AWS_REGION=eu-west-3
      - AWS_PROFILE=default

And this is what visual studio makes of the file when running:

services:
  restapi:
    build:
      context: D:\Repositories\dank\dank\api\RestApi
      dockerfile: RestApi/Dockerfile
      labels:
        com.microsoft.created-by: visual-studio
        com.microsoft.visual-studio.project-name: RestApi
      target: base
    container_name: restapi
    entrypoint: tail -f /dev/null
    environment:
      ASPNETCORE_ENVIRONMENT: Development
      AWS_PROFILE: default
      AWS_REGION: eu-west-3
      DOTNET_USE_POLLING_FILE_WATCHER: '1'
      NUGET_FALLBACK_PACKAGES: ''
    expose:
    - '5000'
    image: restapi:dev
    labels:
      com.microsoft.visualstudio.debuggee.arguments: ' --additionalProbingPath /root/.nuget/packages  "bin/Debug/netcoreapp2.1/RestApi.dll"'
      com.microsoft.visualstudio.debuggee.killprogram: /bin/sh -c "if PID=$$(pidof
        dotnet); then kill $$PID; fi"
      com.microsoft.visualstudio.debuggee.program: dotnet
      com.microsoft.visualstudio.debuggee.workingdirectory: /app
    tty: true
    volumes:
    - D:\Repositories\dank\dank\api\RestApi\RestApi:/app:rw
    - C:\Users\Gebruiker\vsdbg\vs2017u5:/remote_debugger:rw
    - C:\Users\Gebruiker\AppData\Roaming\ASP.NET\Https:/root/.aspnet/https:ro
    - C:\Users\Gebruiker\.aws:/root/.aws:rw
    - C:\Users\Gebruiker\AppData\Roaming\Microsoft\UserSecrets:/root/.microsoft/usersecrets:ro
    - C:\Users\Gebruiker\.nuget\packages:/root/.nuget/packages:ro
    - D:\Repositories\dank\dank\api\RestApi:/src:rw
  reverseproxy:
    build:
      context: D:\Repositories\dank\dank\api\RestApi\ReverseProxy
      dockerfile: Dockerfile
    container_name: reverseproxy
    image: reverseproxy:latest
    links:
    - restapi
    ports:
    - published: 80
      target: 80
version: '3.7'
1

1 Answers

0
votes

When reading the official documentation: https://docs.microsoft.com/en-us/visualstudio/containers/container-build?view=vs-2019#debugging

I saw that they place the exposing of their ports at the top of the dockerfile. When doing so, it works in visual studio and port 5000 is correctly exposed by my api container and reachable by the reverse proxy.

This is my current dockerfile with the changes:

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

ENV ASPNETCORE_URLS http://+:5000
EXPOSE 5000

FROM mcr.microsoft.com/dotnet/core/sdk:2.1-stretch AS build
WORKDIR /src
COPY ["RestApi/RestApi.csproj", "RestApi/"]
COPY ["Services/Services.csproj", "Services/"]
COPY ["DataServices/DataServices.csproj", "DataServices/"]
COPY ["Entities/Entities.csproj", "Entities/"]
RUN dotnet restore "RestApi/RestApi.csproj"
COPY . .
WORKDIR "/src/RestApi"
RUN dotnet build "RestApi.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "RestApi.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

ENTRYPOINT ["dotnet", "RestApi.dll"]

The reason that this works is (from the documentation):

When building in Debug configuration, there are several optimizations that Visual Studio does that help with the performance of the build process for containerized projects. The build process for containerized apps is not as straightforward as simply following the steps outlined in the Dockerfile. Building in a container is much slower than building on the local machine. So, when you build in the Debug configuration, Visual Studio actually builds your projects on the local machine, and then shares the output folder to the container using volume mounting. A build with this optimization enabled is called a Fast mode build.

In Fast mode, Visual Studio calls docker build with an argument that tells Docker to build only the base stage. Visual Studio handles the rest of the process without regard to the contents of the Dockerfile. So, when you modify your Dockerfile, such as to customize the container environment or install additional dependencies, you should put your modifications in the first stage. Any custom steps placed in the Dockerfile's build, publish, or final stages will not be executed.