当业务量发生变化时,需要对上游服务进行扩缩容,或者因服务器硬件故障需要更换服务器。如果网关是通过配置来维护上游服务信息,在微服务架构模式下,其带来的维护成本可想而知。再者因不能及时更新这些信息,也会对业务带来一定的影响,还有人为误操作带来的影响也不可忽视,所以网关非常必要通过服务注册中心动态获取最新的服务实例信息。架构图如下所示:

常见的注册中心:Eureka, Etcd, Consul, Nacos, Zookeeper 等
APISIX 要扩展注册中心其实是件非常容易的事情,其基本步骤如下:
https://www.bookstack.cn/read/apisix-2.13-zh/275fbdd662ec08a9.md
discovery:
nacos:
host:
- "http://192.168.xx.xx:8848"
prefix: "/nacos/v1"
fetch_interval: 1
weight: 1
timeout:
connect: 2000
send: 2000
read: 5000
https://www.bookstack.cn/read/apisix-2.13-zh/a586728927b44a68.md
https://apisix.apache.org/zh/docs/apisix/next/discovery/kubernetes/
discovery:
kubernetes:
service:
schema: https
host: 192.168.60.146
port: "6443" #这里有一个比较坑的地方,port 必须是字符串,否则会导致 APISIX 启动报错:
client:
token: |-
ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNkltWTNNRVpCUTJSa2FHSnNkMVpsYjIwMWNFODVTMVpLUjE5TFFVTlhZVEo0ZWs5UlpFMXJiakZtV0RRaWZRLmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUpoY0dsemFYZ2lMQ0pyZFdKbGNtNWxkR1Z6TG1sdkwzTmxjblpwWTJWaFkyTnZkVzUwTDNObFkzSmxkQzV1WVcxbElqb2laR1ZtWVhWc2RDMTBiMnRsYmkxa2F6WTJlaUlzSW10MVltVnlibVYwWlhNdWFXOHZjMlZ5ZG1salpXRmpZMjkxYm5RdmMyVnlkbWxqWlMxaFkyTnZkVzUwTG01aGJXVWlPaUprWldaaGRXeDBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5elpYSjJhV05sTFdGalkyOTFiblF1ZFdsa0lqb2lOemxpTnpnd00yWXRPR1poWXkwMFlXRTVMVGsxWWpjdFlXSmhORFEwWVdNNE4yRXhJaXdpYzNWaUlqb2ljM2x6ZEdWdE9uTmxjblpwWTJWaFkyTnZkVzUwT21Gd2FYTnBlRHBrWldaaGRXeDBJbjAuT3hWUTh2d2w0ZnZaLThZbTk1anlNcTNxTFBPTDhjaGZxdlZKQy10WXhLb3J5X2Fma3dzcU5WZ1RONWZuYlhmLW53MlNHWmpJdV9MbnhhbGxiQmhGT0l6UkI3QTY5QkpsYkpfTTNTNHNXcjdhN1EzaF9xTUZsc0pQQ2VhSG1NV3doZUR2dnZfOHFoV2dfN3MtRGk4OHp6QWpva1dOMlZIM3FBRXU5dWpmeVRlUTJXRzZYTVJyWWM1Y0pwN2F2WjBrNUo0V05yMHdTRHpYRkFsQUtUOHV4NUJWSlg0VEl6eXdjZDdTdWtkR3FrbmVtUnc3Q0lDWmR0bnZxZ1lXWnJpRFdwaVBSYklDLUFISFgtY3RrREtBV19TdFhvNFRLSTcxTlRYTzdVd0wtMWV4eXM0VnBETEZ6TkdhVDBUOWVRM1llTktfRUxRQy0zZWJGOEItRjFDRU5n
match:
- default
- ^my-[a-z]+$
1 为了让 APISIX 能查询和监听 Kubernetes 的 Endpoints 资源变动,我们需要创建一个 ServiceAccount:
kind: ServiceAccount
apiVersion: v1
metadata:
name: apisix-test
namespace: default
2 以及一个具有集群级查询和监听 Endpoints 资源权限的 ClusterRole:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: apisix-test
rules:
- apiGroups: [ "" ]
resources: [ endpoints ]
verbs: [ get,list,watch ]
3 再将这个 ServiceAccount 和 ClusterRole 关联起来:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: apisix-test
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: apisix-test
subjects:
- kind: ServiceAccount
name: apisix-test
namespace: default
4 然后我们需要获取这个 ServiceAccount 的 token 值,如果 Kubernetes 是 v1.24 之前的版本,可以通过下面的方法获取 token 值:
$ kubectl get secrets | grep apisix-test
$ kubectl get secret apisix-test-token-89hcm -o jsonpath={.data.token} | base64 -d
5 Kubernetes 从 v1.24 版本开始,不能再通过 kubectl get secret 获取 token 了,需要手动建立secret来生成token:
# 集群执行这个yaml
apiVersion: v1
kind: Secret
metadata:
name: apisix-test-kubeapi
namespace: default
annotations:
kubernetes.io/service-account.name: "apisix-test"
type: kubernetes.io/service-account-token
data:
# 然后执行
kubectl get secret apisix-test-kubeapi -n default -o jsonpath={".data.token"} | base64 -d
6 我们在 APISIX 的配置文件 config.yaml 中添加如下内容( 将上面生成的 token 填写到 token 字段 ):
discovery:
kubernetes:
service:
schema: https
host: 127.0.0.1
port: "6443"
client:
token: ...
上面服务发现,我选择kubernetes时,并没有成功,而我直接在节点节,使用<服务名>.<命令空间>,这种方式反而是支持的,配置如下

kubectl describe serviceaccount <sa-name>
kubectl describe clusterrole <clusterrole-name>
kubectl describe clusterrolebinding <clusterrolebinding-name>
kubectl get rolebindings,clusterrolebindings --all-namespaces | grep apisix-test
说明: service_name 必须满足格式:[namespace]/[name]:[portName]
apiVersion: v1
kind: Endpoints
metadata:
name: plat-dev
namespace: default
subsets:
- addresses:
- ip: "10.5.10.109"
- ip: "10.5.10.110"
ports:
- port: 3306
name: port
这里有一个比较坑的地方,port 必须是字符串,否则会导致 APISIX 启动报错
invalid discovery kubernetes configuration: object matches none of the required
2024/05/17 03:01:07 [error] 54#54: *114 [lua] informer_factory.lua:295: list failed, kind: Endpoints, reason: Unauthorized, message : {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}
检查token值
2024/05/17 03:01:07 [error] 54#54: *114 [lua] informer_factory.lua:295: list failed, kind: Endpoints, reason: Forbidden, message : {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Forbidden","code":403}
检查serviceaccount绑定的clusterrole是否有endpoint权限
2024/05/17 03:05:22 [error] 52#52: *623 [lua] init.lua:400: nodes(): get unexpected upstream service_name: cms.default.svc.cluster.local, client: 192.168.60.136, server: _, request: "GET /k8s/products HTTP/1.1", host: "test-apisix.pkulaw.com"
2024/05/17 03:05:22 [error] 52#52: *623 [lua] init.lua:545: handle_upstream(): failed to set upstream: no valid upstream node: nil, client: 192.168.60.136, server: _, request: "GET /k8s/products HTTP/1.1", host: "test-apisix.pkulaw.com"
因为apisix中获取到的是k8s服务的endpoints地址【由service指向的pod的真实地址】,这个地址对k8s集群外是不公开的,如图

大功告成!
参考:https://www.aneasystone.com/archives/2023/03/apisix-service-discovery.html