GoSuda

En gennemgang af, hvordan man eksekverer en Go-server, der kan udvides, i dotnet aspire

By snowmerak
views ...

dotnet aspire?

Dotnet aspire er et værktøj, der er skabt for at hjælpe udviklere med cloud-native udvikling og konfiguration i takt med, at cloud-native miljøer vokser. Dette værktøj gør det muligt for .NET-udviklere nemt at deployere .NET-projekter og forskellige cloud-native infrastrukturer samt tjenester eller containere på andre sprog.

Det er naturligvis lanceret og drives fra Docker til k8s, og mange felter, industrier og udviklere i det eksisterende on-premise miljø er ved at flytte til cloud-native miljøer, og er allerede flyttet. Det er nu et modent felt. Derfor mener jeg ikke, at det er nødvendigt at forklare de eksisterende ulemper ved værtsnavne, portkonfiguration, firewalls, metrikstyring osv.

Så umiddelbart vil ovenstående forklaringer sandsynligvis ikke give dig nogen idé om, hvad dotnet aspire er. Det skyldes, at Microsoft heller ikke har givet en præcis definition. Derfor vil jeg heller ikke give nogen særlig definition. Men da jeg vil bruge de grundlæggende funktioner i dotnet aspire, som jeg forstår dem i denne artikel, bør du referere til dem og definere din egen position.

Projektkonfiguration

Oprettelse af et dotnet aspire-projekt

Hvis du ikke har en dotnet aspire-skabelon, skal du først installere skabelonen. Installer skabelonen med følgende kommando. Hvis du ikke har .net, skal du selv installere det.

1dotnet new install Aspire.ProjectTemplates

Og opret en ny løsning i en passende mappe.

1dotnet new sln

Kør derefter følgende kommando i løsningsmappen for at oprette et projekt med aspire-apphost-skabelonen.

1dotnet new aspire-apphost -o AppHost

Dette vil oprette et aspire-apphost-projekt, der kun indeholder simpel kode til opsætning.

Tilføjelse af Valkey

Lad os simpelthen tilføje Valkey.

Før du tilføjer den, tilbyder dotnet aspire forskellige tredjepartsløsninger gennem community hosting. Naturligvis kan valkey også modtage support fra denne community hosting, og den kan nemt bruges gennem følgende NuGet-pakke.

1dotnet add package Aspire.Hosting.Valkey

Derudover tilbydes forskellige integrerede hostings, som kan findes her. Lad os vende tilbage til valkey og åbne filen Program.cs i AppHost-projektet og redigere den som følger.

1var builder = DistributedApplication.CreateBuilder(args);
2
3var cache = builder.AddValkey("cache")
4    .WithDataVolume(isReadOnly: false)
5    .WithPersistence(interval: TimeSpan.FromMinutes(5),
6        keysChangedThreshold: 100);
7
8builder.Build().Run();

cache er en implementering af IResourceBuilder-grænsefladen, som indeholder oplysninger til opbygning af valkey-tjenesten.WithDataVolume opretter et volumen til lagring af cachedata, og WithPersistence giver mulighed for kontinuerlig lagring af cachedata. Indtil videre ser det ud til at spille en lignende rolle som volumes i docker-compose. Det er naturligvis noget, I også nemt kan lave. Men det falder uden for rammerne af denne artikel, så jeg vil ikke diskutere det nu.

Oprettelse af en Go-sprog ekkosserver

Lad os tilføje en simpel Go-sprogserver. Først oprettes et arbejdsområde ved hjælp af go work init i løsningsmappen. For .NET-udviklere kan et Go-arbejdsområde betragtes som svarende til en løsning.

Opret derefter en mappe med navnet EchoServer, gå ind i den, og kør go mod init EchoServer. Denne kommando opretter et Go-modul. Et modul kan betragtes som svarende til et projekt for .NET-udviklere. Opret derefter filen main.go og skriv følgende kode.

 1package main
 2
 3import (
 4	"log"
 5	"net/http"
 6	"os"
 7)
 8
 9func main() {
10	addr := os.Getenv("PORT")
11	log.Printf("Server started on %s", addr)
12
13	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
14		name := request.URL.Query().Get("name")
15		writer.Write([]byte("Hello, " + name))
16	})
17
18	http.ListenAndServe(":"+addr, nil)
19}

Når denne server køres af Aspire AppHost, injicerer den miljøvariablen PORT, som den skal lytte på, og udfører derefter serveren ved at læse den pågældende port. Det er en simpel server, der modtager en name-forespørgsel og returnerer Hello, {name}.

Lad os nu tilføje denne server til dotnet aspire.

Tilføjelse af ekkosserveren til aspire

Gå tilbage til Aspire AppHost-projektet, hvor du tilføjede Valkey, og tilføj community hosting til Go-sproget.

