GoSuda

Mencoba Menjalankan Server Go yang Dapat Diperluas di dotnet Aspire

By snowmerak
views ...

dotnet aspire?

dotnet aspire adalah alat yang dikembangkan untuk membantu pengembang dalam pengembangan dan konfigurasi cloud-native, seiring dengan meningkatnya lingkungan cloud-native. Alat ini memungkinkan pengembang .NET untuk dengan mudah menyebarkan proyek .NET dan berbagai infrastruktur cloud-native, serta layanan atau container dalam bahasa lain.

Tentu saja, docker hingga k8s telah dirilis dan dioperasikan, dan banyak sektor, industri, serta pengembang telah beralih atau sedang beralih dari lingkungan on-premise yang ada ke lingkungan cloud-native. Ini adalah bidang yang telah matang. Oleh karena itu, saya rasa tidak perlu menjelaskan ketidaknyamanan yang ada terkait nama host, konfigurasi port, firewall, dan manajemen metrik.

Maka, bahkan dari penjelasan di atas, Anda mungkin masih belum memahami apa itu dotnet aspire. Ini karena Microsoft sendiri belum memberikan definisi yang tepat. Oleh karena itu, saya juga tidak akan memberikan definisi khusus. Namun, dalam artikel ini, saya akan menggunakan fungsionalitas dasar dotnet aspire seperti yang saya pahami, jadi Anda bisa merujuknya untuk menentukan posisi Anda sendiri.

Konfigurasi Proyek

Pembuatan Proyek dotnet aspire

Jika Anda belum memiliki template dotnet aspire, Anda perlu menginstalnya terlebih dahulu. Instal template dengan perintah berikut. Jika Anda tidak memiliki .net, silakan instal sendiri.

1dotnet new install Aspire.ProjectTemplates

Kemudian, buat solusi baru di folder yang sesuai.

1dotnet new sln

Setelah itu, jalankan perintah berikut di folder solusi untuk membuat proyek template aspire-apphost.

1dotnet new aspire-apphost -o AppHost

Maka proyek aspire-apphost akan dibuat dengan kode sederhana untuk pengaturan.

Penambahan Valkey

Mari kita tambahkan Valkey secara singkat.

Sebelum menambahkannya, dotnet aspire menyediakan berbagai solusi pihak ketiga melalui community hosting. Tentu saja, Valkey juga dapat didukung oleh community hosting ini, dan dapat dengan mudah digunakan melalui paket nuget berikut.

1dotnet add package Aspire.Hosting.Valkey

Berbagai hosting terintegrasi lainnya tersedia dan dapat diperiksa di sini. Kembali ke Valkey, buka file Program.cs di proyek AppHost dan ubah seperti berikut.

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 adalah implementasi antarmuka IResourceBuilder yang berisi informasi untuk membangun layanan Valkey.WithDataVolume membuat volume untuk menyimpan data cache, dan WithPersistence memungkinkan data cache untuk disimpan secara terus-menerus. Sampai di sini, terlihat bahwa ini memiliki peran yang mirip dengan volumes di docker-compose. Tentu saja, Anda juga dapat membuatnya dengan mudah. Namun, ini di luar cakupan artikel ini, jadi saya tidak akan membahasnya sekarang.

Pembuatan Go Language Echo Server

Mari kita tambahkan server Go Language sederhana. Pertama, buat workspace dengan go work init di folder solusi. Bagi pengembang .NET, Go workspace dapat dianggap mirip dengan solusi.

Kemudian, buat folder bernama EchoServer, masuk ke dalamnya, dan jalankan go mod init EchoServer. Perintah ini akan membuat Go module. Module dapat dianggap mirip dengan proyek bagi pengembang .NET. Lalu, buat file main.go dan tuliskan seperti berikut.

 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}

Server ini akan membaca variabel lingkungan PORT yang disuntikkan saat Aspire AppHost dijalankan untuk mendengarkan, dan kemudian menjalankan server pada port tersebut. Ini adalah server sederhana yang menerima query name dan mengembalikan Hello, {name}.

Sekarang mari kita tambahkan server ini ke dotnet aspire.

Menambahkan Echo Server ke Aspire

Kembali ke proyek Aspire AppHost tempat Valkey ditambahkan, dan tambahkan community hosting untuk bahasa Go.

1dotnet add package CommunityToolkit.Aspire.Hosting.Golang

Kemudian, buka file Program.cs dan tambahkan pernyataan berikut.

 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();

Di sini, echoServer adalah implementasi antarmuka IResourceBuilder yang berisi informasi untuk membangun server Go Language. Metode AddGolangApp yang baru saja ditambahkan adalah metode ekstensi dari host kustom untuk menambahkan server Go Language. Dapat dilihat bahwa port 3000 digunakan secara tetap, dan variabel lingkungan PORT disuntikkan. Terakhir, WithExternalHttpEndpoints adalah untuk memungkinkan akses dari luar.

Untuk pengujian, jika Anda mengakses http://localhost:3000/?name=world, Anda akan melihat Hello, world ditampilkan.

Namun, saat ini dotnet aspire memiliki penalti besar yang diberikan kepada proyek non-dotnet. Yaitu...

Ekstensi Proyek

Bagaimana dengan Skalabilitas Horizontal?

