集成 Kubernetes 服务发现
Kubernetes 通过 Endpoints 或 EndpointSlices 跟踪每个 Service 后端已就绪 Pod 的地址。APISIX 可以监听这些资源,直接将流量路由到动态变化的 Pod 地址,而不使用 Service 虚拟 IP 或集群 DNS 名称。
该集成支持单个 Kubernetes 集群或多个命名集群。APISIX 使用 ServiceAccount Bearer 令牌向每个 Kubernetes API 进行身份认证,并向上游提供发现的地址。
前置条件
- APISIX 部署可以连接 Kubernetes API Server 和发现的 Pod 地址。
- Kubernetes ServiceAccount 令牌,通过
client.token直接提供或通过client.token_file文件提供。 - 对
endpoints资源具有get、list和watch权限。当watch_endpoint_slices为true时,还要对discovery.k8s.ioAPI Group 中的endpointslices资源授予相同权限。 - 启用 TLS 证书校验时,APISIX 可以访问包含 Kubernetes API Server CA 证书的 PEM 证书包。
授予 Kubernetes API 访问权限
以下资源清单会创建 apisix 命名空间并授予服务发现所需的权限。如果 APISIX 在其他命名空间中运行,请替换 Namespace、ServiceAccount 和 ClusterRoleBinding Subject 中的 apisix。
apiVersion: v1
kind: Namespace
metadata:
name: apisix
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: apisix-discovery
namespace: apisix
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: apisix-discovery
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch"]
- apiGroups: ["discovery.k8s.io"]
resources: ["endpointslices"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: apisix-discovery
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: apisix-discovery
subjects:
- kind: ServiceAccount
name: apisix-discovery
namespace: apisix
应用 RBAC 资源:
kubectl apply -f kubernetes-discovery-rbac.yaml
当 APISIX 在 Kubernetes 中运行并读取挂载的 ServiceAccount 令牌时,请在 APISIX Deployment 或 StatefulSet 中将 spec.template.spec.serviceAccountName 设置为 apisix-discovery。应用 RBAC 资源清单不会更改现有 Pod 的身份。更新 Pod Spec 后,请滚动更新工作负载。
配置单个 Kubernetes 集群
当 APISIX 在 Pod 中运行时,默认配置会从 Pod 环境读取 Kubernetes API 地址和挂载的 ServiceAccount 令牌:
discovery:
kubernetes: {}
在生产环境中,请显式启用证书校验。创建并挂载一个 PEM 证书包,其中同时包含 Kubernetes API CA 以及 APISIX 已信任的所有系统或自定义 CA。apisix.ssl.ssl_trusted_certificate 是全局配置,因此,如果仅使用 Kubernetes CA 替换现有证书包,可能会破坏其他 TLS 连接。请确保 API Server 主机名与其证书保持一致。
apisix:
ssl:
ssl_trusted_certificate: /usr/local/apisix/conf/trusted-ca-bundle.pem
discovery:
kubernetes:
service:
schema: https
host: ${KUBERNETES_SERVICE_HOST}
port: ${KUBERNETES_SERVICE_PORT}
ssl_verify: true
client:
token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
namespace_selector:
equal: default
watch_endpoint_slices: true
为保持兼容性,service.ssl_verify 默认为 false,即使 service.schema 为 https 也是如此。该设置会接受不受信任的 API Server 证书,不建议在生产环境中使用。请将其设置为 true,并通过组合后的信任证书包配置 apisix.ssl.ssl_trusted_certificate。
当 APISIX 在 Kubernetes 外部运行时,请显式设置 service.host 和 service.port。通过 client.token 或可读的 client.token_file 提供令牌;HTTPS API Server 要求令牌不能为空。
配置多个 Kubernetes 集群
使用数组配置多个集群。每个条目都需要一个唯一 id(由 1–64 个小写字母或数字组成)、显式 API Server 地址和客户端凭证。单集群的 Service 和 Client 字段默认值不会应用到数组条目。
apisix:
ssl:
ssl_trusted_certificate: /usr/local/apisix/conf/trusted-ca-bundle.pem
discovery:
kubernetes:
- id: prod
service:
schema: https
host: prod-api.example.com
port: "6443"
ssl_verify: true
client:
token_file: /usr/local/apisix/conf/prod-service-account.token
namespace_selector:
match:
- ^prod-
watch_endpoint_slices: true
- id: staging
service:
schema: https
host: staging-api.example.com
port: "6443"
ssl_verify: true
client:
token_file: /usr/local/apisix/conf/staging-service-account.token
namespace_selector:
equal: staging
watch_endpoint_slices: true
CA 证书包必须信任每个已配置的 API Server,并保留 APISIX 发起其他 HTTPS 连接时所需的根 CA。更改服务发现或信任配置后,请重新加载 APISIX。
部署示例服务
在 default 命名空间中部署 HTTPBin 工作负载和一个具有命名端口 http 的 Service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- name: httpbin
image: mccutchen/go-httpbin:v2.15.0
ports:
- name: http
containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
namespace: default
spec:
selector:
app: httpbin
ports:
- name: http
port: 80
targetPort: http
应用这些资源,并等待两个 Pod 均进入 Ready 状态:
kubectl apply -f httpbin.yaml
kubectl rollout status deployment/httpbin -n default
路由到发现的服务
对于单个集群,service_name 使用 namespace/service:port-name。对于多个集群,请添加集群 ID 前缀:cluster-id/namespace/service:port-name。如果 Kubernetes 资源定义了命名端口,请使用端口名称而不是端口号。
创建路由,通过 http 端口将请求发送到 default 命名空间中的 httpbin Service:
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "kubernetes-discovery-route",
"uri": "/anything",
"upstream": {
"type": "roundrobin",
"discovery_type": "kubernetes",
"service_name": "default/httpbin:http"
}
}'
对于多集群示例中的 prod 条目,请改用 prod/default/httpbin:http。
发送请求,验证 APISIX 可以解析就绪端点并代理请求:
curl -i "http://127.0.0.1:9080/anything"
收到 HTTP/1.1 200 OK 响应即表示路由已访问发现的端点。
验证服务发现与 TLS 信任
如果已启用 Control API,请检查服务发现缓存:
curl "http://127.0.0.1:9090/v1/discovery/kubernetes/dump"
确认输出包含预期的命名空间、服务、端口名称和就绪端点地址。使用多个集群时,还要确认输出中包含预期的集群 id。
要验证受信任证书的行为:
- 配置
service.ssl_verify: true和正确的 CA 证书包,重新加载 APISIX,并确认服务发现转储中出现预期的端点。 - 在隔离的测试部署中,将
apisix.ssl.ssl_trusted_certificate指向不信任 API Server 的证书包,或使用与证书不匹配的主机。重新加载 APISIX,确认错误日志报告证书校验失败,并且没有收到新的端点更新。重新加载期间,先前发现的条目可能仍保留在共享内存中,因此不要将旧条目仍然存在视为新 TLS 连接成功的证据。 - 恢复正确的 CA 证书包和主机,重新加载 APISIX,并确认服务发现恢复正常。
不要将 ssl_verify: false 作为生产环境信任失败的修复方法。请修复 CA 证书包、证书链、API Server 主机名或系统时间。
后续步骤
Kubernetes 服务发现支持命名空间选择器、Kubernetes Label Selector 表达式、可配置的端点权重、共享内存大小,以及 Endpoints 或 EndpointSlices。有关完整的服务发现状态和故障排查端点,请参阅 Control API 参考。