przegląd sieciowania wewnętrznej pętli .NET.NET Aspire
Jedną z zalet programowania przy użyciu .NET.NET Aspire jest możliwość lokalnego tworzenia, testowania i debugowania aplikacji natywnych dla chmury. Sieć w pętli wewnętrznej jest kluczowym aspektem .NET.NET Aspire, który umożliwia aplikacjom komunikowanie się ze sobą w środowisku deweloperskim. W tym artykule dowiesz się, jak .NET.NET Aspire obsługuje różne scenariusze sieciowe z serwerami proxy, punktami końcowymi, konfiguracjami punktów końcowych i profilami uruchamiania.
Sieciowanie w wewnętrznej pętli
Pętla wewnętrzna to proces tworzenia i testowania aplikacji lokalnie przed wdrożeniem jej w środowisku docelowym. .NET .NET Aspire udostępnia kilka narzędzi i funkcji, które upraszczają i rozszerzają środowisko sieciowe w pętli wewnętrznej, takie jak:
- Profile uruchamiania: Profile uruchamiania to pliki konfiguracji określające sposób uruchamiania aplikacji lokalnie. Profile uruchamiania (takie jak plik launchSettings.json) umożliwiają definiowanie punktów końcowych, zmiennych środowiskowych i ustawień uruchamiania aplikacji.
- konfiguracja Kestrel: konfiguracja Kestrel umożliwia określenie punktów końcowych, na których nasłuchuje serwer internetowy Kestrel. Punkty końcowe Kestrel można skonfigurować w ustawieniach aplikacji, a .NET.NET Aspire automatycznie używa tych ustawień do tworzenia punktów końcowych.
- Konfiguracje punktów końcowych/Punkty końcowe: Punkty końcowe to połączenia między Twoją aplikacją a usługami, od których zależy, takimi jak bazy danych, kolejki komunikatów lub interfejsy API. Punkty końcowe zawierają informacje, takie jak nazwa usługi, port hosta, schemat i zmienna środowiskowa. Punkty końcowe można dodawać do aplikacji niejawnie (za pośrednictwem profilów uruchamiania) lub jawnie, wywołując WithEndpoint.
- Proxies: .NET.NET Aspire automatycznie uruchamia serwer proxy dla każdego powiązania usługi dodawanego do aplikacji i przypisuje port, aby serwer proxy mógł nasłuchiwać. Następnie serwer proxy przekazuje żądania do portu, na którym nasłuchuje aplikacja, co może różnić się od portu serwera proxy. Dzięki temu można uniknąć konfliktów portów i uzyskać dostęp do aplikacji i usług przy użyciu spójnych i przewidywalnych adresów URL.
Jak działają punkty końcowe
Powiązanie usługi w .NET.NET Aspire obejmuje dwie integracje: usługę reprezentującą zasób zewnętrzny wymagany przez aplikację (na przykład bazę danych, kolejkę komunikatów lub interfejs API) oraz powiązanie, które ustanawia połączenie między aplikacją a usługą i udostępnia niezbędne informacje.
.NET .NET Aspire obsługuje dwa typy powiązań usługi: niejawne, automatycznie tworzone na podstawie określonych profilów uruchamiania definiujących zachowanie aplikacji w różnych środowiskach, a jawne, utworzone ręcznie przy użyciu WithEndpoint.
Podczas tworzenia połączenia, niezależnie od tego, czy jest jawne, czy ukryte, .NET.NET Aspire uruchamia lekki zwrotny serwer proxy na określonym porcie, odpowiadając za routing i równoważenie obciążenia dla żądań z aplikacji do usługi. Proxy to .NET.NET Aspire szczegół implementacji, który nie wymaga konfiguracji ani zarządzania.
Aby ułatwić wizualizację działania punktów końcowych, rozważ diagram sieci wewnętrznej pętli w szablonach startowych .NET.NET Aspire.
Uruchamianie profilów
Podczas wywoływania AddProjecthost aplikacji wyszukuje Właściwości/launchSettings.json w celu określenia domyślnego zestawu punktów końcowych. Host aplikacji wybiera określony profil uruchamiania przy użyciu następujących reguł:
- Jawny argument
launchProfileName
przekazywany podczas wywoływaniaAddProject
. - Zmienna środowiskowa
DOTNET_LAUNCH_PROFILE
. Aby uzyskać więcej informacji, zobacz sekcję zmienne środowiskowe .NET. - Pierwszy profil uruchamiania zdefiniowany w launchSettings.json.
Rozważmy następujący plik launchSettings.json:
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "https://localhost:7239;http://localhost:5066",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
W pozostałej części tego artykułu wyobraź sobie, że utworzyłeś/-aś IDistributedApplicationBuilder i przypisałeś/-aś ją do zmiennej o nazwie builder
za pomocą interfejsu API CreateBuilder().
var builder = DistributedApplication.CreateBuilder(args);
Aby określić profile uruchamiania http i https, skonfiguruj wartości applicationUrl
dla obu elementów w pliku launchSettings.json. Te adresy URL są używane do tworzenia punktów końcowych dla tego projektu. Jest to odpowiednik:
builder.AddProject<Projects.Networking_Frontend>("frontend")
.WithHttpEndpoint(port: 5066)
.WithHttpsEndpoint(port: 7239);
Ważny
Jeśli nie ma launchSettings.json (lub profilu uruchamiania), domyślnie nie ma powiązań.
Aby uzyskać więcej informacji, zobacz .NET.NET Aspire i uruchom profile.
Skonfigurowane punkty końcowe usługi Kestrel
.NET .NET Aspire obsługuje konfigurację punktu końcowego Kestrel. Rozważmy na przykład plik appsettings.json dla projektu, który definiuje punkt końcowy Kestrel ze schematem HTTPS i portem 5271:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"Kestrel": {
"Endpoints": {
"Https": {
"Url": "https://*:5271"
}
}
}
}
Poprzednia konfiguracja określa punkt końcowy Https
. Właściwość Url
jest ustawiona na https://*:5271
, co oznacza, że punkt końcowy nasłuchuje na wszystkich interfejsach na porcie 5271. Aby uzyskać więcej informacji, zobacz Konfiguruj punkty końcowe dla serwera internetowego Kestrel ASP.NET Core.
Po skonfigurowaniu punktu końcowego Kestrel projekt powinien usunąć każdą konfigurację applicationUrl
z pliku launchSettings.json.
Notatka
Jeśli applicationUrl
znajduje się w pliku launchSettings.json i skonfigurowano punkt końcowy Kestrel, host aplikacji zgłosi wyjątek.
Podczas dodawania zasobu projektu istnieje przeciążenie, które pozwala określić, że punkt końcowy Kestrel powinien być używany zamiast pliku launchSettings.json:
builder.AddProject<Projects.Networking_ApiService>(
name: "apiservice",
configure: static project =>
{
project.ExcludeLaunchProfile = true;
project.ExcludeKestrelEndpoints = false;
})
.WithHttpsEndpoint();
Aby uzyskać więcej informacji, zobacz AddProject.
Porty i serwery proxy
Podczas definiowania powiązania usługi port hosta jest zawsze przydzielany serwerowi proxy, który jest umieszczony przed usługą. Umożliwia to, aby jedna lub wiele replik usługi mogło zachowywać się podobnie. Ponadto wszystkie zależności zasobów korzystające z interfejsu API WithReference korzystają z punktu końcowego serwera proxy ze zmiennej środowiskowej.
Rozważ następujący łańcuch metod, który najpierw wywołuje AddProject, potem WithHttpEndpoint, a następnie WithReplicas:
builder.AddProject<Projects.Networking_Frontend>("frontend")
.WithHttpEndpoint(port: 5066)
.WithReplicas(2);
Powyższy kod powoduje wykonanie następującego diagramu sieciowego:
Powyższy diagram przedstawia następujące elementy:
- Przeglądarka internetowa jako punkt wejścia do aplikacji.
- Port hosta: 5066.
- Serwer proxy front-end znajduje się pomiędzy przeglądarką internetową a replikami usługi front-end, który nasłuchuje na porcie 5066.
- Replika usługi frontendowej
frontend_0
nasłuchuje na losowo przypisanym porcie 65001. - Replika usługi frontendowej
frontend_1
nasłuchuje na losowo wybranym porcie 65002.
Bez odwołania do WithReplicas
, istnieje tylko jedna usługa frontendowa. Serwer proxy nadal nasłuchuje na porcie 5066, ale usługa frontendowa nasłuchuje na losowym porcie.
builder.AddProject<Projects.Networking_Frontend>("frontend")
.WithHttpEndpoint(port: 5066);
Zdefiniowano dwa porty:
- Port hosta: 5066.
- Losowy port serwera proxy, z którymi będzie powiązana podstawowa usługa.
Powyższy diagram przedstawia następujące elementy:
- Przeglądarka internetowa jako punkt wejścia do aplikacji.
- Port hosta: 5066.
- Serwer frontend proxy znajduje się między przeglądarką internetową a usługą frontend i nasłuchuje na porcie 5066.
- Usługa frontend nasłuchuje na porcie 65001.
Podstawowa usługa jest zasilana za pomocą tego portu ASPNETCORE_URLS
dla zasobów projektu. Inne zasoby mają dostęp do tego portu, określając zmienną środowiskową w powiązaniu usługi:
builder.AddNpmApp("frontend", "../NodeFrontend", "watch")
.WithHttpEndpoint(port: 5067, env: "PORT");
Poprzedni kod udostępnia losowy port w zmiennej środowiskowej PORT
. Aplikacja używa tego portu do nasłuchiwania połączeń przychodzących z serwera proxy. Rozważmy następujący diagram:
Powyższy diagram przedstawia następujące elementy:
- Przeglądarka internetowa jako punkt wejścia do aplikacji.
- Port hosta 5067.
- Serwis proxy warstwy frontowej znajduje się pomiędzy przeglądarką internetową a usługą frontend, nasłuchujący na porcie 5067.
- Usługa frontendu nasłuchuje na porcie 65001.
Napiwek
Aby uniknąć przekierowywania punktu końcowego, ustaw właściwość IsProxied
na false
przy wywoływaniu metody rozszerzenia WithEndpoint
. Aby uzyskać więcej informacji, zobacz Rozszerzenia punktu końcowego: dodatkowe zagadnienia.
Pomijanie portu hosta
W przypadku pominięcia portu hosta .NET.NET Aspire generuje losowy port zarówno dla hosta, jak i portu usługi. Jest to przydatne, gdy chcesz uniknąć konfliktów portów i nie zależy ci na hoście lub porcie usługi. Rozważ następujący kod:
builder.AddProject<Projects.Networking_Frontend>("frontend")
.WithHttpEndpoint();
W tym scenariuszu zarówno porty hosta, jak i usługi są losowe, jak pokazano na poniższym diagramie:
Powyższy diagram przedstawia następujące elementy:
- Przeglądarka internetowa jako punkt wejścia do aplikacji.
- Port hosta o losowej wartości: 65000.
- Frontend proxy znajduje się między przeglądarką internetową a usługą frontendową, nasłuchując na porcie 65000.
- Usługa frontendowa jest nasłuchująca na porcie 65001.
Porty kontenerowe
Po dodaniu zasobu kontenera .NET.NET Aspire automatycznie przypisuje losowy port do kontenera. Aby określić port kontenera, skonfiguruj zasób kontenera przy użyciu żądanego portu:
builder.AddContainer("frontend", "mcr.microsoft.com/dotnet/samples", "aspnetapp")
.WithHttpEndpoint(port: 8000, targetPort: 8080);
Powyższy kod:
- Tworzy zasób kontenera o nazwie
frontend
na podstawie obrazumcr.microsoft.com/dotnet/samples:aspnetapp
. - Uwidacznia punkt końcowy
http
przez powiązanie hosta z portem 8000 i mapowanie go na port 8080 kontenera.
Rozważmy następujący diagram:
Metody rozszerzenia punktu końcowego
Każdy zasób implementujący interfejs IResourceWithEndpoints może używać metod rozszerzenia WithEndpoint
. Istnieje kilka wersji tego rozszerzenia, co umożliwia określenie schematu, portu kontenera, portu hosta, nazwy zmiennej środowiskowej i tego, czy punkt końcowy jest przekierowany.
Istnieje również przeciążenie, które umożliwia określenie delegata do konfiguracji punktu końcowego. Jest to przydatne, gdy trzeba skonfigurować punkt końcowy na podstawie środowiska lub innych czynników. Rozważ następujący kod:
builder.AddProject<Projects.Networking_ApiService>("apiService")
.WithEndpoint(
endpointName: "admin",
callback: static endpoint =>
{
endpoint.Port = 17003;
endpoint.UriScheme = "http";
endpoint.Transport = "http";
});
Powyższy kod udostępnia delegata wywołania zwrotnego w celu skonfigurowania punktu końcowego. Punkt końcowy nosi nazwę admin
i jest skonfigurowany do używania schematu http
i transportu, a także portu hosta 17003. Konsument odwołuje się do tego punktu końcowego po nazwie; rozważ następujące wywołanie AddHttpClient
:
builder.Services.AddHttpClient<WeatherApiClient>(
client => client.BaseAddress = new Uri("http://_admin.apiservice"));
Uri
jest konstruowany przy użyciu nazwy punktu końcowego admin
poprzedzonej sentinelem _
. Jest to konwencja wskazująca, że segment admin
jest nazwą punktu końcowego należącego do usługi apiservice
. Aby uzyskać więcej informacji, zobacz .NET.NET Aspire service discovery.
Dodatkowe zagadnienia
Podczas wywoływania metody rozszerzenia WithEndpoint
przeciążenie callback
uwidacznia nieprzetworzone EndpointAnnotation, co umożliwia użytkownikowi dostosowanie wielu aspektów punktu końcowego.
Właściwość AllocatedEndpoint
umożliwia uzyskanie lub ustawienie punktu końcowego dla usługi. Właściwości IsExternal
i IsProxied
określają sposób zarządzania i uwidocznienia punktu końcowego: IsExternal
decyduje, czy ma być publicznie dostępny, a IsProxied
zapewnia zarządzanie nim przez DCP, co pozwala na wewnętrzne różnice portów i replikację.
Napiwek
Jeśli hostujesz zewnętrzny wykonywalny, który uruchamia własny serwer proxy i napotyka problemy z powiązaniem portu z powodu już powiązanego portu DCP, spróbuj ustawić właściwość IsProxied
na wartość false
. To uniemożliwia DCP zarządzanie serwerem proxy, dzięki czemu plik wykonywalny może pomyślnie powiązać port.
Właściwość Name
identyfikuje usługę, natomiast właściwości Port
i TargetPort
określają odpowiednio docelowe i nasłuchujące porty.
W przypadku komunikacji sieciowej właściwość Protocol
obsługuje TCP i UDP, z możliwością zwiększenia w przyszłości, a właściwość Transport
wskazuje protokół transportowy (HTTP, HTTP2, HTTP3). Na koniec, jeśli usługa jest adresowalna za pomocą URI, właściwość UriScheme
zapewnia schemat identyfikatora URI do konstruowania URI usługi.
Aby uzyskać więcej informacji, zobacz dostępne właściwości EndpointAnnotation.
Filtrowanie punktów końcowych
Wszystkie punkty końcowe zasobów projektów .NET.NET Aspire wykorzystują zestaw domyślnych heurystyk. Niektóre punkty końcowe są uwzględniane w ASPNETCORE_URLS
w czasie wykonywania, niektóre są publikowane jako HTTP/HTTPS_PORTS
, a niektóre konfiguracje są rozwiązywane z konfiguracji Kestrel. Niezależnie od domyślnego zachowania można filtrować punkty końcowe uwzględnione w zmiennych środowiskowych przy użyciu metody rozszerzenia WithEndpointsInEnvironment:
builder.AddProject<Projects.Networking_ApiService>("apiservice")
.WithHttpsEndpoint() // Adds a default "https" endpoint
.WithHttpsEndpoint(port: 19227, name: "admin")
.WithEndpointsInEnvironment(
filter: static endpoint =>
{
return endpoint.Name is not "admin";
});
Powyższy kod dodaje domyślny punkt końcowy HTTPS, a także punkt końcowy admin
na porcie 19227. Jednak punkt końcowy admin
jest wykluczony ze zmiennych środowiskowych. Jest to przydatne, gdy chcesz uwidocznić punkt końcowy tylko do użytku wewnętrznego.