Apache APISIX 是 Apache 软件基金会下的顶级项目,由 API7.ai 开发并捐赠。它是一个具有动态、实时、高性能等特点的云原生 API 网关。可以使用 APISIX 网关作为所有业务的流量入口,它提供了动态路由、动态上游、动态证书、A/B 测试、灰度发布(金丝雀发布)、蓝绿部署、限速、防攻击、收集指标、监控报警、可观测、服务治理等功能。
本教程基于Yaml文件在K8S集群中快速安装 Apache APISIX,并且通过管理 API 和APISIX Dashboard来验证是否安装成功。
一、基本概念
APISIX 主要分为两个部分:
- APISIX 核心:包括 Lua 插件、多语言插件运行时(Plugin Runner)、Wasm 插件运行时等;
- 功能丰富的各种内置插件:包括可观测性、安全、流量控制等。
APISIX 在其核心中,提供了路由匹配、负载均衡、服务发现、API 管理等重要功能,以及配置管理等基础性模块。除此之外,APISIX 插件运行时也包含其中,提供原生 Lua 插件的运行框架和多语言插件的运行框架,以及实验性的 Wasm 插件运行时等。APISIX 多语言插件运行时提供多种开发语言的支持,比如 Golang、Java、Python、JS 等。
APISIX 目前也内置了各类插件,覆盖了 API 网关的各种领域,如认证鉴权、安全、可观测性、流量管理、多协议接入等。当前 APISIX 内置的插件使用原生 Lua 实现,关于各个插件的介绍与使用方式,可以查看相关插件文档。
Apache APISIX 使用 routes 来提供灵活的网关管理功能,在一个请求中,routes 包含了访问路径和上游目标等信息。
Route(也称之为路由)是访问上游目标的路径,在 Apache APISIX 中,Route 首先通过预定的规则来匹配客户端请求,然后加载和执行相应的插件,最后将请求转发至特定的 Upstream。
在 APISIX 中,一个最简单的 Route 仅由匹配路径和 Upstream 地址两个信息组成。
Upstream(也称之为上游)是一组具备相同功能的节点集合,它是对虚拟主机的抽象。Upstream 可以通过预先配置的规则对多个服务节点进行负载均衡。
二、APISIX部署方式
1、Helm Chart 部署
通过 Helm 包管理器快速部署 APISIX,适合需要标准化配置的场景。
- 步骤:添加 Helm 仓库、安装 APISIX 及 Dashboard、配置端口转发。
- 优势:简化依赖管理,支持一键安装,适合快速验证和轻量级环境。
2、YAML 文件手动部署
通过直接应用 Kubernetes 资源声明文件(YAML)部署,适合需要高度自定义的场景。
- 步骤:克隆仓库、应用 etcd.yaml、apisix.yaml、apisix-dashboard.yaml 等文件,配置持久化存储。
- 优势:灵活控制组件配置,便于集成自定义插件或调整资源分配。
3、Stand-alone 模式
独立运行模式,无需依赖 etcd,配置通过本地文件热加载。
- 适用场景:K8s 声明式配置或需要与 Consul 等配置中心集成。
- 限制:不支持 Admin API,仅通过 apisix.yaml 文件管理路由规则。
4、Docker Compose 部署
适用于本地开发或测试环境,通过 Docker 容器快速启动 APISIX 和 etcd。
特点:依赖外部 etcd 集群,需配置 docker-compose.yaml 和 config.yaml。
三、基于YAML文件在K8S中的部署流程
1、环境准备
在正式安装部署前,我们要准备好K8S集群并确保网络通畅。可以使用kubeadm、minikube、kubeasz、sealos等工具快速部署K8S集群。
2、部署etcd集群
etcd 是 APISIX 的配置中心,需通过 StatefulSet 部署并配置持久化存储
apiVersion: v1
kind: Namespace
metadata:
name: apisix
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: apisix-etcd
namespace: apisix
labels:
app.kubernetes.io/instance: apisix-etcd
app.kubernetes.io/name: apisix-etcd
spec:
podManagementPolicy: Parallel
replicas: 3
serviceName: apisix-etcd-headless
selector:
matchLabels:
app.kubernetes.io/instance: apisix-etcd
app.kubernetes.io/name: apisix-etcd
template:
metadata:
labels:
app.kubernetes.io/instance: apisix-etcd
app.kubernetes.io/name: apisix-etcd
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/instance: apisix-etcd
app.kubernetes.io/name: apisix-etcd
topologyKey: kubernetes.io/hostname
weight: 1
initContainers:
- name: init-permissions
image: busybox:1.32
command: ["sh", "-c", "chown -R 1001:1001 /bitnami/etcd && chmod -R 777 /bitnami/etcd"]
volumeMounts:
- name: data
mountPath: /bitnami/etcd
containers:
- name: apisix-etcd
image: etcd:3.5.14-amd64
imagePullPolicy: IfNotPresent
ports:
- containerPort: 2379
name: client
protocol: TCP
- containerPort: 2380
name: peer
protocol: TCP
env:
- name: BITNAMI_DEBUG
value: 'false'
- name: MY_POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: MY_POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: MY_STS_NAME
value: apisix-etcd
- name: ETCDCTL_API
value: '3'
- name: ETCD_ON_K8S
value: 'yes'
- name: ETCD_START_FROM_SNAPSHOT
value: 'no'
- name: ETCD_DISASTER_RECOVERY
value: 'no'
- name: ETCD_NAME
value: $(MY_POD_NAME)
- name: ETCD_DATA_DIR
value: /bitnami/etcd/data
- name: ETCD_LOG_LEVEL
value: info
- name: ALLOW_NONE_AUTHENTICATION
value: 'yes'
- name: ETCD_ADVERTISE_CLIENT_URLS
value: http://$(MY_POD_NAME).apisix-etcd-headless.apisix.svc.cluster.local:2379
- name: ETCD_LISTEN_CLIENT_URLS
value: http://0.0.0.0:2379
- name: ETCD_INITIAL_ADVERTISE_PEER_URLS
value: http://$(MY_POD_NAME).apisix-etcd-headless.apisix.svc.cluster.local:2380
- name: ETCD_LISTEN_PEER_URLS
value: http://0.0.0.0:2380
- name: ETCD_INITIAL_CLUSTER_TOKEN
value: apisix-etcd-cluster-k8s
- name: ETCD_INITIAL_CLUSTER_STATE
value: new
- name: ETCD_INITIAL_CLUSTER
value: apisix-etcd-0=http://apisix-etcd-0.apisix-etcd-headless.apisix.svc.cluster.local:2380,apisix-etcd-1=http://apisix-etcd-1.apisix-etcd-headless.apisix.svc.cluster.local:2380,apisix-etcd-2=http://apisix-etcd-2.apisix-etcd-headless.apisix.svc.cluster.local:2380
- name: ETCD_CLUSTER_DOMAIN
value: apisix-etcd-headless.apisix.svc.cluster.local
volumeMounts:
- name: data
mountPath: /bitnami/etcd
lifecycle:
preStop:
exec:
command:
- /opt/bitnami/scripts/etcd/prestop.sh
livenessProbe:
exec:
command:
- /opt/bitnami/scripts/etcd/healthcheck.sh
initialDelaySeconds: 60
timeoutSeconds: 5
periodSeconds: 30
successThreshold: 1
failureThreshold: 5
readinessProbe:
exec:
command:
- /opt/bitnami/scripts/etcd/healthcheck.sh
initialDelaySeconds: 60
timeoutSeconds: 5
periodSeconds: 10
successThreshold: 1
failureThreshold: 5
securityContext:
fsGroup: 1001
volumeClaimTemplates:
- kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: data
creationTimestamp: null
spec:
accessModes:
- ReadWriteOnce
storageClassName: apisix-etcd
resources:
requests:
storage: 5Gi
volumeMode: Filesystem
---
apiVersion: v1
kind: Service
metadata:
name: apisix-etcd-headless
namespace: apisix
labels:
app.kubernetes.io/instance: apisix-etcd
app.kubernetes.io/name: apisix-etcd
spec:
ports:
- name: client
port: 2379
protocol: TCP
targetPort: 2379
- name: peer
port: 2380
protocol: TCP
targetPort: 2380
clusterIP: None
selector:
app.kubernetes.io/instance: apisix-etcd
app.kubernetes.io/name: apisix-etcd
publishNotReadyAddresses: true
---
apiVersion: v1
kind: Service
metadata:
name: apisix-etcd
namespace: apisix
labels:
app.kubernetes.io/instance: apisix-etcd
app.kubernetes.io/name: apisix-etcd
spec:
ports:
- name: client
port: 2379
protocol: TCP
targetPort: 2379
- name: peer
port: 2380
protocol: TCP
targetPort: 2380
selector:
app.kubernetes.io/instance: apisix-etcd
app.kubernetes.io/name: apisix-etcd
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: apisix-etcd-pv-0
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: apisix-etcd
hostPath:
path: /data/apisix-etcd-pv-0
type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: apisix-etcd-pv-1
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: apisix-etcd
hostPath:
path: /data/apisix-etcd-pv-1
type: DirectoryOrCreate
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: apisix-etcd-pv-2
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: apisix-etcd
hostPath:
path: /data/apisix-etcd-pv-2
type: DirectoryOrCreate
3、部署APISIX
kind: Deployment
apiVersion: apps/v1
metadata:
name: apisix
namespace: apisix
labels:
app.kubernetes.io/instance: apisix
app.kubernetes.io/name: apisix
app.kubernetes.io/version: 2.10.0
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/instance: apisix
app.kubernetes.io/name: apisix
template:
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/instance: apisix
app.kubernetes.io/name: apisix
spec:
volumes:
- name: apisix-config
configMap:
name: apisix
defaultMode: 420
initContainers:
- name: wait-etcd
image: busybox:1.32
command:
- sh
- '-c'
- >-
until nc -z apisix-etcd.apisix.svc.cluster.local 2379; do echo
waiting for etcd `date`; sleep 2; done;
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
containers:
- name: apisix
image: apisix:3.7.0-debian-0820
ports:
- name: http
containerPort: 9080
protocol: TCP
- name: tls
containerPort: 9443
protocol: TCP
- name: admin
containerPort: 9180
protocol: TCP
resources: {}
volumeMounts:
- name: apisix-config
mountPath: /usr/local/apisix/conf/config.yaml
subPath: config.yaml
readinessProbe:
tcpSocket:
port: 9080
initialDelaySeconds: 10
timeoutSeconds: 1
periodSeconds: 10
successThreshold: 1
failureThreshold: 6
lifecycle:
preStop:
exec:
command:
- /bin/sh
- '-c'
- sleep 30
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
securityContext: {}
schedulerName: default-scheduler
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
---
kind: ConfigMap
apiVersion: v1
metadata:
name: apisix
namespace: apisix
data:
config.yaml: >-
apisix:
node_listen: 9080 # APISIX listening port
enable_ipv6: false
enable_control: true
control:
ip: "0.0.0.0"
port: 9092
deployment:
admin:
allow_admin: # https://nginx.org/en/docs/http/ngx_http_access_module.html#allow
- 0.0.0.0/0 # We need to restrict ip access rules for security. 0.0.0.0/0 is for test.
admin_key:
- name: "admin"
key: xxx
role: admin # admin: manage all configuration data
- name: "viewer"
key: xxx
role: viewer
etcd:
host: # it's possible to define multiple etcd hosts addresses of the same etcd cluster.
- "http://apisix-etcd.apisix.svc.cluster.local:2379"
prefix: "/apisix" # apisix configurations prefix
timeout: 30 # 30 seconds
plugins: # plugin list
- api-breaker
- authz-keycloak
- basic-auth
- batch-requests
- consumer-restriction
- cors
- echo
- fault-injection
- grpc-transcode
- hmac-auth
- http-logger
- ip-restriction
- ua-restriction
- jwt-auth
- kafka-logger
- key-auth
- limit-conn
- limit-count
- limit-req
- log-rotate
- node-status
- openid-connect
- authz-casbin
- prometheus
- proxy-cache
- proxy-mirror
- proxy-rewrite
- redirect
- referer-restriction
- request-id
- request-validation
- response-rewrite
- serverless-post-function
- serverless-pre-function
- sls-logger
- syslog
- tcp-logger
- udp-logger
- uri-blocker
- wolf-rbac
- zipkin
- server-info
- traffic-split
- gzip
- real-ip
stream_plugins:
- mqtt-proxy
- ip-restriction
- limit-conn
plugin_attr:
server-info:
report_interval: 60
report_ttl: 3600
log-rotate:
interval: 3600 # rotate interval (unit: second)
max_kept: 168 # max number of log files will be kept
max_size: -1 # max size of log files will be kept
enable_compression: false # enable log file compression(gzip) or not, default false
---
kind: Service
apiVersion: v1
metadata:
name: apisix-admin
namespace: apisix
labels:
app.kubernetes.io/instance: apisix
app.kubernetes.io/name: apisix
spec:
ports:
- name: apisix-admin
protocol: TCP
port: 9180
targetPort: 9180
selector:
app.kubernetes.io/instance: apisix
app.kubernetes.io/name: apisix
type: ClusterIP
---
kind: Service
apiVersion: v1
metadata:
name: apisix-gateway
namespace: apisix
labels:
app.kubernetes.io/instance: apisix
app.kubernetes.io/name: apisix
spec:
ports:
- name: apisix-gateway-http
protocol: TCP
port: 80
targetPort: 9080
- name: apisix-gateway-https
protocol: TCP
port: 443
targetPort: 9443
selector:
app.kubernetes.io/instance: apisix
app.kubernetes.io/name: apisix
type: ClusterIP
sessionAffinity: None
4、部署APISIX Dashboard
kind: Deployment
apiVersion: apps/v1
metadata:
name: apisix-dashboard
namespace: apisix
labels:
app.kubernetes.io/instance: apisix-dashboard
app.kubernetes.io/name: apisix-dashboard
app.kubernetes.io/version: 2.9.0
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/instance: apisix-dashboard
app.kubernetes.io/name: apisix-dashboard
template:
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/instance: apisix-dashboard
app.kubernetes.io/name: apisix-dashboard
spec:
volumes:
- name: apisix-dashboard-config
configMap:
name: apisix-dashboard
defaultMode: 420
containers:
- name: apisix-dashboard
image: apisix-dashboard:3.0.0-alpine
ports:
- name: http
containerPort: 9000
protocol: TCP
resources: {}
volumeMounts:
- name: apisix-dashboard-config
mountPath: /usr/local/apisix-dashboard/conf/conf.yaml
subPath: conf.yaml
livenessProbe:
httpGet:
path: /ping
port: http
scheme: HTTP
timeoutSeconds: 1
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
readinessProbe:
httpGet:
path: /ping
port: http
scheme: HTTP
timeoutSeconds: 1
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
securityContext: {}
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
serviceAccountName: apisix-dashboard
serviceAccount: apisix-dashboard
securityContext: {}
schedulerName: default-scheduler
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
---
kind: Service
apiVersion: v1
metadata:
name: apisix-dashboard
namespace: apisix
labels:
app.kubernetes.io/instance: apisix-dashboard
app.kubernetes.io/name: apisix-dashboard
app.kubernetes.io/version: 2.9.0
spec:
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9000
selector:
app.kubernetes.io/instance: apisix-dashboard
app.kubernetes.io/name: apisix-dashboard
type: ClusterIP
---
kind: ConfigMap
apiVersion: v1
metadata:
name: apisix-dashboard
namespace: apisix
labels:
app.kubernetes.io/instance: apisix-dashboard
app.kubernetes.io/name: apisix-dashboard
app.kubernetes.io/version: 2.9.0
data:
conf.yaml: |-
conf:
listen:
host: 0.0.0.0
port: 9000
etcd:
endpoints:
- http://apisix-etcd.apisix.svc.cluster.local:2379
log:
error_log:
level: warn
file_path: /dev/stderr
access_log:
file_path: /dev/stdout
authentication:
secert: secert
expire_time: 3600
users:
- username: admin
password: 6p#0*urwP1s3X1Ey
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: apisix-dashboard
namespace: apisix
5、配置APISIX与APISIX Dashboard Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: apisix-ingress
namespace: apisix
spec:
rules:
- host: apisix-dashboard.ctyun.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: apisix-dashboard
port:
number: 80
- host: apisix-gataway.ctyun.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: apisix-gateway
port:
number: 80
tls:
- hosts:
- apisix-dashboard.ctyun.cn
secretName: apisix-dashboard
验证
你可以创建一个路由,将客户端的请求转发至 httpbin.org(这个网站能测试 HTTP 请求和响应的各种信息)。
通过下面的命令,你将创建一个路由,把请求http://127.0.0.1:9080/ip
转发至 httpbin.org/ip:
curl -i "http://127.0.0.1:9180/apisix/admin/routes" -X PUT -d '
{
"id": "getting-started-ip",
"uri": "/ip",
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'
<button class="copyButton_V-PD clean-btn" type="button" aria-label="Copy code to clipboard">Copy</button>如果配置成功,将会返回 HTTP/1.1 201 Created
。
验证
curl "http://127.0.0.1:9080/ip"
<button class="copyButton_V-PD clean-btn" type="button" aria-label="Copy code to clipboard">Copy</button>你将会得到类似下面的返回:
{
"origin": "183.94.122.205"
}
APISIX Dashboard登录