在 Kubernetes 上部署和运维网关
api7/aisix Helm Chart 用于在 Kubernetes 中部署、暴露和扩缩 AISIX 网关。无论网关从 AISIX Enterprise、AISIX Cloud 还是 AISIX OSS 资源文件接收资源,监听器、Service、自动扩缩容、共享 Redis、中断处理、排空和应用设置的工作方式都相同。本页先介绍连接控制面的安装流程,再介绍这些共通的 Kubernetes 运维操作。
连接 AISIX Enterprise 或 AISIX Cloud 的网关需要数据面管理器端点,以及为目标环境签发的网 关证书包。连接后,网关会从控制面接收模型、调用方 API Key 和策略。对于 AISIX OSS,请先使用资源文件部署网关,再从本页的暴露网关继续。
前提条件
- 一个 Kubernetes 集群,已配置
kubectl访问权限并安装 Helm 3。 - 对于 OpenShift 或 OKD,需要 cURL,以及能够在网关项目中管理工作负载、Service、Secret 和 Route、读取 Pod 日志并运行
oc exec的oc会话。 - 对于 OpenShift 或 OKD Route 示例,需要应用域名和入口 CA 证书,或有权读取集群 Ingress 配置及
openshift-config-managed中的default-ingress-certConfigMap。集群管理员也可以提供域名和 CA。 - 可以访问一个能够签发网关证书的 AISIX Enterprise 或 AISIX Cloud 环境。
- 集群可以通过网络访问 AISIX Enterprise 或 AISIX Cloud 数据面管理器端点。对于 AISIX Enterprise,请先完成部署 AISIX Enterprise 控制面。
部署网关
在控制台中打开目标环境的 数据面 视图并签发网关证书。Kubernetes (Helm) 标签页会提供下文使用的数据面管理器端点和证书包。本示例还将初始部署固定为一个副本。私钥只显示一次。
在 OpenShift 或 OKD 上,使用 oc project aisix-dp 或 oc new-project aisix-dp 选择或创建 aisix-dp 项目。本流程中请用 oc 代替 kubectl,并省略下方的 kubectl create namespace 命令。
将证书包存储在 Secret 中,避免私钥出现在 values 文件中:
kubectl create namespace aisix-dp
kubectl -n aisix-dp create secret generic aisix-gateway-certificate \
--from-file=cert.pem=./cert.pem \
--from-file=key.pem=./key.pem \
--from-file=ca.pem=./ca.pem
使用同一视图中的数据面管理器端点安装 Chart。Dev 文档会将 Chart 的已发布网关镜像替换为 dev 镜像:
helm repo add api7 https://charts.api7.ai
helm repo update
helm install aisix-dp api7/aisix --namespace aisix-dp \
--set image.repository=ghcr.io/api7/aisix \
--set image.tag=dev \
--set controlPlane.baseURL=https://dp-manager.example.com:7944 \
--set controlPlane.certificate.existingSecret=aisix-gateway-certificate \
--set replicaCount=1
网关首次上报心跳后,会出现在环境的 数据面 视图中。Chart 默认为两个副本,但此初始命令只启动一个副本,因为在配置共享 Redis 之前,限流计数器使用每个副本各自的内存。控制台 Helm 代码片段省略了 replicaCount,因此原样安装会启动两个副本。如上所示,请在配置 Redis 前添加 --set replicaCount=1。增加副本数或启用自动扩缩容器前,请先在副本间共享限流计数器。
每个副本会注册为独立实例,并共享同一个证书。
查看 Chart 接受的所有值:
helm show values api7/aisix
Chart 源码发布在 api7/api7-helm-chart 仓库中。
在 OpenShift 或 OKD 上,请从在 OpenShift 上运行继续,不要使用下方的通用暴露方式。
暴露网关
Chart 默认为代理创建 ClusterIP 类型的 Service。如需通过云负载均衡器发布:
service:
type: LoadBalancer
port: 80
# 保留客户端源 IP,按模型配置的 IP 允许列表会使用该地址进行匹配。
externalTrafficPolicy: Local
如果负载均衡器改为发送 PROXY protocol 头,请把网关看到的 TCP 对端地址加入 config.proxy.real_ip.trusted_proxies。在默认的 externalTrafficPolicy: Cluster 下,该对端是节点地址。参见客户端 IP 解析。
Chart 默认只给网关一个明文 HTTP 代理监听器:它在容器内绑定 containerPorts.proxy(端口 3000),由 Service 以 service.port 发布。Service 可以暴露端口 80 或 443,无需让进程绑定特权容器端口。
同时提供 HTTPS 和明文 HTTP
配置 listeners 即可同时提供多个代理端口,每个端口有各自的 TLS:
listeners:
- name: https # 端口名称,容器端口和 Service 端口共用。
containerPort: 3443
servicePort: 443
# nodePort: 30443 # 可选;仅适用于非 ClusterIP 类型的 Service。
tls:
secretName: aisix-proxy-tls
- name: http
containerPort: 3000
servicePort: 80
非空的 listeners 就是代理监听器的完整集合,并取代默认的那一个监听器。此时没有任何东西绑定 containerPorts.proxy,service.port 和 service.nodePort 也不会被读取,因为每个条目都带有自己的配置。代理 Service 仍然只有一个,它为每个条目发布一个端口,并按名称指向该条目的容器端口。
每个监听器提供相同的路由,包括 /livez 和 /readyz,因此 startup、readiness 和 liveness 探针都指向第一个条目——当该条目终止 TLS 时探针使用 HTTPS,且 kubelet 不会校验证书。Chart 会把这组监听器以 proxy.listeners 写入网关的配置文件。它仍然会写入 proxy.addr,网关会忽略该值并记录一行 INFO 日志,这行日志无需处理。此功能需要支持 proxy.listeners 的网关镜像。
这些 values 背后的网关侧规则,包括明文监听器为什么只能绑定到可信网络接口,参阅同时提供 HTTPS 和 HTTP。
网关从文件读取 TLS 证书材料,因此每个启用 TLS 的监听器都需要各自的 kubernetes.io/tls Secret,键名为 tls.crt 和 tls.key。Chart 会把它以只读方式挂载到 /etc/aisix/tls/<name>。使用你已有的证书和私钥创建:
kubectl -n aisix-dp create secret tls aisix-proxy-tls \
--cert=./tls.crt --key=./tls.key
或者由 cert-manager 签发该 Secret 并自动续期:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: aisix-proxy-tls
namespace: aisix-dp
spec:
secretName: aisix-proxy-tls
dnsNames:
- gateway.example.com
issuerRef:
name: letsencrypt
kind: ClusterIssuer
轮换后的证书会以挂载点中文件变更的形式到达网关。请使用 Chart 安装后提示中的 Deployment 名称重启 Pod,以使其生效。包含 aisix 的 Release 名通常会原样使用;名称覆盖可能会改变结果:
kubectl rollout restart deployment/<deployment-name> -n <namespace>
绑定特权容器端口
只有当网关必须直接监听某个低于 1024 的端口时,才在容器内绑定该端口。发布的镜像以非 root 用户 UID 10001 运行,网关二进制文件具有生效的 CAP_NET_BIND_SERVICE 文件能力:
containerPorts:
proxy: 80
配置了 listeners 时,请把特权端口写在应当绑定它的那个条目的 containerPort 上,此时 containerPorts.proxy 不会被读取。
如果你自定义渲染后的 Pod 并丢弃所有 capability,请为 AISIX 容器重新添加 NET_BIND_SERVICE:
spec:
containers:
- name: aisix
securityContext:
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"]
Kubernetes Restricted Pod Security Standard 允许此 capability。由于二进制文件的文件 capability 已设置 effective bit,如果运行时阻止授予该 capability,容器可能会因 exec: Operation not permitted 而失败。
只有当网关必须直接绑定节点且集群策略允许时,才使用 hostNetwork 或 hostPort。这些选项会引入节点端口冲突并降低网络隔离;Baseline 和 Restricted Pod Security Standard 也不允许使用它们。
完整的网络暴露和凭证模型请参阅网络与安全。
在 OpenShift 上运行
以下平台步骤适用于已获得环境数据面管理器端点和网关证书、连接 AISIX Enterprise 或 AISIX Cloud 的网关。AISIX Cloud 的接入和连接信息由 API7 协调,网关仍由客户自行运维。
Chart 可在默认的 restricted-v2 安全上下文约束(SCC)下运行,无需自定义 SCC 或修改 ServiceAccount。它不设置 runAsUser、runAsGroup 和 fsGroup,由项目分配这些值。容器使用只读根文件系统、禁止提权,并丢弃除 NET_BIND_SERVICE 之外的所有 capability;运行期可写路径使用 emptyDir 卷。
不要向网关 ServiceAccount 授予 anyuid。如果集群管理员因组织策略或自定义卷分配了固定 ID,请将 podSecurityContext.runAsUser、podSecurityContext.runAsGroup 和 podSecurityContext.fsGroup 设为所分配的值。除非镜像 UID 10001 位于项目允许的范围内,否则不要复用它。
为默认的明文 HTTP proxy Service 端口创建 edge Route。如果集群管理员提供了应用域名,请将 ROUTE_DOMAIN 设为该域名,并省略下方第一条 export:
export ROUTE_DOMAIN="$(oc get ingresses.config.openshift.io cluster \
-o jsonpath='{.spec.domain}')"
export GATEWAY_ROUTE_HOST="aisix-gateway.$ROUTE_DOMAIN"
oc create route edge aisix-dp \
--service=aisix-dp \
--port=proxy \
--hostname="$GATEWAY_ROUTE_HOST" \
--namespace aisix-dp
该命令使用默认 Release 名和 proxy Service 端口。如果 Release 覆盖了名称或使用自定义监听器,请运行 oc get service -n aisix-dp,并替换为实际 Service 名和命名端口。
默认应用域名通常使用由集群内部入口 CA 签发的通配符证书。如果工作站尚不信任该 CA,请导出它供验证请求使用:
oc get configmap default-ingress-cert -n openshift-config-managed \
-o jsonpath='{.data.ca-bundle\.crt}' > ingress-ca.crt
export CURL_CA_BUNDLE="$PWD/ingress-ca.crt"
如果管理员提供了 CA 文件,请将其保存为 ingress-ca.crt,并只运行 CURL_CA_BUNDLE 的 export 命令。如果 Route 或默认 Ingress Controller 使用工作站已信任的证书,请跳过该 export。
等待 Deployment 就绪,然后确认分配的 SCC、UID、就绪状态和控制面心跳:
oc rollout status deployment/aisix-dp -n aisix-dp --timeout=5m
export GATEWAY_POD="$(oc get pod -n aisix-dp \
-l 'app.kubernetes.io/instance=aisix-dp,app.kubernetes.io/component=gateway' \
-o jsonpath='{.items[0].metadata.name}')"
oc get pod -n aisix-dp "$GATEWAY_POD" \
-o jsonpath='{.metadata.annotations.openshift\.io/scc}{"\n"}'
oc exec -n aisix-dp "$GATEWAY_POD" -- id -u
curl -fsS "https://$GATEWAY_ROUTE_HOST/readyz"
第一行输出应为 restricted-v2,第二行显示进程实际使用的 UID,就绪请求应返回 ok。确认该 UID 位于项目分配的范围内,并且托管控制面报告网关健康且心跳正常更新。
在 OKD 上运行
OpenShift 步骤同样适用于 OKD,无需修改。AISIX Cloud 客户仍需通过 API7 协调托管控制面的接入和连接信息。
在副本间共享限流计数器
限流计数器默认存储在每个网关自己的内存中,因此 N 个副本实际会执行每项已配置请求、Token 和并发限制的 N 倍。在运行多个副本前——包括自动扩缩容器新增的任何副本——请让所有副本指向同一个 Redis:
rateLimit:
backend: redis
redis:
url: redis://redis.default.svc:6379
当连接 URL 包含密码时,请改用 rateLimit.redis.existingSecret。若要与 URL 分开提供 Redis 用户名和密码,请通过 configSecrets 从 Secret 读取,详见设置其他网关配置。共享 Redis 连接的其他设置,例如 mode、nodes 或 timeout_secs,写在 config.ratelimit.redis 下。
所有副本都指向同一个 Redis 部署后,再提高 replicaCount 或启用下面的一种自动扩缩容方式。如果部署不使用请求、Token 或并发限制,也可以有意识地接受每个副本独立的内存后端。
基于 CPU 或内存扩缩容
autoscaling 会为网关 Deployment 创建 HorizontalPodAutoscaler:
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 20
targetCPUUtilizationPercentage: 70
目标值是 Pod 资源 requests 的百分比,因此 Chart 默认设置 CPU request。它特意不设置 CPU limit:限流会增加代理的长尾延迟,并抑制自动扩缩容器读取的信号。基于 CPU 扩缩容要求集群中安装 metrics-server。
在 Linux 上,proxy.workers 默认使用网关进程可用的 CPU 并行度。Kubernetes CPU request 不会限制该值,但 CPU limit 会限制。如果每个副本需要稳定的 Worker 数量,由于 Chart 不设置 CPU limit,请显式设置 config.proxy.workers,并确保该值不超过为副本规划的 CPU 容量。有关 Worker 配置和容量规划注意事项,请参阅每核一线程 Worker。
启用自动扩缩容后,Deployment 会省略 spec.replicas,避免后续 helm upgrade 重置自动扩缩容器选择的副本数。此后会忽略 replicaCount 值。
所有 behavior 策略都会原样传递,例如让缩容比 Kubernetes 默认行为更平缓:
autoscaling:
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 60
对于 Pods、Object 或 External 指标(例如通过 Prometheus adapter 暴露的序列),请使用 autoscaling.extraMetrics。
使用 KEDA 基于请求负载扩缩容
CPU 是负载的间接指标。如需改为根据网关自身流量扩缩容,请使用 KEDA,并针对网关指标执行 Prometheus 查询。
启用示例前,请准备以下集群组件:
- 安装 KEDA,包括
ScaledObjectCRD 和控制器。 - 提供可查询网关指标的 Prometheus 服务器。
- 如果需要由 Chart 创建下文所示的抓取配置,请安装 Prometheus Operator 或其他能够消费
ServiceMonitor对象的控制器。仅安装 CRD 会让 Helm 能够创建对象,但不会有组件将其转换为抓取配置。当 Prometheus 实例按标签选择 ServiceMonitor 时,请设置metrics.serviceMonitor.labels。如果 Prometheus 通过其他方式发现指标 Service,请将metrics.serviceMonitor.enabled保持为false,并省略该配置块。
确认所启用值依赖的 CRD 已经存在:
kubectl get crd scaledobjects.keda.sh
# 仅当 metrics.serviceMonitor.enabled 为 true 时需要。
kubectl get crd servicemonitors.monitoring.coreos.com
这些前提条件就绪后再配置 Chart:
metrics:
serviceMonitor:
enabled: true
keda:
enabled: true
minReplicas: 2
maxReplicas: 20
pollingInterval: 15
cooldownPeriod: 300
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring.svc:9090
query: sum(rate(aisix_llm_requests_total[2m]))
threshold: "100"
aisix_llm_requests_total 统计模型推理请求,例如 /v1/chat/completions,但不包括 MCP 或 A2A 调用。如果这类流量才是扩缩容依据,请使用 aisix_proxy_requests_total。
流式请求在流结束时计数,而不是在开始时。因此在一批长流进行期间,基于这两个计数器的 rate() 会比实际到达的负载滞后大约一个流的时长;稳态速率不变。选择 pollingInterval 和查询窗口时请考虑这一延迟。1.5.0 及更早版本的网关在响应开始时对流式请求计数。
autoscaling 和 keda 互斥。同时启用两者会使 Helm 渲染失败,避免两个控制器同时写入 spec.replicas。
扩缩容事件期间的行为
自动扩缩容器新增的副本在能够提供服务前不会接收流量。连接控制面的网关会先从控制面获取配置;在配置可用之前,网关不会绑定代理监听器,因此 Chart 指向该监听器的所有探针只会得到被拒绝的连接。配置为从 etcd 加载动态资源的 AISIX OSS 网关也 会经历相同的等待。
使用资源文件的 AISIX OSS 网关在进程启动时同步加载并验证文件。文件有效时,配置会在代理监听器绑定前就绪;文件无效时,进程会输出验证报告并退出。Kubernetes 因进程失败而重启容器,不会等到启动探针预算耗尽。
Chart 的 startupProbe 覆盖连接控制面或 etcd 的等待。在启动探针成功前,Kubernetes 不执行就绪和存活探针,使 Pod 在获取并应用初始配置期间保持在 Service 端点之外。启动探针预算为 periodSeconds x failureThreshold,应覆盖等待配置来源的时间。如果来源持续不可用并超过预算,Kubernetes 会重启容器;反复重启会表现为 CrashLoopBackOff。有关就绪契约和预算设置,请参阅启动与第一个配置。
副本缩容时,Kubernetes 会同时开始将其从 Service 端点移除并终止 Pod。以下两个 Chart 配置会在此过程中保护进行中的请求。
preStopSleepSeconds 在容器收到 SIGTERM 前先暂停一段时间,让端点移除在网关开始关闭之前传播到每个节点。它覆盖的是监听 Kubernetes API 的负载均衡器;通过轮询健康检查感知的负载均衡器在整个暂停期间看到的仍是就绪的 Pod,由网关自身的排空窗口 shutdown.min_drain_secs 覆盖。
terminationGracePeriodSeconds 限定暂停、排空窗口及后续在途请求排空的总时长。启用快照持久化时,它还需要覆盖最多额外 5 秒的未完成缓存写入。网关对在途请求的排空没有自身期限;Kubernetes 默认的 30 秒会中断流式响应,因此 Chart 使用更长的值。
两者的默认值均为端点撤出和长请求留出时间;helm show values api7/aisix 会显示当前值。如果工作负载的流 式传输或 Realtime WebSocket 会话的持续时间超过暂停和排空窗口结束后剩余的预算,请提高 terminationGracePeriodSeconds。启用快照持久化时,还应为缓存写入排空留出 5 秒。
观察扩缩容决策及其依据的指标:
kubectl -n aisix-dp get hpa aisix-dp --watch
kubectl -n aisix-dp describe hpa aisix-dp
应对节点中断
PodDisruptionBudget 限制节点排空等主动驱逐,使配置数量的网关副本保持可用。下方示例优先将副本分布到不同可用区:
podDisruptionBudget:
enabled: true
minAvailable: 50%
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/name: aisix
ScheduleAnyway 是调度偏好,因此容量受限时副本仍可位于同一可用区。如果必须强制执行分布约束,请使用 DoNotSchedule,并为符合条件的可用区规划足够容量,避免 Pod 一直 Pending。请将选择器设为该网关 Release 实际使用的标签。
Chart 使用 emptyDir 卷挂载 /var/lib/aisix。同一 Pod 内的容器重启后该卷仍然存在,但 Pod 被替换时数据会丢失。连接控制面的替代 Pod 会从证书 Secret 重建身份并从控制面下载配置;替代的 AISIX OSS 网关则挂载并加载资源文件。请跨故障域保留多个副本,使现有副本可以在其他副本替换期间继续提供服务。
对于连接 AISIX Enterprise 或 AISIX Cloud 的网关,要在控制面不可用且 Pod 已被替换后从缓存配置恢复,需要同时以两种方式自定义工作负载:为每个副本提供独立的持久化状态目录,并将 config.managed.snapshot_cache_enabled 设置为 true。仅提供持久化存储不会启用缓存。完整的恢复与安全要求请参阅从缓存配置重启。
AISIX Enterprise 和 AISIX Cloud 的完整部署模式请参阅高可用。
设置其他网关配置
在两种网关模式中,Chart 都负责 Pod 及其启动配置。控制面负责已连接网关的动态资源,资源文件负责 AISIX OSS 网关的资源。网关从一个配置文件读取启动配置,该文件由 Chart 渲染到 ConfigMap 中并以只读方式挂载。config value 与该文件逐键对应,节名和键名与启动配置参考相同,并列出了每项设置的网关默认值。只需设置要修改的键:
config:
observability:
log_level: debug
upstream:
pool_max_idle_per_host: 32
proxy:
real_ip:
# 受信任可设置 X-Forwarded-For 或发送 PROXY protocol 头的代理。
trusted_proxies: ["10.0.0.0/8"]
recursive: true
设置为 null 的键不会写入文件,网关会使用自身的默认值。修改 config 后,helm upgrade 会滚动更新 Pod。运行 helm show values api7/aisix 可查看所有键。
部分键由 Chart 根据其他 value 设置,在 config 下会被拒绝。渲染会失败,并在报错中指明应改用的 value: