Spring Cloud Gateway使用Kubernetes Service服务发现和Kubernetes ConfigMap配置中心
由于历史原因, 系统网关组件过旧, 现在想要对其进行改造, 将使用全新的组件进行升级, 完全摒弃一些外部组件, 使用Kubernetes统一管理, 降低维护成本. 大概是这样:
现状:
- API网关:Spring Cloud Zuul
- 注册中心:Spring Cloud Eureka
- 配置中心:无
- 部署环境:Kubernetes
- 构建工具:Gradle
目标:
- API网关:Spring Cloud Gateway
- 注册中心:Kubernetes Service Discovery
- 配置中心:Kubernetes ConfigMap Configuration
- 部署环境:Kubernetes
- 构建工具:Gradle
特性列表
- [x] Kubernetes Service Discovery
- [x] Kubernetes ConfigMap Configuration
- [x] Kubernetes ConfigMap Configuration Hot-Reload
- [x] Kubernetes Health Check
- [x] Gateway URL Route to Kubernetes Service
- [ ] Gateway White/Black List
开发环境
- Windows 11:22H2
- OpenJDK:11
- Jetbrains IDEA
- Spring Boot:2.7.12
- Spring Cloud:2021.0.7
快速开始
- 通过 https://start.spring.io/ 生成你的项目, 引入需要的依赖, 这是我的
build.gradle
dependencies {
// 应用健康检查
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Logback日志与链路追踪 TraceID
implementation 'org.springframework.boot:spring-boot-starter-logging'
implementation 'org.apache.skywalking:apm-toolkit-logback-1.x:8.8.0'
// 网关组件
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
// Kubernetes服务发现与配置中心
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-all'
// 单元测试
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
2. 配置 bootstrap-dev.yml
开启必要的特性, 这是我的 bootstrap-dev.yml
spring:
application:
name: dyrs-cncf-gateway
cloud:
kubernetes:
config:
enabled: true
name: my-config-map
namespace: dev
discovery:
enabled: true
namespaces:
- dev
reload:
enabled: true
monitoring-config-maps: true
strategy: refresh
gateway:
enabled: true
discovery:
locator:
enabled: true
lower-case-service-id: true
url-expression: "uri"
3. 预部署一个应用, 并为它配置 Kubernetes Service
, 在后面会通过Gateway应用访问这个 Kubernetes Service
. 在这里我的服务名为 py-http-example
, 这是我的service.yaml
kind: Service
apiVersion: v1
metadata:
name: py-http-example
namespace: dev
labels:
app: py-http-example
spec:
ports:
- name: http-5000
protocol: TCP
port: 5000
targetPort: 5000
nodePort: 32214
selector:
app: py-http-example
type: NodePort
4. 使用Gradle打包我的应用程序, 并通过docker build/push到镜像仓库
5. 将Gateway应用部署到Kubernetes集群, 并配置NodePort Service, 方便在开发过程中访问
kind: Service
apiVersion: v1
metadata:
name: cncf-gateway
namespace: dev
labels:
app: cncf-gateway
spec:
ports:
- name: http-8080
protocol: TCP
port: 8080
targetPort: 8080
nodePort: 30142
selector:
app: cncf-gateway
type: NodePort
6. 现在通过curl测试Gateway应用程序NodePort能否被正确访问
$ curl <http://172.16.103.210:30142/actuator/health>
{"status":"UP","groups":["liveness","readiness"]}
7. 最后通过Gateway应用程序调用py-http-example
服务的接口, 来进行网关的验证
$ curl <http://172.16.103.210:30142/py-http-example/api/books>
{
"books": [
{
"author": "Judy",
"id": 1,
"title": "Python"
},
{
"author": "Cline",
"id": 2,
"title": "Java"
}
]
}
常见问题
Kubernetes ConfigMap
改变, 但是应用获取不到变更后的值(@Value)
需要启用Class注解@RefreshScope
- 通过Gateway应用访问Service, 返回503错误: There was an unexpected error (type=Service Unavailable, status=503).
需要修改 spring.cloud.gateway.discovery.locator.url-expression="url"
, 默认值是 "'lb://'+serviceId"
- 通过
restTemplate.getForObject
访问Service报错
Service port必须是80