dotnet / orleans

Cloud Native application framework for .NET
https://docs.microsoft.com/dotnet/orleans
MIT License
9.89k stars 2.01k forks source link

[Question] How to connect Orleans Client to Orleans Server in Docker? #8985

Open NikHusachenko opened 3 weeks ago

NikHusachenko commented 3 weeks ago

I try to deploy Silo client and silo server on Docker via docker-compose, but I get error that silo client cannot connect to other container on port 30000. I set upped containers for talking, and I can send simple http request from first project to second and get response. But I can't run project using Orleans. This is code for client:

var builder = WebApplication.CreateBuilder(args);
builder.Host
    .UseOrleansClient(client =>
    {
        client
            .UseLocalhostClustering(30000)
            .Configure<ClusterOptions>(options =>
            {
                options.ClusterId = "<Dev>";
                options.ServiceId = "<Quiz>";
            })
            .Configure<EndpointOptions>(options =>
            {
                options.AdvertisedIPAddress = IPAddress.IPv6Loopback;
                options.GatewayPort = 30_000;
                options.SiloPort = 11_111;
            });
    })
    .ConfigureLogging(logging => logging.AddConsole());

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

Server code:

var builder = WebApplication.CreateBuilder(args);
builder.Host
    .UseOrleans(siloBuilder =>
    {
        siloBuilder
            .UseLocalhostClustering(30000)
            .AddMemoryGrainStorage("<DevStore>")
            .Configure<ClusterOptions>(options =>
            {
                options.ClusterId = "<Dev>";
                options.ServiceId = "<Quiz>";
            })
            .Configure<EndpointOptions>(options => options.AdvertisedIPAddress = IPAddress.Loopback)
            .Configure<EndpointOptions>(options =>
            {
                options.SiloListeningEndpoint = new IPEndPoint(IPAddress.Loopback, 11111);
                options.GatewayListeningEndpoint = new IPEndPoint(IPAddress.Loopback, 30000);
                options.AdvertisedIPAddress = IPAddress.Loopback;
                options.SiloPort = 11_111;
                options.GatewayPort = 30_000;
            });
    })
    .ConfigureLogging(logging => logging.AddConsole());

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

In the future I have to use UseRedisClustering instead a UseLocalhostClustering. This project successfully run in local PC, but in Docker I get exception ''Connection attempt to endpoint S127.0.0.1:30000:0 failed". This is Dockerfile.silo for server project:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base

WORKDIR /app
EXPOSE 5034
EXPOSE 11111
EXPOSE 30000

# ...

ENTRYPOINT ["dotnet", "DockerSilo.Orleans.dll", "--urls", "http://*:5034" ]

And Dockerfile for client project:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base

WORKDIR /app
EXPOSE 5131

# ...

ENTRYPOINT ["dotnet", "DockerSilo.Api.dll", "--urls", "http://*:5131"]

And docker-compose:

services:
  redis:
    image: redis
    ports:
      - 6379:6379

  api:
    build: 
      context: .
      dockerfile: Dockerfile.web
    ports:
      - 5131:5131
    networks:
      - siloNet

  silo:
    build: 
      context: .
      dockerfile: Dockerfile.silo
    ports:
      - 5034:5034
      - 11111:11111
      - 30000:30000
    networks:
      - siloNet

networks:
  siloNet:
    driver: bridge

As you are seen, all parts configured well, but I don't know why this doesn't work. Please, help me resolve this problem, because I did 250 container builds tries for last two days and can't solve this alone

MickaelThumerel commented 3 weeks ago

UseLocalhostClustering Is made to connect on same computer one silo and one client for dev purpose. Orleans is not designed to pass in direct connection though part (client, silo, ...) except in specific local condition (For dev).

With the docker compose you create a virtual network where every container have a virtual IP in it like theire was on separate computer.

You can: 1) Orlean Way: Use a db image and the nuget package associate to provide a meeting point

2) You can change to gateway to redirect docker localhost to the computer one instead on the docker one. It will by pass the docker virtual network for localhost connection.

Attention: Solution 2 will only work with One silo.

Orleans is designed to use a DB a meeting point for cluster nodes (Silo) and/or clients. Through docker it's easy to have one. PS: Sometime the client close because it can connect to any silo. I advise you to delay the client start to prevent it

cameliaonu commented 1 week ago

@MickaelThumerel

The host.docker.internal should be mentioned in the Orleans-Server? I am using UseDevelopmentClustering for the server? Should I mention host.docker.internal for the PrimarySiloEndpoint, insteand of IPAddress.Loopback or IPAddress.Any?

This host.docker.internal:host-gateway should be mentioned in the docker-compose, for the server container?

MickaelThumerel commented 1 week ago

@cameliaonu => host.docker.internal for the PrimarySiloEndpoint, insteand of IPAddress.Loopback or IPAddress.Any : YES

It must be configured in both client and silo.

In the docker compose you must write the redirection as extra host. cf Docker Compose spec

for the AdvertisedIPAddress, i'm not sure of what is for. sorry