实施 API 版本控制
在软件开发的动态环境中,维护强大且灵活的 API 对于构建可扩展和可互操作的系统至关重要。随着软件随时间演进,不可避免地需要对 API 进行更改和更新。API 版本控制提供了一种系统的方法来引入重大更改,同时保持向后兼容性。
在本指南中,你将了解几种不同的 API 版本控制策略以及如何在 APISIX 中实施它们。
前置条件
基于路径的版本控制
基于路径的版本控制是 API 版本控制最流行的方法之一,它涉及将版本号直接合并到 API 端点的 URL 路径中,例如:
https://apis.yourdomain.com/v1/foo
https://apis.yourdomain.com/v2/foo
要在 APISIX 中实施此策略,请为每个 API 版本创建一个路由,如下所示:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "apis-v1",
"uri": "/v1/*",
"upstream": {
"type": "roundrobin",
"nodes": {
"https://apis.yourdomain.com": 1
},
"pass_host": "node",
"scheme": "https"
}
}'
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "apis-v2",
"uri": "/v2/*",
"upstream": {
"type": "roundrobin",
"nodes": {
"https://apis.yourdomain.com": 1
},
"pass_host": "node",
"scheme": "https"
}
}'
services:
- name: Version v1 Service
routes:
- uris:
- /v1/*
name: apis-v1
upstream:
type: roundrobin
pass_host: node
scheme: https
nodes:
- host: apis.yourdomain.com
weight: 1
- name: Version v2 Service
routes:
- uris:
- /v2/*
name: apis-v2
upstream:
type: roundrobin
pass_host: node
scheme: https
nodes:
- host: apis.yourdomain.com
weight: 1
将配置同步到 APISIX:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
创建一个将请求代理到 v1 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: ingress-apisix
name: passhost-node
spec:
targetRefs:
- name: your-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
type: ExternalName
externalName: apis.yourdomain.com
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: apis-v1
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: PathPrefix
value: /v1/*
backendRefs:
- name: your-external-domain
port: 443
创建另一个将请求代理到 v2 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: ingress-apisix
name: passhost-node
spec:
targetRefs:
- name: your-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
type: ExternalName
externalName: apis.yourdomain.com
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: apis-v2
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: PathPrefix
value: /v2/*
backendRefs:
- name: your-external-domain
port: 443
创建一个将请求代理到 v1 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
ingressClassName: apisix
scheme: https
passHost: node
externalNodes:
- type: Domain
name: apis.yourdomain.com
port: 443
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: apis-v1
spec:
ingressClassName: apisix
http:
- name: apis-v1
match:
paths:
- /v1/*
upstreams:
- name: your-external-domain
创建另一个将请求代理到 v2 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
ingressClassName: apisix
scheme: https
passHost: node
externalNodes:
- type: Domain
name: apis.yourdomain.com
port: 443
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: apis-v2
spec:
ingressClassName: apisix
http:
- name: apis-v2
match:
paths:
- /v2/*
upstreams:
- name: your-external-domain
将配置应用到你的集群:
kubectl apply -f v1-route.yaml -f v2-route.yaml
基于查询的版本控制
基于查询的版本控制是另一种 API 版本控制方法,它涉及将版本号合并到 URL 查询参数中,例如:
https://apis.yourdomain.com/foo?version=1
https://apis.yourdomain.com/foo?version=2
要在 APISIX 中实施此策略,请为每个 API 版本创建一个路由,并配置其匹配条件和优先级,如下所示:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "apis-v1",
"uri": "/*",
"vars": [[ "arg_version", "==", "1" ]],
"priority": 2,
"upstream": {
"type": "roundrobin",
"nodes": {
"https://apis.yourdomain.com": 1
},
"pass_host": "node",
"scheme": "https"
}
}'
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "apis-v2",
"uri": "/*",
"vars": [[ "arg_version", "==", "2" ]],
"priority": 3,
"upstream": {
"type": "roundrobin",
"nodes": {
"https://apis.yourdomain.com": 1
},
"pass_host": "node",
"scheme": "https"
}
}'
services:
- name: Version v1 Service
routes:
- uris:
- /*
name: apis-v1
vars:
- - arg_version
- "=="
- "1"
priority: 2
upstream:
type: roundrobin
pass_host: node
scheme: https
nodes:
- host: apis.yourdomain.com
weight: 1
- name: Version v2 Service
routes:
- uris:
- /*
name: apis-v2
vars:
- - arg_version
- "=="
- "2"
priority: 3
upstream:
type: roundrobin
pass_host: node
scheme: https
nodes:
- host: apis.yourdomain.com
weight: 1
将配置同步到 APISIX:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
创建一个将请求代理到 v1 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: ingress-apisix
name: passhost-node
spec:
targetRefs:
- name: your-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
type: ExternalName
externalName: apis.yourdomain.com
---
apiVersion: apisix.apache.org/v1alpha1
kind: HTTPRoutePolicy
metadata:
namespace: ingress-apisix
name: http-route-policy
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: apis-v1
priority: 2
vars:
- - arg_version
- ==
- "1"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: apis-v1
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: PathPrefix
value: /*
backendRefs:
- name: your-external-domain
port: 443
创建另一个 将请求代理到 v2 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: ingress-apisix
name: passhost-node
spec:
targetRefs:
- name: your-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
type: ExternalName
externalName: apis.yourdomain.com
---
apiVersion: apisix.apache.org/v1alpha1
kind: HTTPRoutePolicy
metadata:
namespace: ingress-apisix
name: http-route-policy
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: apis-v2
priority: 3
vars:
- - arg_version
- ==
- "2"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: apis-v2
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: PathPrefix
value: /*
backendRefs:
- name: your-external-domain
port: 443
创建一个将请求代理到 v1 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
ingressClassName: apisix
scheme: https
passHost: node
externalNodes:
- type: Domain
name: apis.yourdomain.com
port: 443
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: apis-v1
spec:
ingressClassName: apisix
http:
- name: apis-v1
match:
paths:
- /*
exprs:
- subject:
scope: Query
name: version
op: Equal
value: "1"
priority: 2
upstreams:
- name: your-external-domain
创建另一个将请求代理到 v2 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
ingressClassName: apisix
scheme: https
passHost: node
externalNodes:
- type: Domain
name: apis.yourdomain.com
port: 443
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: apis-v2
spec:
ingressClassName: apisix
http:
- name: apis-v2
match:
paths:
- /*
exprs:
- subject:
scope: Query
name: version
op: Equal
value: "2"
priority: 3
upstreams:
- name: your-external-domain
将配置应用到你的集群:
kubectl apply -f v1-route.yaml -f v2-route.yaml
由于两个路由都配置为匹配相同的 URI,设置优先级将允许具有较高优先级的路由首先匹配请求。
基于标头的版本控制
第三种 API 版本控制方法是使用 HTTP 标头进行版本控制。版本可以包含在自定义标头中,例如:
GET /foo HTTP/1.1
...
Api-Version: 1
GET /foo HTTP/1.1
...
Api-Version: 2
要在 APISIX 中实施此策略,请为每个 API 版本创建一个路由,并配置其匹配条件和优先级,如下所示:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "apis-v1",
"uri": "/*",
"vars": [[ "http_api_version", "==", "1" ]],
"priority": 2,
"upstream": {
"type": "roundrobin",
"nodes": {
"https://apis.yourdomain.com": 1
},
"pass_host": "node",
"scheme": "https"
}
}'
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "apis-v2",
"uri": "/*",
"vars": [[ "http_api_version", "==", "2" ]],
"priority": 3,
"upstream": {
"type": "roundrobin",
"nodes": {
"https://apis.yourdomain.com": 1
},
"pass_host": "node",
"scheme": "https"
}
}'
services:
- name: Version v1 Service
routes:
- uris:
- /*
name: apis-v1
vars:
- - http_api_version
- "=="
- "1"
priority: 2
upstream:
type: roundrobin
pass_host: node
scheme: https
nodes:
- host: apis.yourdomain.com
weight: 1
- name: Version v2 Service
routes:
- uris:
- /*
name: apis-v2
vars:
- - http_api_version
- "=="
- "2"
priority: 3
upstream:
type: roundrobin
pass_host: node
scheme: https
nodes:
- host: apis.yourdomain.com
weight: 1
将配置同步到 APISIX:
adc sync -f adc.yaml
- Gateway API
- APISIX CRD
创建一个将请求代理到 v1 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: ingress-apisix
name: passhost-node
spec:
targetRefs:
- name: your-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
type: ExternalName
externalName: apis.yourdomain.com
---
apiVersion: apisix.apache.org/v1alpha1
kind: HTTPRoutePolicy
metadata:
namespace: ingress-apisix
name: http-route-policy
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: apis-v1
priority: 2
vars:
- - http_api_version
- ==
- "1"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: apis-v1
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: PathPrefix
value: /*
backendRefs:
- name: your-external-domain
port: 443
创建另一个将请求代理到 v2 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: ingress-apisix
name: passhost-node
spec:
targetRefs:
- name: your-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
type: ExternalName
externalName: apis.yourdomain.com
---
apiVersion: apisix.apache.org/v1alpha1
kind: HTTPRoutePolicy
metadata:
namespace: ingress-apisix
name: http-route-policy
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: apis-v2
priority: 3
vars:
- - http_api_version
- ==
- "2"
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: apis-v2
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: PathPrefix
value: /*
backendRefs:
- name: your-external-domain
port: 443
创建一个将请求代理到 v1 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
ingressClassName: apisix
scheme: https
passHost: node
externalNodes:
- type: Domain
name: apis.yourdomain.com
port: 443
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: apis-v1
spec:
ingressClassName: apisix
http:
- name: apis-v1
match:
paths:
- /*
exprs:
- subject:
scope: Header
name: Api-Version
op: Equal
value: "1"
priority: 2
upstreams:
- name: your-external-domain
创建另一个将请求代理到 v2 API 的路由的 Kubernetes 清单文件:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: your-external-domain
spec:
ingressClassName: apisix
scheme: https
passHost: node
externalNodes:
- type: Domain
name: apis.yourdomain.com
port: 443
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: apis-v2
spec:
ingressClassName: apisix
http:
- name: apis-v2
match:
paths:
- /*
exprs:
- subject:
scope: Header
name: Api-Version
op: Equal
value: "2"
priority: 3
upstreams:
- name: your-external-domain
将配置应用到你的集群:
kubectl apply -f v1-route.yaml -f v2-route.yaml
相应地调整标头过滤条件,例如当 内容协商 用于版本控制时。
由于两个路由都配置为匹配相同的 URI,设置优先级将允许具有较高优先级的路由首先匹配请求。
下一步
对 API 进行版本控制时,通常需要将请求转发到不同的 URI 路径而不是原始请求路径,或者将请求从已弃用的端点重定向到版本化端点。有关更多信息,请参阅以下插件:
proxy-rewrite插件redirect插件(即将推出)