7

I have two .net core microservices(PatientService and AppointmentService) with normal web APIs and gRPC service. I am using gRPC for inter service communication instead of using HTTP calls.

Appointment service depends upon patient service for data, meaning when I hit a endpoint on appointment service to get appointments I need patient information from patient service, so I am using gRPC for this call.

Now my application is working just fine and I am able to communicate between two, without doing any extra stuff using kestrel on my local environment. But when I run the same application in Docker the application does not run, I am not able to hit neither HTTP1 nor HTTp2 ports. I am running Linux containers.

My question is how to run HTTP1 and HTTP2 in a .net core application? How to do inter service communication in .net microservices using grpc?

How to run .net core web API + gRPC service in docker using Linux containers(Ubuntu 18.04)? How to run gRPC without TLS?

Please help I have tried everything and I am stuck.I have this important build to release.

Docker File.

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /etc/ssl/openssl.cnf
RUN sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /usr/lib/ssl/openssl.cnf
RUN sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1/g' /usr/lib/ssl/openssl.cnf
WORKDIR /app
EXPOSE 80
EXPOSE 6002
EXPOSE 443
EXPOSE 5001
EXPOSE 6001
#our sql server was use this port for connect
EXPOSE 7007

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["API/API.csproj", "API/"]
COPY ["Infrastructure/Infrastructure.csproj", "Infrastructure/"]
COPY ["Application/Application.csproj", "Application/"]
COPY ["Domain/Domain.csproj", "Domain/"]
COPY ["Common/Common.csproj", "Common/"]
RUN dotnet restore "API/API.csproj"
COPY . .
WORKDIR "/src/API"
RUN dotnet build "API.csproj" -c Release -o /app/build

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

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

Sundar Singh
  • 654
  • 5
  • 15
  • This needs a bit more information - how are you trying to access it? Are all services running as containers? How did you start the container(s)? – Leonardo Dagnino Jun 16 '20 at 14:31
  • yep, both services are running as containers. Below are the commands I have tried: `docker run -d -p 6001:80 -p 6000:6000 --name patientservice-for-scrips scripspatientserviceqa docker run -d -p 6004:80 --name appointmentservice-for-scrips appointmentschedulingqa docker run -d -p 25672:25672 -p 6672:6672 --name appointmentScheduling-for-scrips appointmentscheduling docker run -it -p 6002:5000 -p 5001:5001 -e ASPNETCORE_URLS="https://+443;http://+80" -e ASPNETCORE_HTTPS_PORT=5001 --restart=always -d --name patientservice-for-scrips scripspatientserviceqa` – Devender Singh Jun 17 '20 at 08:32
  • Actually I want to run the HTTP2 without TLS or SSL and Please do not pay attention to the ports I was using the same ports are exposed on the docker file – Devender Singh Jun 17 '20 at 08:42
  • How are they trying to communicate? Is there any configuration file where you configure their hostnames? By the way, you can edit your question to add information with better formatting. – Leonardo Dagnino Jun 17 '20 at 14:11
  • I think you should use `docker-compose` - then you can specify the service names, which will be resolvable between the containers as `http://configuredname` – Leonardo Dagnino Jun 17 '20 at 14:13

1 Answers1

10

I found a solution which works for me, it took me just 3 weeks to figure it out.

There are 3 main concerns:

  1. Docker exposed ports
  2. Kestrel configuration
  3. Client channel configuration

Kestrel should be set with following parameters in appsetting.json or in the program cs which one you prefer:

  "Kestrel": {
    "EndPoints": {
      "Grpc": {
        "Url": "http://*:8080",
        "Protocols": "Http2"
      },
      "webApi": {
        "Protocols": "Http1",
        "Url": "http://*:80"
      }
    }
  }

OR

ConfigureKestrel(options =>
                {
                    options.ListenAnyIP(80, listenOptions => listenOptions.Protocols = HttpProtocols.Http1); //webapi
                    options.ListenAnyIP(8080, listenOptions => listenOptions.Protocols = HttpProtocols.Http2); //grpc
                })

After this setting, you start the docker with following commands (ports and ip may differ as you wish, make sure there is no other thing listening on those ports ips):

docker run -p 127.0.0.40:8080:80 -p 127.0.0.40:8081:8080 --env ASPNETCORE_ENVIRONMENT=Development -it my_project -e ASPNETCORE_ENVIRONMENT=Development -e ASPNETCORE_URLS=http://+

After this u have to configure your channel (do not use the ".AddGrpcClient" extension from Grpc.AspNetCore):

services.AddSingleton(x =>
                        {
                            AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
                            return GrpcChannel.ForAddress("127.0.0.40:8081",
                                //TODO:GRPC Root SSL Creds
                                channelOptions: new GrpcChannelOptions()
                                {
                                    Credentials = ChannelCredentials.Insecure
                                });
                        });

After this you create your clients as you wish with the Channel you created and it should be fine whatever you want to do. No other method worked for me.

UPDATE: I found a way to make it work with "AddGrpcClient" from Grpc.AspNetCore.

services.AddGrpcClient<ControllerGuide.GuideClient>(
(x, opt) =>
{
    AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
    opt.Address = new Uri("UriGRPC:5001");
    opt.ChannelOptionsActions.Add(act =>
    {
        act.Credentials = ChannelCredentials.Insecure;
    });
});
Alex Cr
  • 431
  • 5
  • 8
  • Hey Alex! Thanks for sharing this. Can you please post your ubuntu configuration as in Apache or Nginx that is forwarding requests to the Docker containers? Thanks! – Vulovic Vukasin Aug 13 '21 at 21:28
  • Sorry, i cant. The server configurations are made trough the devops team. – Alex Cr Sep 01 '21 at 09:06
  • No problem, ill link the documentation on how I did it through nginx and docker. Thank you for the insights tough! – Vulovic Vukasin Sep 01 '21 at 13:48