1dotnet add package CommunityToolkit.Aspire.Hosting.Golang

Og åbn filen Program.cs og tilføj følgende udsagn.

 1var builder = DistributedApplication.CreateBuilder(args);
 2
 3var cache = builder.AddValkey("cache")
 4    .WithDataVolume(isReadOnly: false)
 5    .WithPersistence(interval: TimeSpan.FromMinutes(5),
 6        keysChangedThreshold: 100);
 7
 8var echoServer = builder.AddGolangApp("echo-server", "../EchoServer")
 9    .WithHttpEndpoint(port: 3000, env: "PORT")
10    .WithExternalHttpEndpoints();
11
12builder.Build().Run();

Her er echoServer en implementering af IResourceBuilder-grænsefladen, der indeholder oplysninger til opbygning af Go-sprogserveren. Den nyligt tilføjede AddGolangApp-metode er en udvidelsesmetode til den brugerdefinerede vært til tilføjelse af Go-sprogserveren. Den bruger fast port 3000 og injicerer miljøvariablen PORT. Endelig giver WithExternalHttpEndpoints ekstern adgang.

For at teste kan du få vist Hello, world, når du får adgang til http://localhost:3000/?name=world.

Men i øjeblikket har dotnet aspire en tung straf for non-dotnet-projekter. Det er...

Projektudvidelse

Hvordan foregår horisontal skalering så?

I øjeblikket tilbyder dotnet aspire kun WithReplica-indstillingen til buildere for .NET-projekter, der er tilføjet med metoden AddProject. Men den tilbyder ikke denne indstilling for Go-sprogværter eller eksterne projekter som AddContainer.

Derfor skal du implementere den direkte ved hjælp af en separat load balancer eller reverse proxy. Men hvis dette er tilfældet, kan den pågældende reverse proxy blive en SPOF, så det er en god idé, at reverse proxyen tilbyder indstillingen WithReplica. Så er reverse proxyen nødvendigvis et .NET-projekt.

Indtil nu har jeg brugt metoder som nginx, trafik og direkte implementering til dette problem, men når begrænsningen er et .NET-projekt, har jeg ikke umiddelbart nogen løsning. Så jeg ledte efter en reverse proxy, der var implementeret i .NET, og heldigvis var der et valg, der hed YARP. YARP er en reverse proxy implementeret i .NET, den kan også fungere som en load balancer og tilbyder forskellige funktioner, så jeg besluttede, at det var et godt valg.

Lad os nu tilføje YARP.

Konfiguration af reverse proxy med YARP

Først skal du oprette et projekt til brug af YARP.

1dotnet new web -n ReverseProxy

Og flyt til projektet og installer YARP.

1dotnet add package Yarp.ReverseProxy --version 2.2.0

Når installationen er fuldført, skal du åbne filen Program.cs og skrive følgende kode.

 1using Yarp.ReverseProxy.Configuration;
 2
 3var builder = WebApplication.CreateBuilder(args);
 4
 5var routes = new List<RouteConfig>();
 6var clusters = new List<ClusterConfig>();
 7
 8builder.Services.AddReverseProxy()
 9    .LoadFromMemory(routes, clusters);
10
11var app = builder.Build();
12
13app.MapReverseProxy();
14app.Run(url: $"http://0.0.0.0:{Environment.GetEnvironmentVariable("PORT") ?? "5000"}");

Denne kode er den grundlæggende kode til brug af YARP.routes indeholder ruteoplysningerne, som reverse proxyen skal bruge, og clusters indeholder klyngeoplysningerne, som reverse proxyen skal bruge. Disse oplysninger indlæses i reverse proxyen med metoden LoadFromMemory. Endelig mappes og køres reverse proxyen ved hjælp af metoden MapReverseProxy.

Og til faktisk brug tilføjes en reference til reverse proxy-projektet i aspire apphost-projektet, og følgende sætning tilføjes og ændres i filen Program.cs.

1dotnet add reference ../ReverseProxy
1var echoServer = builder.AddGolangApp("echo-server", "../EchoServer")
2    .WithHttpEndpoint(env: "PORT");
3
4var reverseProxy = builder.AddProject<Projects.ReverseProxy>("gateway")
5    .WithReference(echoServer)
6    .WithHttpEndpoint(port: 3000, env: "PORT", isProxied: true)
7    .WithExternalHttpEndpoints();

Nu kan reverse proxyen referere til ekkosserveren. Strukturen er ved at blive ændret, så anmodninger, der kommer udefra, modtages fra reverse proxyen og sendes videre til ekkosserveren.

Ændring af reverse proxy