Saat ini, dotnet aspire hanya menyediakan opsi WithReplica untuk builder proyek .NET yang ditambahkan dengan metode AddProject. Namun, opsi ini tidak tersedia untuk host Go Language atau proyek eksternal seperti AddContainer.

Oleh karena itu, Anda harus mengimplementasikannya sendiri menggunakan load balancer atau reverse proxy terpisah. Namun, hal ini dapat membuat reverse proxy menjadi SPOF, sehingga reverse proxy sebaiknya menyediakan opsi WithReplica. Jika demikian, reverse proxy haruslah proyek .NET.

Selama ini, masalah ini telah diatasi dengan menggunakan nginx, trafik, atau implementasi langsung, tetapi dengan batasan proyek .NET, saya tidak memiliki solusi langsung. Jadi, saya mencari reverse proxy yang diimplementasikan dengan .NET, dan untungnya ada pilihan YARP. YARP adalah reverse proxy yang diimplementasikan dengan .NET, dapat berfungsi sebagai load balancer, dan menyediakan berbagai fitur, sehingga saya menganggapnya sebagai pilihan yang baik.

Sekarang mari kita tambahkan YARP.

Konfigurasi Reverse Proxy dengan YARP

Pertama, buat proyek untuk menggunakan YARP.

1dotnet new web -n ReverseProxy

Kemudian, masuk ke proyek dan instal YARP.

1dotnet add package Yarp.ReverseProxy --version 2.2.0

Setelah instalasi selesai, buka file Program.cs dan tuliskan seperti berikut.

 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"}");

Kode ini adalah kode dasar untuk menggunakan YARP.routes berisi informasi rute yang akan digunakan oleh reverse proxy, dan clusters berisi informasi cluster yang akan digunakan oleh reverse proxy. Informasi ini dimuat ke reverse proxy dengan metode LoadFromMemory. Terakhir, reverse proxy dipetakan dan dijalankan menggunakan metode MapReverseProxy.

Dan untuk penggunaan praktis, tambahkan referensi proyek reverse proxy di proyek aspire apphost, dan tambahkan serta modifikasi pernyataan berikut di file 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();

Sekarang reverse proxy dapat mereferensikan echo server. Permintaan yang datang dari luar akan diterima oleh reverse proxy dan diteruskan ke echo server.

Modifikasi Reverse Proxy

Pertama, kita harus mengubah alamat listening proyek yang dialokasikan ke reverse proxy. Hapus applicationUrl di dalam file Properties/launchSettings.json. Kemudian, buka file Program.cs dan modifikasi secara menyeluruh seperti di bawah ini.

 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"}");

Pertama, modifikasi informasi tentang routes dan clusters. Tambahkan echo-route dan echo-cluster untuk mengatur agar permintaan dikirim ke echo server. Dan ubah agar alamat echo server dibaca dari variabel lingkungan.

Aturan alamat ini adalah services__{service-name}__http__{index}. Dalam kasus echo server, nama layanannya adalah echo-server, dan karena ini adalah instans tunggal, indeks 0 digunakan. Jika server asp .net core ditambahkan, beberapa instans dapat dibuat melalui WithReplica, sehingga indeks dapat ditingkatkan.http://localhost:8080 yang di-handle sebagai pengecualian adalah nilai sampah yang tidak memiliki arti.

Sekarang, jalankan proyek dan akses http://localhost:3000/?name=world, Anda akan tetap melihat Hello, world ditampilkan.

Ide Ekstensi

Sekarang kita telah menambahkan server Go ke dotnet aspire dan mengkonfirmasi bahwa permintaan diteruskan melalui reverse proxy. Maka, proses ini dapat diperluas untuk diimplementasikan secara programmatic. Misalnya, untuk echo server, beberapa instans dapat dibuat dengan menambahkan penomoran setelah nama layanan, dan pengaturan untuk reverse proxy dapat ditambahkan secara otomatis.

Dalam file Program.cs proyek aspire apphost, modifikasi kode yang menggunakan reverse proxy dan echo server sebagai berikut.

 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}

Dan modifikasi file Program.cs proyek reverse proxy sebagai berikut.

 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};

Tambahkan pengaturan tujuan untuk 8 instans echo server yang diperluas. Sekarang reverse proxy memiliki informasi tujuan untuk echo server yang diperluas dan dapat meneruskan permintaan. Jika Anda mengakses http://localhost:3000/?name=world seperti sebelumnya, Anda akan tetap melihat Hello, world ditampilkan.

Kesimpulan

Dalam artikel ini, kami menjelaskan proses penambahan server Go ke dotnet aspire dan meneruskan permintaan melalui reverse proxy. Namun, terkait ekstensi, belum semuanya ditulis, dan contoh yang dapat diimplementasikan secara lebih programmatic melalui variabel lingkungan telah ditulis di repositori terpisah. Untuk konfigurasi proyek dan kode yang lebih rinci, silakan merujuk ke snowmerak/AspireStartPack.

Secara pribadi, saya berharap dotnet aspire dapat menjalankan perannya sebagai alternatif docker compose, dan sebagai alat penyebaran cloud. Sudah ada generator yang menghasilkan docker compose atau k8s manifest, sehingga saya pikir aksesibilitas pengembang umum terhadap alat infrastruktur telah meningkat.