๐ช API ็ฝๅ
ณ่ฎพ่ฎกๆๅ
1. ไธบไปไน้่ฆ็ฝๅ
ณ๏ผ
1.1 ๆฒกๆ็ฝๅ
ณ็้ฎ้ข
ไผ ็ปๆถๆ๏ผๆ ็ฝๅ
ณ๏ผ๏ผ
โโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Client โโโโโโโ Service A โ
โโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ โโโโโโโโโโโโโโโ
โโโโโโโโโโโโโ Service B โ
โ โโโโโโโโโโโโโโโ
โ โโโโโโโโโโโโโโโ
โโโโโโโโโโโโโ Service C โ
โโโโโโโโโโโโโโโ
้ฎ้ข๏ผ
โข ๅฎขๆท็ซฏ้่ฆ็ฅ้ๆๆๆๅกๅฐๅ
โข ๆฏไธชๆๅก้ฝ่ฆๅฎ็ฐ่ฎค่ฏใ้ๆตใๆฅๅฟ
โข ่ทจๅใๅ่ฎฎ่ฝฌๆข็ญ้ๅคๅค็
โข ๆๅกๅๆดๅฎขๆท็ซฏ้่ฆๅๆญฅไฟฎๆน
โข ๅฎๅ
จ่พน็ๆจก็ณ๏ผๆปๅป้ขๅคง
1.2 ็ฝๅ
ณ่งฃๅณ็ๆ ธๅฟ้ฎ้ข
| ็ปไธๅ
ฅๅฃ |
ๅไธ่ฎฟ้ฎ็น๏ผๅฑ่ฝๅ็ซฏๅคๆๆง |
| ๅฎๅ
จ่พน็ |
้ไธญ่ฎค่ฏๆๆ๏ผๅๅฐๆปๅป้ข |
| ๆต้็ฎกๆง |
้ๆตใ็ๆญใ่ด่ฝฝๅ่กก |
| ๅ่ฎฎ่ฝฌๆข |
HTTP/gRPC/WebSocket ไบ่ฝฌ |
| ่ฏทๆฑ่ๅ |
BFF ๆจกๅผ๏ผๅๅฐๅฎขๆท็ซฏ่ฏทๆฑๆฌกๆฐ |
| ็ๆงๅฎก่ฎก |
็ปไธๆฅๅฟใ้พ่ทฏ่ฟฝ่ธชใๆๆ ้้ |
| ็ฐๅบฆๅๅธ |
ๆ่งๅ่ทฏ็ฑๅฐไธๅ็ๆฌ |
1.3 ็ฝๅ
ณๆถๆ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ API Gateway โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โ
โ โ ่ฎค่ฏ โ โ ้ๆต โ โ ่ทฏ็ฑ โ โ ็ๆง โ โ
โ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โ
โ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โ
โ โ ็ผๅญ โ โ ็ๆญ โ โ ่ฝฌๆข โ โ ๆฅๅฟ โ โ
โ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Service A โ โ Service B โ โ Service C โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
2. ็ฝๅ
ณๅจๅๅธๅผ็ณป็ปไธญ็ๅบ็จ
2.1 ๆ ธๅฟๅ่ฝ
่ทฏ็ฑไธ่ด่ฝฝๅ่กก
// YARP ่ทฏ็ฑ้
็ฝฎ็คบไพ
{
"ReverseProxy": {
"Routes": {
"orders-route": {
"ClusterId": "orders-cluster",
"Match": { "Path": "/api/orders/{**catch-all}" }
},
"users-route": {
"ClusterId": "users-cluster",
"Match": { "Path": "/api/users/{**catch-all}" }
}
},
"Clusters": {
"orders-cluster": {
"LoadBalancingPolicy": "RoundRobin",
"Destinations": {
"d1": { "Address": "http://orders-service-1:5000" },
"d2": { "Address": "http://orders-service-2:5000" }
}
}
}
}
}
่ฎค่ฏไธๆๆ
// JWT ่ฎค่ฏไธญ้ดไปถ
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://identity-server";
options.Audience = "api-gateway";
});
// ็ฝๅ
ณ็ปไธ้ช่ฏ๏ผไธๆธธๆๅกไฟกไปป็ฝๅ
ณ
app.UseAuthentication();
app.UseAuthorization();
้ๆตไธ็ๆญ
// ไฝฟ็จ Polly ๅฎ็ฐ็ๆญ
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
.AddTransforms(context =>
{
context.AddRequestTransform(async transformContext =>
{
// ๆทปๅ ้ๆต้ป่พ
await _rateLimiter.WaitAsync(transformContext.HttpContext.RequestAborted);
});
});
่ฏทๆฑ่ๅ๏ผBFF ๆจกๅผ๏ผ
// GraphQL ่ๅๅคไธชๆๅก
public class Query
{
public async Task<OrderWithUser> GetOrderDetail(
[Service] IOrderService orderService,
[Service] IUserService userService,
int orderId)
{
var order = await orderService.GetOrderAsync(orderId);
var user = await userService.GetUserAsync(order.UserId);
return new OrderWithUser { Order = order, User = user };
}
}
2.2 ๅธธ่งๆถๆๆจกๅผ
ๅไธ็ฝๅ
ณ
้็จ๏ผไธญๅฐๅ็ณป็ป
โโโโโโโโโโโโ
โ Gateway โ
โโโโโโฌโโโโโโ
โโโโโโโโโโโผโโโโโโโโโโ
โผ โผ โผ
Users Orders Products
ๅค็ฝๅ
ณ๏ผๆๅฎขๆท็ซฏๅ๏ผ
้็จ๏ผๅค็ซฏๅบ็จ๏ผWeb/Mobile/็ฌฌไธๆน๏ผ
Web Client Mobile App Partner API
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ
โ Web GW โ โMobile GW โ โPartner GWโ
โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ
โโโโโโโโโโโโโโโผโโโโโโโโโโโโโโ
โผ
Internal Services
็ฝๅ
ณ + Service Mesh
้็จ๏ผๅคงๅๅพฎๆๅก็ณป็ป
Client โ API Gateway โ [Service Mesh (Istio/Linkerd)]
โ
โโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโ โโโโโโโโโโ โโโโโโโโโโ
โSidecar โ โSidecar โ โSidecar โ
โ + โ โ + โ โ + โ
โService โ โService โ โService โ
โโโโโโโโโโ โโโโโโโโโโ โโโโโโโโโโ
2.3 ็ฝๅ
ณ vs Service Mesh
| ๆต้ๅ
ฅๅฃ |
โ
ๅๅๅๆต้ |
โ ไธป่ฆไธ่ฅฟๅ |
| ่ฎค่ฏๆๆ |
โ
ๅค้จ่ฎค่ฏ |
โ
ๆๅก้ด mTLS |
| ้ๆต็ๆญ |
โ
ๅ
ฅๅฃ็บงๅซ |
โ
ๆๅก็บงๅซ |
| ๅ่ฎฎ่ฝฌๆข |
โ
|
โ |
| ่ฏทๆฑ่ๅ |
โ
|
โ |
| ๅฏ่งๆตๆง |
โ
ๅ
ฅๅฃ็บงๅซ |
โ
ๅ
จ้พ่ทฏ |
| ้จ็ฝฒๅคๆๅบฆ |
ไฝ |
้ซ |
3. .NET ็ฝๅ
ณๅฎ็ฐๆนๆก
3.1 ๆนๆกๆฆ่ง
| YARP |
ๅๅไปฃ็ๅบ |
Microsoft |
่ชๅฎไน็ฝๅ
ณ |
| Ocelot |
API ็ฝๅ
ณๆกๆถ |
ๅผๆบ็คพๅบ |
ๅฟซ้ๆญๅปบ |
| Azure API Management |
ไบๆๅก |
Microsoft |
Azure ้จ็ฝฒ |
| Kong |
็ฌ็ซ็ฝๅ
ณ |
Kong Inc |
ๅค่ฏญ่จ็ฏๅข |
| ่ช็ ๏ผASP.NET Core๏ผ |
่ชๅฎไน |
- |
็นๆฎ้ๆฑ |
3.2 YARP๏ผYet Another Reverse
Proxy๏ผ
ๅ
: Yarp.ReverseProxy
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();
appsettings.json:
{
"ReverseProxy": {
"Routes": {
"api-route": {
"ClusterId": "api-cluster",
"Match": { "Path": "/api/{**catch-all}" },
"Transforms": [
{ "PathRemovePrefix": "/api" }
]
}
},
"Clusters": {
"api-cluster": {
"LoadBalancingPolicy": "RoundRobin",
"HealthCheck": {
"Active": {
"Enabled": true,
"Interval": "00:00:10",
"Path": "/health"
}
},
"Destinations": {
"d1": { "Address": "http://backend-1:5000" },
"d2": { "Address": "http://backend-2:5000" }
}
}
}
}
}
่ชๅฎไนไธญ้ดไปถ:
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
.AddTransforms(context =>
{
// ๆทปๅ ่ฏทๆฑๅคด
context.AddRequestHeader("X-Forwarded-Host", context.HttpContext.Request.Host.Value);
// ่ชๅฎไน่ฝฌๆข
context.AddRequestTransform(async transformContext =>
{
var userId = transformContext.HttpContext.User.FindFirst("sub")?.Value;
if (userId != null)
{
transformContext.ProxyRequest.Headers.Add("X-User-Id", userId);
}
});
});
3.3 Ocelot
ๅ
: Ocelot
// Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddJsonFile("ocelot.json");
builder.Services.AddOcelot();
var app = builder.Build();
await app.UseOcelot();
app.Run();
ocelot.json:
{
"Routes": [
{
"DownstreamPathTemplate": "/api/users/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{ "Host": "users-service", "Port": 5001 }
],
"UpstreamPathTemplate": "/users/{everything}",
"UpstreamHttpMethod": [ "Get", "Post", "Put", "Delete" ],
"AuthenticationOptions": {
"AuthenticationProviderKey": "Bearer"
},
"RateLimitOptions": {
"EnableRateLimiting": true,
"Period": "1s",
"Limit": 100
}
},
{
"DownstreamPathTemplate": "/api/orders/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{ "Host": "orders-service", "Port": 5002 }
],
"UpstreamPathTemplate": "/orders/{everything}",
"LoadBalancerOptions": {
"Type": "RoundRobin"
}
}
],
"GlobalConfiguration": {
"BaseUrl": "https://api.example.com"
}
}
ๆๅกๅ็ฐ๏ผConsul๏ผ:
builder.Services.AddOcelot()
.AddConsul();
{
"Routes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"DownstreamScheme": "http",
"UpstreamPathTemplate": "/users/{everything}",
"ServiceName": "users-service",
"LoadBalancerOptions": { "Type": "RoundRobin" }
}
],
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Scheme": "http",
"Host": "consul",
"Port": 8500,
"Type": "Consul"
}
}
}
3.4 ่ช็ ็ฝๅ
ณ๏ผASP.NET Core๏ผ
// ็ฎๅๅๅไปฃ็ๅฎ็ฐ
public class ProxyMiddleware
{
private readonly RequestDelegate _next;
private readonly IHttpClientFactory _clientFactory;
private readonly IServiceDiscovery _discovery;
public ProxyMiddleware(RequestDelegate next, IHttpClientFactory clientFactory,
IServiceDiscovery discovery)
{
_next = next;
_clientFactory = clientFactory;
_discovery = discovery;
}
public async Task InvokeAsync(HttpContext context)
{
var path = context.Request.Path.Value;
// ่ทฏ็ฑๅน้
var service = ResolveService(path);
if (service == null)
{
await _next(context);
return;
}
// ๆๅกๅ็ฐ
var endpoint = await _discovery.GetEndpointAsync(service);
// ่ฝฌๅ่ฏทๆฑ
var client = _clientFactory.CreateClient();
var request = CreateProxyRequest(context, endpoint);
var response = await client.SendAsync(request);
// ๅคๅถๅๅบ
await CopyResponseAsync(context, response);
}
private HttpRequestMessage CreateProxyRequest(HttpContext context, string endpoint)
{
var request = new HttpRequestMessage
{
Method = new HttpMethod(context.Request.Method),
RequestUri = new Uri($"{endpoint}{context.Request.Path}{context.Request.QueryString}")
};
// ๅคๅถ่ฏทๆฑๅคด
foreach (var header in context.Request.Headers)
{
request.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
}
// ๅคๅถ่ฏทๆฑไฝ
if (context.Request.ContentLength > 0)
{
request.Content = new StreamContent(context.Request.Body);
}
return request;
}
}
4. .NET ็ฝๅ
ณๆกๆถๅฏนๆฏ
4.1 ๅ่ฝๅฏนๆฏ
| ่ทฏ็ฑ |
โ
|
โ
|
โ
|
โ
|
| ่ด่ฝฝๅ่กก |
โ
|
โ
|
โ
|
โ
|
| ๅฅๅบทๆฃๆฅ |
โ
|
โ
|
โ
|
โ
|
| ้ๆต |
้ๆฉๅฑ |
โ
|
โ
|
โ
|
| ็ๆญ |
้ๆฉๅฑ |
โ
|
โ
|
โ
|
| ่ฎค่ฏ |
้้ๆ |
โ
|
โ
|
โ
|
| ่ฏทๆฑ่ๅ |
โ |
โ
|
โ
|
ๆไปถ |
| ๆๅกๅ็ฐ |
้ๆฉๅฑ |
โ
|
โ
|
โ
|
| ็ผๅญ |
้ๆฉๅฑ |
โ
|
โ
|
โ
|
| WebSocket |
โ
|
โ
|
โ
|
โ
|
| gRPC |
โ
|
โ |
โ
|
โ
|
| ็ฎก็ UI |
โ |
โ |
โ
|
โ
|
4.2 ๆง่ฝๅฏนๆฏ
| ๅๅ้ |
โญโญโญโญโญ |
โญโญโญ |
โญโญโญโญ |
| ๅปถ่ฟ |
< 1ms |
2-5ms |
1-2ms |
| ๅ
ๅญๅ ็จ |
ไฝ |
ไธญ |
้ซ |
| CPU ๅ ็จ |
ไฝ |
ไธญ |
ไธญ |
YARP ๆฏ็ฎๅ .NET ็ๆไธญๆง่ฝๆๅฅฝ็ๆนๆก๏ผๅพฎ่ฝฏๅ
้จๆๅกๅคง้ไฝฟ็จใ
4.3 ไผๅฃๅฟๅฏนๆฏ
YARP
| โ
ๅพฎ่ฝฏๅฎๆน็ปดๆค๏ผ้ฟๆๆฏๆ |
โ ๅ่ฝ้่ฆ่ชๅทฑๆฉๅฑ |
| โ
ๆง่ฝๆไฝณ |
โ ๆฒกๆๅ
็ฝฎ้ๆต/็ๆญ |
| โ
้ซๅบฆๅฏๅฎๅถ |
โ ๅญฆไน ๆฒ็บฟ็จ้ซ |
| โ
ๆฏๆ gRPC/WebSocket |
โ ๆ ็ฎก็็้ข |
| โ
ไธ ASP.NET Core ๆทฑๅบฆ้ๆ |
|
Ocelot
| โ
ๅผ็ฎฑๅณ็จ๏ผๅ่ฝๅฎๆด |
โ ๆง่ฝไธๅฆ YARP |
| โ
้
็ฝฎ็ฎๅ |
โ ไธๆฏๆ gRPC |
| โ
ๅ
็ฝฎ้ๆต/็ๆญ/็ผๅญ |
โ ็คพๅบๆดป่ทๅบฆไธ้ |
| โ
ๆฏๆๆๅกๅ็ฐ๏ผConsul/Eureka๏ผ |
โ ๆฉๅฑๆงๆ้ |
| โ
ๆๆกฃๅฎๅ |
|
Azure API Management
| โ
ๅฎๆด็็ฎก็็้ข |
โ ๆๆฌ่พ้ซ |
| โ
ๅผๅ่
้จๆท |
โ ไป
้ Azure |
| โ
ๆ็ฎกๆๅก๏ผๆ ้่ฟ็ปด |
โ ๅทๅฏๅจๅปถ่ฟ |
| โ
ๅ
็ฝฎๅๆๅ็ๆง |
โ ่ชๅฎไนๅ้ |
| โ
็ๆฌ็ฎก็ใAPI ๆๆกฃ |
|
Kong
| โ
่ฏญ่จๆ ๅ
ณ๏ผๅค็ฏๅข้จ็ฝฒ |
โ ไธๆฏ .NET ๅ็ |
| โ
ไธฐๅฏ็ๆไปถ็ๆ |
โ ้จ็ฝฒๅคๆ๏ผ้่ฆๆฐๆฎๅบ๏ผ |
| โ
ไผไธ็ๅ่ฝๅผบๅคง |
โ ไผไธ็ๆถ่ดน |
| โ
็ฎก็็้ข |
โ ไธ .NET ้ๆไธๅฆๅ็ๆนๆก |
4.4 ้ๅๅปบ่ฎฎ
| ้ซๆง่ฝ้ๆฑ |
YARP |
ๆง่ฝๆไฝณ๏ผๅฎๆนๆฏๆ |
| ๅฟซ้ๆญๅปบ |
Ocelot |
ๅ่ฝๅฎๆด๏ผ้
็ฝฎ็ฎๅ |
| Azure ้จ็ฝฒ |
Azure APIM |
ๆ็ฎกๆๅก๏ผๆ ้่ฟ็ปด |
| ๅค่ฏญ่จๅพฎๆๅก |
Kong |
่ฏญ่จๆ ๅ
ณ๏ผๆไปถไธฐๅฏ |
| ๆทฑๅบฆๅฎๅถ |
YARP + ่ชๅฎไนๆฉๅฑ |
ๅฏๆงๆงๆๅผบ |
| ไธญๅฐๅ้กน็ฎ |
Ocelot |
ๅค็จไธ็ฎๅ |
5. ไบ้จ็ฝฒ็ฝๅ
ณ่ฎพ่ฎกๆณจๆไบ้กน
5.1 ้ซๅฏ็จ่ฎพ่ฎก
โโโโโโโโโโโโโโโโโโโ
โ Load Balancer โ
โ (Azure LB / โ
โ AWS ALB) โ
โโโโโโโโโโฌโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
โ Gateway โ โ Gateway โ โ Gateway โ
โ (Zone A) โ โ (Zone B) โ โ (Zone C) โ
โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโ
ๅ
ณ้ฎ็น๏ผ - โ
ๅคๅฎไพ้จ็ฝฒ๏ผ่ทจๅฏ็จๅบ - โ
ๆ ็ถๆ่ฎพ่ฎก๏ผๆฏๆๆฐดๅนณๆฉๅฑ - โ
ๅฅๅบทๆฃๆฅ้
็ฝฎ - โ
ไผ่ฏไฟๆ๏ผๅฆ้่ฆ๏ผ
5.2 ๅฎๅ
จ่ฎพ่ฎก
// 1. HTTPS ๅผบๅถ
app.UseHttpsRedirection();
app.UseHsts();
// 2. ่ฏทๆฑๅคดๅฎๅ
จ
app.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
await next();
});
// 3. IP ็ฝๅๅ๏ผๅ
้จๆๅก๏ผ
builder.Services.AddReverseProxy()
.AddTransforms(context =>
{
context.AddRequestTransform(async transformContext =>
{
var clientIp = transformContext.HttpContext.Connection.RemoteIpAddress;
if (!IsAllowedIp(clientIp))
{
transformContext.HttpContext.Response.StatusCode = 403;
return;
}
});
});
// 4. ่ฏทๆฑๅคงๅฐ้ๅถ
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10MB
});
5.3 ้ๆตไธ็ๆญ
// ไฝฟ็จ ASP.NET Core Rate Limiting (.NET 7+)
builder.Services.AddRateLimiter(options =>
{
// ๅ
จๅฑ้ๆต
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = 100,
Window = TimeSpan.FromMinutes(1),
QueueLimit = 10
}));
// ๆ่ทฏ็ฑ้ๆต
options.AddPolicy("api", context =>
RateLimitPartition.GetSlidingWindowLimiter(
partitionKey: context.User.Identity?.Name ?? "anonymous",
factory: _ => new SlidingWindowRateLimiterOptions
{
PermitLimit = 1000,
Window = TimeSpan.FromMinutes(1),
SegmentsPerWindow = 6
}));
options.OnRejected = async (context, token) =>
{
context.HttpContext.Response.StatusCode = 429;
await context.HttpContext.Response.WriteAsJsonAsync(new
{
error = "Too many requests",
retryAfter = context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)
? retryAfter.TotalSeconds : 60
}, token);
};
});
app.UseRateLimiter();
5.4 ๅฏ่งๆตๆง
// OpenTelemetry ้ๆ
builder.Services.AddOpenTelemetry()
.WithTracing(tracing =>
{
tracing
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddSource("Yarp.ReverseProxy")
.AddOtlpExporter(options =>
{
options.Endpoint = new Uri("http://otel-collector:4317");
});
})
.WithMetrics(metrics =>
{
metrics
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddMeter("Yarp.ReverseProxy")
.AddOtlpExporter();
});
// ๅฅๅบทๆฃๆฅ็ซฏ็น
builder.Services.AddHealthChecks()
.AddCheck("gateway", () => HealthCheckResult.Healthy())
.AddRedis(redisConnectionString)
.AddUrlGroup(new Uri("http://backend/health"), "backend");
app.MapHealthChecks("/health", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
5.5 ้
็ฝฎ็ฎก็
// ๅจๆ้
็ฝฎ๏ผๆ ้้ๅฏ๏ผ
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"))
.ConfigureHttpClient((context, handler) =>
{
// ่ชๅฎไน HttpClient
handler.SslOptions.RemoteCertificateValidationCallback =
(sender, cert, chain, errors) => true; // ไป
ๅผๅ็ฏๅข
});
// ไป้
็ฝฎไธญๅฟๅ ่ฝฝ๏ผๅฆ Azure App Configuration๏ผ
builder.Configuration.AddAzureAppConfiguration(options =>
{
options.Connect(connectionString)
.Select("Gateway:*")
.ConfigureRefresh(refresh =>
{
refresh.Register("Gateway:Sentinel", refreshAll: true)
.SetCacheExpiration(TimeSpan.FromSeconds(30));
});
});
5.6 ๅฎนๅจๅ้จ็ฝฒ
Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["Gateway/Gateway.csproj", "Gateway/"]
RUN dotnet restore "Gateway/Gateway.csproj"
COPY . .
WORKDIR "/src/Gateway"
RUN dotnet build -c Release -o /app/build
FROM build AS publish
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
# ๅฅๅบทๆฃๆฅ
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost/health || exit 1
ENTRYPOINT ["dotnet", "Gateway.dll"]
Kubernetes ้จ็ฝฒ:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
spec:
replicas: 3
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
spec:
containers:
- name: gateway
image: myregistry/api-gateway:latest
ports:
- containerPort: 80
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 5
periodSeconds: 10
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Production"
---
apiVersion: v1
kind: Service
metadata:
name: api-gateway
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
selector:
app: api-gateway
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-gateway-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-gateway
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
5.7 ไบ้จ็ฝฒๆฃๆฅๆธ
ๅ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ไบ้จ็ฝฒ็ฝๅ
ณๆฃๆฅๆธ
ๅ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ ้ซๅฏ็จ โ
โ โก ๅคๅฎไพ้จ็ฝฒ๏ผ่ณๅฐ 3 ไธช๏ผ โ
โ โก ่ทจๅฏ็จๅบๅๅธ โ
โ โก ๅฅๅบทๆฃๆฅ้
็ฝฎ โ
โ โก ่ชๅจๆฉ็ผฉๅฎน็ญ็ฅ โ
โ โ
โ ๅฎๅ
จ โ
โ โก HTTPS ๅผบๅถ โ
โ โก WAF ้
็ฝฎ โ
โ โก DDoS ้ฒๆค โ
โ โก ่ฏทๆฑๅคงๅฐ้ๅถ โ
โ โก ๆๆไฟกๆฏ่ฑๆ โ
โ โ
โ ๆง่ฝ โ
โ โก ้ๆต็ญ็ฅ โ
โ โก ็ๆญ้็บง โ
โ โก ๅๅบ็ผๅญ โ
โ โก ่ฟๆฅๆฑ ้
็ฝฎ โ
โ โ
โ ๅฏ่งๆต โ
โ โก ๆฅๅฟ่ๅ โ
โ โก ้พ่ทฏ่ฟฝ่ธช โ
โ โก ๆๆ ็ๆง โ
โ โก ๅ่ญฆ้
็ฝฎ โ
โ โ
โ ่ฟ็ปด โ
โ โก ้
็ฝฎไธญๅฟ้ๆ โ
โ โก ๅฏ้ฅ็ฎก็๏ผKey Vault๏ผ โ
โ โก ่็ปฟ/้ไธ้ๅๅธ โ
โ โก ๅๆป็ญ็ฅ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
6. ๆป็ป
ๆ ธๅฟ่ฆ็น
| ็ฝๅ
ณไฝ็จ |
็ปไธๅ
ฅๅฃใๅฎๅ
จ่พน็ใๆต้็ฎกๆงใ็ๆงๅฎก่ฎก |
| ๆจ่ๆนๆก |
้ซๆง่ฝ้ YARP๏ผๅฟซ้ๆญๅปบ้ Ocelot๏ผAzure ้ APIM |
| ไบ้จ็ฝฒ |
ๅคๅฎไพใ่ทจๅฏ็จๅบใ้ๆต็ๆญใๅฏ่งๆตๆง |
| ๅฎๅ
จ |
HTTPSใWAFใ้ๆตใ่ฏทๆฑๆ ก้ช |
้ๅ้ๆฅ
| ๆฐ้กน็ฎ + ้ซๆง่ฝ |
YARP |
| ๅฟซ้ๆญๅปบ + ๅ่ฝๅฎๆด |
Ocelot |
| Azure ไบๅ็ |
Azure API Management |
| ๅค่ฏญ่จๅพฎๆๅก |
Kong |
ๅ่่ตๆบ