Først skal du ændre lytteadressen for det projekt, der er tildelt reverse proxyen. Fjern applicationUrl inde i filen Properties/launchSettings.json. Og åbn filen Program.cs og ændre den omfattende som følger.

 1using Yarp.ReverseProxy.Configuration;
 2
 3var builder = WebApplication.CreateBuilder(args);
 4
 5var routes = new List<RouteConfig>
 6{
 7    new RouteConfig
 8    {
 9        ClusterId = "cluster-echo",
10        RouteId = "route-echo",
11        Match = new RouteMatch
12        {
13            Path = "/"
14        }
15    }
16};
17
18var echoServerAddr = Environment.GetEnvironmentVariable("services__echo-server__http__0") ?? "http://localhost:8080";
19
20var clusters = new List<ClusterConfig>
21{
22    new ClusterConfig
23    {
24        ClusterId = "cluster-echo",
25        Destinations = new Dictionary<string, DestinationConfig>
26        {
27            { "destination-echo", new DestinationConfig { Address = echoServerAddr } }
28        }
29    }
30};
31
32builder.Services.AddReverseProxy()
33    .LoadFromMemory(routes, clusters);
34
35var app = builder.Build();
36
37app.MapReverseProxy();
38app.Run(url: $"http://0.0.0.0:{Environment.GetEnvironmentVariable("PORT") ?? "5000"}");

Først skal du ændre oplysningerne for routes og clusters. Tilføj henholdsvis echo-route og echo-cluster for at sende anmodninger til ekkosserveren. Og rediger for at læse og bruge adressen på ekkosserveren fra miljøvariablen.

Reglen for denne adresse er services__{service-name}__http__{index}. I tilfældet med ekkosserveren er tjenestenavnet echo-server, og da det er en enkelt instans, bruges 0 som indeks. Hvis du tilføjer en asp .net core-server, kan flere instanser oprettes gennem WithReplica, så du kan bruge dem ved at øge indekset. Undtagelseshåndteringen http://localhost:8080 er en ubetydelig skraldeværdi.

Når du kører projektet og får adgang til http://localhost:3000/?name=world, vil du stadig se Hello, world.

Udvidelseside

Nu har vi bekræftet, at Go-serveren er blevet tilføjet til dotnet aspire, og at anmodninger videresendes gennem reverse proxyen. Så nu kan vi udvide denne proces til at blive implementeret programmatisk. Du kan f.eks. oprette flere instanser ved at tilføje nummerering efter tjenestenavnet for ekkosserveren og automatisk tilføje indstillingerne for reverse proxyen.

Rediger koden, der bruger reverse proxyen og ekkosserveren i filen Program.cs i aspire apphost-projektet, som følger.

 1var reverseProxy = builder.AddProject<Projects.ReverseProxy>("gateway")
 2    .WithHttpEndpoint(port: 3000, env: "PORT", isProxied: true)
 3    .WithExternalHttpEndpoints();
 4
 5for (var i = 0; i < 8; i++)
 6{
 7    var echoServer = builder.AddGolangApp($"echo-server-{i}", "../EchoServer")
 8        .WithHttpEndpoint(env: "PORT");
 9    reverseProxy.WithReference(echoServer);
10}

Og rediger filen Program.cs i reverse proxy-projektet som følger.

 1var echoServerDestinations = new Dictionary<string, DestinationConfig>();
 2for (var i = 0; i < 8; i++)
 3{
 4    echoServerDestinations[$"destination-{i}"] = new DestinationConfig
 5    {
 6        Address = Environment.GetEnvironmentVariable($"services__echo-server-{i}__http__0") ?? "http://localhost:8080"
 7    };
 8}
 9
10var clusters = new List<ClusterConfig>
11{
12    new ClusterConfig
13    {
14        ClusterId = "cluster-echo",
15        Destinations = echoServerDestinations
16    }
17};

Tilføj destinationsindstillinger for de 8 øgede ekkosserverinstanser. Nu har reverse proxyen destinationsoplysninger om de øgede ekkosservere og kan videresende anmodninger. Hvis du får adgang til den eksisterende http://localhost:3000/?name=world, vil du stadig se Hello, world.

Afsluttende bemærkninger

Denne artikel har forklaret processen med at tilføje en Go-server til dotnet aspire og videresende anmodninger gennem en reverse proxy. Dog er udvidelsen endnu ikke skrevet fuldt ud, og et eksempel, der kan implementeres mere programmatisk gennem miljøvariabler, er skrevet i et separat lager. Se snowmerak/AspireStartPack for detaljer om projektkonfiguration og kode.

Personligt forventer jeg, at dotnet aspire kan spille sin egen rolle som et alternativ til docker compose og som et cloud-deploymentværktøj. Der er allerede en generator, der genererer docker compose eller k8s-manifest, så jeg tror, at almindelige udviklere har bedre adgang til infrastrukturværktøjer.