微服务解决方案:添加新的 API 网关
你必须拥有ABP商业版或更高级别的许可证才能创建微服务解决方案。
API网关是你的微服务系统的入口点。它们负责将传入的请求路由到正确的微服务。在一个微服务系统中,你可以拥有多个API网关来服务于不同的目的。例如,你可以拥有一个面向客户的公共API网关和一个面向内部服务的私有API网关。在解决方案模板中,有一个名为gateways的文件夹,其中包含API网关项目。你可以向此文件夹添加新的API网关。
此外,在根目录中有一个名为_templates的文件夹。此文件夹包含可用于创建新微服务、API网关和应用程序的模板。这些模板可以根据你的需求进行定制。
添加新的API网关
要向解决方案添加新的网关应用程序,你可以使用gateway模板。此模板会创建一个带有必要配置和依赖项的新ASP.NET Core应用程序。按照以下步骤添加新的Web应用程序:
在ABP Studio的解决方案资源管理器中,右键单击gateways文件夹,选择添加 -> 新模块 -> 网关。
这将打开创建新模块对话框。输入新网关应用程序的名称,如果需要则指定输出目录,然后单击创建按钮。有一个命名约定:模块名称应包含解决方案名称作为前缀,并且模块名称中不允许使用点(.)字符。
新网关已创建并添加到解决方案中。你可以在gateways文件夹中看到新的应用程序。
配置 appsettings.json
新网关应用程序使用YARP作为反向代理。你可以配置appsettings.json文件来定义路由和端点。appsettings.json文件中的ReverseProxy部分包含了反向代理的配置。你可以向此部分添加新的路由和端点。
{
"ReverseProxy": {
"Routes": {
"AbpApi": {
"ClusterId": "Administration",
"Match": {
"Path": "/api/abp/{**catch-all}"
}
},
"AdministrationSwagger": {
"ClusterId": "Administration",
"Match": {
"Path": "/swagger-json/Administration/swagger/v1/swagger.json"
},
"Transforms": [
{ "PathRemovePrefix": "/swagger-json/Administration" }
]
},
"ProductService": {
"ClusterId": "ProductService",
"Match": {
"Path": "/api/productservice/{**catch-all}"
}
},
"ProductServiceSwagger": {
"ClusterId": "ProductService",
"Match": {
"Path": "/swagger-json/ProductService/swagger/v1/swagger.json"
},
"Transforms": [
{ "PathRemovePrefix": "/swagger-json/ProductService" }
]
}
},
"Clusters": {
"Administration": {
"Destinations": {
"Administration": {
"Address": "http://localhost:44393/"
}
}
},
"ProductService": {
"Destinations": {
"ProductService": {
"Address": "http://localhost:44350/"
}
}
}
}
}
}
配置 OpenId 选项
我们应该通过修改Identity服务中的OpenIddictDataSeeder来配置OpenId选项。以下是PublicGateway应用程序的OpenIddictDataSeeder选项示例。
将创建的网关URL添加到OpenIddictDataSeeder类的CreateSwaggerClientAsync方法中的redirectUris参数中。
private async Task CreateSwaggerClientAsync(string clientId, string[] scopes)
{
var webGatewaySwaggerRootUrl = _configuration["OpenIddict:Applications:WebGateway:RootUrl"]!.TrimEnd('/');
//PublicGateway 的 Url
var publicGatewaySwaggerRootUrl = _configuration["OpenIddict:Applications:PublicGateway:RootUrl"]!.TrimEnd('/');
...
await CreateOrUpdateApplicationAsync(
name: clientId,
type: OpenIddictConstants.ClientTypes.Public,
consentType: OpenIddictConstants.ConsentTypes.Implicit,
displayName: "Swagger测试客户端",
secret: null,
grantTypes: new List<string>
{
OpenIddictConstants.GrantTypes.AuthorizationCode,
},
scopes: commonScopes.Union(scopes).ToList(),
redirectUris: new List<string> {
$"{webGatewaySwaggerRootUrl}/swagger/oauth2-redirect.html",
$"{publicGatewaySwaggerRootUrl}/swagger/oauth2-redirect.html", // PublicGateway 的重定向 URI
...
},
clientUri: webGatewaySwaggerRootUrl,
logoUri: "/images/clients/swagger.svg"
);
}
将新的网关URL添加到Identity服务的appsettings.json文件中。
{
"OpenIddict": {
"Applications": {
...
"PublicGateway": {
"RootUrl": "http://localhost:44382"
}
}
}
}
配置 AuthServer
我们应该为**CORS(跨域资源共享)和RedirectAllowedUrls(允许的重定向URL)**配置AuthServer。
"App": {
"SelfUrl": "http://localhost:***",
"CorsOrigins": "...... ,http://localhost:44382",
"EnablePII": false,
"RedirectAllowedUrls": "...... ,http://localhost:44382"
}
为新网关创建 Helm 图表
如果你希望将新网关部署到Kubernetes,你应该为该新应用程序创建一个Helm图表。
首先,将新网关添加到etc/helm文件夹中的build-all-images.ps1脚本中。你可以复制现有应用程序的配置,并根据新应用程序进行修改。以下是PublicGateway应用程序的build-all-images.ps1脚本示例。
./build-image.ps1 -ProjectPath "../../gateways/public/Acme.Bookstore.PublicGateway/Acme.Bookstore.PublicGateway.csproj" -ImageName bookstore/publicgateway
由于我们希望在集群外部公开我们的网关,我们应该将主机URL添加到etc/helm/projectname文件夹中的values.projectname-local.yaml文件中。以下是PublicGateway应用程序的values.bookstore-local.yaml文件示例。
global:
...
hosts:
...
publicgateway: "[RELEASE_NAME]-publicgateway"
出于开发目的,我们还应该为新网关创建TLS证书。你可以编辑etc/helm文件夹中的create-tls-certificate.ps1脚本,为新网关生成TLS证书。以下是PublicGateway应用程序的create-tls-certificate.ps1脚本示例。
mkcert --cert-file bookstore-local.pem --key-file bookstore-local-key.pem "bookstore-local" ... "bookstore-local-publicgateway"
kubectl create namespace bookstore-local
kubectl create secret tls -n bookstore-local bookstore-local-tls --cert=./bookstore-local.pem --key=./bookstore-local-key.pem
最后,我们应该在etc/helm/projectname/templates文件夹中的*_helpers.tpl文件中定义新应用程序。你可以复制现有应用程序的配置,并根据新应用程序进行修改。以下是PublicGateway应用程序的_helpers.tpl*文件示例。
{{- define "bookstore.hosts.publicgateway" -}}
{{- print "https://" (.Values.global.hosts.publicgateway | replace "[RELEASE_NAME]" .Release.Name) -}}
{{- end -}}
之后,我们需要为新网关创建一个新的Helm图表。你可以复制现有应用程序的配置,并根据新网关进行修改。以下是PublicGateway应用程序的publicgateway Helm图表示例。
# values.yaml
image:
repository: "bookstore/publicgateway"
tag: "latest"
pullPolicy: "IfNotPresent"
swagger:
isEnabled: "true"
# Chart.yaml
apiVersion: v2
name: publicgateway
appVersion: "1.0"
description: Bookstore 公共 API 网关
version: 1.0.0
type: application
# publicapigateway.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: "{{ .Release.Name }}-{{ .Chart.Name }}"
spec:
selector:
matchLabels:
app: "{{ .Release.Name }}-{{ .Chart.Name }}"
template:
metadata:
labels:
app: "{{ .Release.Name }}-{{ .Chart.Name }}"
spec:
containers:
- image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
name: "{{ .Release.Name }}-{{ .Chart.Name }}"
ports:
- name: "http"
containerPort: 80
env:
- name: "DOTNET_ENVIRONMENT"
value: "{{ .Values.global.dotnetEnvironment }}"
- name: "ElasticSearch__IsLoggingEnabled"
value: "{{ .Values.global.elasticSearch.isLoggingEnabled }}"
- name: "ElasticSearch__Url"
value: "http://{{ .Release.Name }}-elasticsearch:{{ .Values.global.elasticSearch.port }}"
- name: "Swagger__IsEnabled"
value: "{{ .Values.swagger.isEnabled }}"
- name: "AbpStudioClient__StudioUrl"
value: "{{ .Values.global.abpStudioClient.studioUrl }}"
- name: "AbpStudioClient__IsLinkEnabled"
value: "{{ .Values.global.abpStudioClient.isLinkEnabled }}"
- name: "ReverseProxy__Clusters__Administration__Destinations__Administration__Address"
value: "http://{{ .Release.Name }}-administration"
- name: "ReverseProxy__Clusters__ProductService__Destinations__ProductService__Address"
value: "http://{{ .Release.Name }}-productservice"
# publicapigateway-service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
name: "{{ .Release.Name }}-{{ .Chart.Name }}"
name: "{{ .Release.Name }}-{{ .Chart.Name }}"
spec:
ports:
- name: "80"
port: 80
selector:
app: "{{ .Release.Name }}-{{ .Chart.Name }}"
# publicapigateway-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: "{{ .Release.Name }}-{{ .Chart.Name }}"
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-buffer-size: "32k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
cert-manager.io/cluster-issuer: "letsencrypt"
spec:
ingressClassName: "nginx"
tls:
- hosts:
- "{{ (include "bookstore.hosts.publicgateway" .) | trimPrefix "https://" }}"
secretName: "{{ .Values.global.tlsSecret }}"
rules:
- host: "{{ (include "bookstore.hosts.publicgateway" .) | trimPrefix "https://" }}"
http:
paths:
- path: /
pathType: "Prefix"
backend:
service:
name: "{{ .Release.Name }}-{{ .Chart.Name }}"
port:
number: 80
创建Helm图表后,你可以在ABP Studio中刷新子图表。
然后,更新元数据信息,右键单击网关子图表,选择属性,这将打开图表属性窗口。你可以在元数据选项卡中进行编辑。
在图表属性 -> Kubernetes服务选项卡中添加服务名称的正则表达式模式。
最后但同样重要的是,我们需要为身份微服务和认证服务器应用程序配置Helm图表环境变量。
# identity.yaml
# 在 "env:" 部分添加这一行
- name: "OpenIddict__Applications__PublicGateway__RootUrl"
value: "{{ include "bookstore.hosts.publicgateway" . }}"
# authserver.yaml
# 为 "App__CorsOrigins" 部分拼接以下行
- name: "App__CorsOrigins"
value: "...,http://{{ .Release.Name }}-administration,{{ include "bookstore.hosts.publicgateway" . }}"
抠丁客








