APISIX
usual
curl -H "Host: apisix.ingress.org" --request GET "http://192.168.0.127:32060/headers"
curl -s http://10.66.117.129:9180/apisix/admin/global_rules -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '{
"id": "1",
"plugins": {
"prometheus": {
"prefer_name": true
},
"cors": {}
}
}'
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/routes -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/plugins/list -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X DELETE
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
一、安装
1、chart 包
helm repo add apisix https://charts.apiseven.com
helm repo update
helm pull apisix/apisix-ingress-controller
helm install apisix apisix/apisix --create-namespace --namespace ingress-apisix
2、镜像
docker pull busybox:1.28
docker pull apache/apisix:3.9.1-debian
docker pull bitnami/etcd:3.5.10-debian-11-r2
docker pull apache/apisix-ingress-controller:1.8.2
docker pull apache/apisix-dashboard:3.0.1-alpine
docker save busybox:1.28 apache/apisix:3.9.1-debian bitnami/etcd:3.5.10-debian-11-r2 apache/apisix-ingress-controller:1.8.2 apache/apisix-dashboard:3.0.1-alpine |gzip > ingress-apisix_3.9.1_imgs.tar.gz
3、配置
vim apisix/values.yaml
image:
repository: easzlab.io.local:5000/apache/apisix
replicaCount: 1
nodeSelector:
nginx/ingress: ai
initContainer:
image: easzlab.io.local:5000/busybox
metrics:
serviceMonitor:
enabled: true
namespace: "ingress-apisix"
labels:
release: "ai-kube-prometheus-stack"
prometheus:
enabled: true
etcd:
enabled: true
dashboard:
enabled: true
ingress-controller:
enabled: true
config:
apisix:
adminAPIVersion: "v3"
nodeSelector:
kubernetes.io/hostname: 10.13.1.12
nodeSelector:
nginx/ingress: ai
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 16
memory: 32Gi
tolerations:
- key: "dedicated"
operator: "Equal"
value: "ingress"
effect: "NoExecute"
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx-ingress
topologyKey: kubernetes.io/hostname
vim apisix/charts/etcd/values.yaml
image:
registry: easzlab.io.local:5000
replicaCount: 1
nodeSelector:
nginx/ingress: ai
persistence:
enabled: false
vim apisix/charts/apisix-dashboard/values.yaml
replicaCount: 1
image:
repository: easzlab.io.local:5000/apache/apisix-dashboard
nodeSelector:
nginx/ingress: ai
vim apisix/charts/apisix-ingress-controller/values.yaml
replicaCount: 1
image:
repository: easzlab.io.local:5000/apache/apisix-ingress-controller
apisix:
serviceNamespace: ingress-apisix
adminAPIVersion: "v3"
initContainer:
image: easzlab.io.local:5000/busybox
nodeSelector:
nginx/ingress: ai
serviceMonitor:
enabled: false
namespace: "ingress-apisix"
labels:
release: "ai-kube-prometheus-stack"
修改Ingress class
vim charts/apisix-ingress-controller/values.yaml
.Values.config.kubernetes.ingressClass
ingressClass: "apisix" -> ingressClass: "nginx"
4、部署
helm install -n ingress-apisix apisix .
5、test
kubectl apply -f -<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-httpbin
labels:
app: test-httpbin
spec:
replicas: 1
selector:
matchLabels:
app: test-httpbin
template:
metadata:
labels:
app: test-httpbin
spec:
containers:
- name: nginx
image: easzlab.io.local:5000/kennethreitz/httpbin
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: test-httpbin-svc
labels:
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: test-httpbin
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-httpbin-ingress
spec:
ingressClassName: nginx
rules:
- host: apisix.ingress.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-httpbin-svc
port:
number: 80
EOF
二、Ingress
1、ingress
vim ingress-apisix.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: apisix-ingress
spec:
ingressClassName: apisix
rules:
- host: apisix.ingress.org
http:
paths:
- backend:
service:
name: nginx1-svc
port:
number: 80
path: /v1
pathType: Prefix
- backend:
service:
name: nginx2-svc
port:
number: 80
path: /v2
pathType: Prefix
- backend:
service:
name: httpbin
port:
number: 80
path: /get
pathType: Prefix
2、ApisixRoute
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: httpserver-route
spec:
http:
- name: rule1
match:
hosts:
- httpbin.example.com
paths:
- /*
backends:
- serviceName: httpbin
servicePort: 80
配置多个域名和路径
- name: rule1
match:
hosts:
- local.example.com
- local01.example.com
paths:
- /*
- /api
backends:
- serviceName: httpbin
servicePort: 80
regex
- name: httpserver-route
match:
hosts:
- local.example.com
paths:
- /api*
backends:
- serviceName: httpbin
servicePort: 8000
plugins:
- name: proxy-rewrite
enable: true
config:
regex_uri: ["^/api(/|$)(.*)", "/$2"]
gzip
plugins:
- name: gzip
enable: true
http to https
plugins:
- name: redirect
enable: true
config:
http_to_https: true
域名跳转
plugins:
- name: redirect
enable: true
config:
uri: "https://local01.example.com$request_uri"
rewrite路径跳转,/api/header -> /header
plugins:
- name: redirect
enable: true
config:
regex_uri: ["^/api(/|$)(.*)", "/$2"]
plugins:
- name: proxy-rewrite
enable: true
config:
regex_uri: ["^/api(/|$)(.*)", "/$2"]
/header -> /api/header
plugins:
- name: proxy-rewrite
enable: true
config:
uri: /api/$uri
基于用户名和密码认证
apiVersion: apisix.apache.org/v2
kind: ApisixConsumer
metadata:
name: httpserver-basicauth
spec:
authParameter:
basicAuth:
value:
username: admin
password: admin
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: httpserver-route
spec:
http:
- name: httpserver-route
match:
hosts:
- local.example.com
paths:
- /*
backends:
- serviceName: httpbin
servicePort: 8000
authentication:
enable: true
type: basicAuth
curl -i -uadmin:admin https://local.example.com/
三、instance
kubectl run httpbin --image kennethreitz/httpbin --port 80
kubectl expose pod httpbin --port 80
curl --location -H "Host: apisix.ingress.org" --request GET "http://192.168.0.127:32431/get?foo1=bar1&foo2=bar2"
example-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-1
labels:
app: nginx-1
spec:
replicas: 1
selector:
matchLabels:
app: nginx-1
template:
metadata:
labels:
app: nginx-1
spec:
containers:
- name: nginx
image: easzlab.io.local:5000/nginx:1.21.3
command: ["/bin/sh", "-c", "mkdir /usr/share/nginx/html/v1;echo 'hello nginx-1'>/usr/share/nginx/html/v1/index.html;nginx -g 'daemon off;'"]
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-2
labels:
app: nginx-2
spec:
replicas: 1
selector:
matchLabels:
app: nginx-2
template:
metadata:
labels:
app: nginx-2
spec:
containers:
- name: nginx
image: easzlab.io.local:5000/nginx:1.21.3
command: ["/bin/sh", "-c", "mkdir /usr/share/nginx/html/v2;echo 'hello nginx-2'>/usr/share/nginx/html/v2/index.html;nginx -g 'daemon off;'"]
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx1-svc
labels:
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: nginx-1
---
apiVersion: v1
kind: Service
metadata:
name: nginx2-svc
labels:
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: nginx-2
httpbin-route.yaml
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: httpbin-route
spec:
http:
- name: route-1
match:
hosts:
- httpbin.org
paths:
- /*
backends:
- serviceName: httpbin
servicePort: 80
curl httpbin.org:32060/headers
四、监控
curl -i http://$(kubectl get svc -n ingress-apisix apisix-prometheus-metrics -o jsonpath="{.spec.clusterIP}"):9091/apisix/prometheus/metrics
主要指标
https://apisix.apache.org/docs/apisix/plugins/prometheus/#using-grafana-to-graph-the-metrics
https://apisix.apache.org/zh/docs/apisix/plugins/prometheus/
apisix_http_status
apisix_bandwidth
apisix_http_requests_total
apisix_nginx_http_current_connections
五、Annotations and Config
https://apisix.apache.org/zh/docs/ingress-controller/concepts/annotations/
https://github.com/apache/apisix/blob/release/3.3/conf/config-default.yaml
六、使用
1、dashbord
port
kubectl get svc -n ingress-apisix -o jsonpath="{.spec.ports[0].nodePort}" apisix-dashboard
username/password
admin/admin
bug
https://github.com/apache/apisix-dashboard/issues/2791
apisix dashboard与apisix的配置文件中都配置plugins
2、gateway 连接信息
export NODE_PORT=$(kubectl get -n ingress-apisix -o jsonpath="{.spec.ports[0].nodePort}" services apisix-gateway)
export NODE_IP=$(kubectl get nodes -n ingress-apisix -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
export NODE_PORT=$(kubectl get -n ingress-apisix -o jsonpath="{.spec.ports[0].nodePort}" services apisix-gateway)
export apisix=$(echo http://apisix.ingress.org:$NODE_PORT)
3、查看已注册路由信息
curl "http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/routes?page=1&page_size=10" -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X GET
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/routes -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
4、API 使用
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/routes -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/plugins/list -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
5、gzip
_meta:
disable: false
buffers.number: 32
buffers.size: 4096
comp_level: 5
http_version: 1.1
min_length: 20
types: '*'
vary: true
{
"_meta": {
"disable": false
},
"buffers": {
"number": 32,
"size": 4096
},
"comp_level": 5,
"http_version": 1.1,
"min_length": 20,
"types": "*",
"vary": true
}
enable plugin
curl -i http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules/gzip \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"gzip": {
"_meta": {
"disable": false
},
"comp_level": 5,
"http_version": 1.1,
"min_length": 20,
"types": "*",
"vary": true,
"buffers": {
"number": 32,
"size": 4096
}
}
}
}'
查看
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules/gzip -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
delete plugin
curl http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules/gzip -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X DELETE
验证
Accept-Encoding: gzip, deflate Content-Encoding: gzip
curl apisix.ingress.org:30962/index.html -i -H "Accept-Encoding: gzip"
根据代码中所做的更改重新加载插件
curl http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/plugins/reload -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT
5、http2
config.yaml
apisix:
enable_http2: true
6、header
k8s.apisix.apache.org/response-rewrite-add-header: "testkey1:testval1,testkey2:testval2"
k8s.apisix.apache.org/response-rewrite-set-header: "testkey1:testval1,testkey2:testval2"
k8s.apisix.apache.org/response-rewrite-remove-header: "testkey1,testkey2"
7、upstream timeout
annotations:
k8s.apisix.apache.org/upstream-read-timeout.: "5s"
k8s.apisix.apache.org/upstream-connect-timeout: "10s"
k8s.apisix.apache.org/upstream-send-timeout: "10s"
8、http-to-https
annotations:
k8s.apisix.apache.org/http-to-https: "true"
9、use-regex
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: apisix-ingress
annotations:
k8s.apisix.apache.org/use-regex: "true"
spec:
ingressClassName: apisix
rules:
- host: apisix.ingress.org
http:
paths:
- backend:
service:
name: nginx1-svc
port:
number: 80
path: /v1/.*/action1
pathType: ImplementationSpecific
10、websocket
nginx
location / {
// 启用支持websocket连接
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
annotation
curl http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/routes/665bd12e \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PATCH -i -d '
{
"enable_websocket": true
}'
curl http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/routes/f7c122fc \
-H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PATCH -i -d '
{
"enable_websocket": false
}'
curl -s $(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/routes/f7c122fc -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: apisix-ingress
annotations:
k8s.apisix.apache.org/enable-websocket: "true"
spec:
ingressClassName: apisix
rules:
- host: apisix.ingress.org
http:
paths:
- backend:
service:
name: websocket
port:
number: 8765
path: /ws
pathType: Exact
client
import asyncio
import websockets
async def main():
async with websockets.connect("ws://localhost:8765") as websocket:
message = "Hello, server"
await websocket.send(message)
print(f"Sent: {message}")
response = await websocket.recv()
print(f"Received: {response}")
# asyncio.run(main()) # python3
asyncio.get_event_loop().run_until_complete(main())
server
import asyncio
import websockets
# 连接处理器
async def echo(websocket, path):
async for message in websocket:
print(message)
await websocket.send(message)
# 启动服务器
start_server = websockets.serve(echo, "0.0.0.0", 8765)
# 创建一个事件循环并运行服务器
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
FROM python:3.12.4-alpine3.20
COPY socket_server.py /opt/
RUN pip install websockets -i https://pypi.tuna.tsinghua.edu.cn/simple
CMD ["python", "/opt/socket_server.py"]
kubectl run websocket --image easzlab.io.local:5000/websocket-test:latest --port 8765
kubectl expose pod websocket --port 8765
postman
ws://apisix.ingress.org:30962/ws
11、Customize Nginx configuration
https://github.com/apache/apisix/blob/master/docs/zh/latest/customize-nginx-configuration.md
https://github.com/apache/apisix/blob/release/3.3/conf/config-default.yaml
http://nginx.org/en/docs/http/ngx_http_core_module.html#http
12、prometheus 插件
启用插件
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"id":"1",
"plugins":{
"prometheus":{
}
}
}'
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules -X PUT -d '
{
"uri": "/test/index.html",
"plugins": {
"redirect": {
"uri": "https://192.168.0.127/error",
"ret_code": 301
}
}
}'
13、limit-req
limit-req插件使用漏桶算法
限制单个客户端对服务的请求速率。
https://apisix.apache.org/zh/docs/apisix/plugins/limit-req/
插件主要参数:
- key用来做请求计数的依据
- rate请求速率(以秒为单位)
- burst支持突发请求量
- nodelay不延迟突发请求
curl http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b635c8f1' -X PUT -d '
{
"uri": "/search/*",
"plugins": {
"limit-conn": {
"conn": 10,
"burst": 0,
"default_conn_delay": 0.1,
"rejected_code": 503,
"key": "remote_addr"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"39.97.63.215:80": 1
}
}
}'
14、limit-conn
limit-conn插件用于限制客户端对单个服务的并发请求数。当客户端对路由的并发请求数达到限制时,可以返回自定义的状态码和响应信息。
15、limit-count
limit-count插件使用固定的窗口算法
,主要用于限制单个客户端在指定时间范围内对服务的总请求数,并且会在HTTP响应头中返回剩余可以请求的个数。
16、synchronizing Kubernetes resources to APISIX
kubectl get cm -n ingress-apisix apisix-configmap -o yaml|sed -e 's/6h/30s/g'|kubectl apply -f -
kubectl get pod -n ingress-apisix -o name|grep controller|xargs kubectl delete -n ingress-apisix
kubectl get cm -n ingress-apisix apisix-configmap -o yaml|sed -e 's/30s/6h/g'|kubectl apply -f -
七、通过 lua 实现限速 limit-rate
https://www.daxuxu.info/blog/post/nginx-lua-jie-shao/
https://blog.donatas.net/blog/2017/07/25/limit-bandwidth-openresty/
https://developer.moduyun.com/article/c65f7549-169e-4544-b4d9-654bd9389bed.html
https://nginx.org/en/docs/http/ngx_http_core_module.html#limit_rate
https://github.com/apache/apisix/blob/master/example/apisix/plugins/3rd-party.lua
local core = require("apisix.core")
local ngx = ngx
local type = type
local schema = {
type = "object",
properties = {
limit_rate_after = {type ="string"},
limit_rate = {type ="string"}
},
required = {"limit_rate_after","limit_rate"},
}
local plugin_name = "limit_rate"
local _M={
version = 0.1,
priority = 99,
name = plugin_name,
schema = schema
}
function _M.check_schema(conf)
return core.schema.check(schema, conf)
end
function _M.access(conf,ctx)
ngx.var.limit_rate_after = conf.limit_rate_after
ngx.var.limit_rate = conf.limit_rate
--return 203, conf.limit_rate_after
end
function _M.header_filter(ctx)
core.response.add_header("X-Custom-Header", "hlyani")
end
--function _M.body_filter(ctx)
-- core.log.warn("hit body_filter phase")
--end
function _M.log(conf, ctx)
core.log.warn("limit_rate_after: ", conf.limit_rate_after, ", limit_rate: ", conf.limit_rate)
end
-- 注册插件
return _M
kubectl cp limit-rate.lua -n ingress-apisix apisix-649cb68c96-4d8cr:/usr/local/apisix/apisix/plugins/ai.lua
kubectl exec -it -n ingress-apisix apisix-649cb68c96-4d8cr apisix reload
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"id":"1",
"plugins":{
"limit-rate":{
"limit_rate": "2k",
"limit_rate_after": "500k"
}
}
}'
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/global_rules -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/plugins/list -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq
curl -s http://$(kubectl get svc -n ingress-apisix apisix-admin -o jsonpath="{.spec.clusterIP}"):9180/apisix/admin/plugins/list -H 'X-API-Key: edd1c9f034335f136f87ad84b625c8f1'|jq|grep ai
kubectl edit cm -n ingress-apisix apisix
http_server_location_configuration_snippet: |
set $limit_rate 0;
set $limit_rate_after 0;
curl apisix.ingress.org:32060/headers -v
curl -o /dev/null apisix.ingress.org:32060/image/jpeg
apiVersion: apisix.apache.org/v2
kind: ApisixPluginConfig
metadata:
name: limit-rate
spec:
plugins:
- name: limit-rate
enable: true
config:
limit_rate: 20k
limit_rate_after: 500k
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-httpbin-ingress
annotations:
k8s.apisix.apache.org/plugin-config-name: limit-rate
spec:
ingressClassName: nginx
rules:
- host: apisix.ingress.org
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: test-httpbin-svc
port:
number: 80
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: test-limit-rate
spec:
http:
- name: route
match:
hosts:
- apisix.ingress.org
paths:
- /
backends:
- serviceName: test-httpbin-svc
servicePort: 80
plugins:
- name: limit-rate
enable: true
config:
limit_rate: 20k
limit_rate_after: 500k
修改 chart 包
vim apisix/templates/limit-rate.yaml
{{- if .Values.apisix.customPlugins.enabled }}
kind: ConfigMap
apiVersion: v1
metadata:
name: limit-rate
data:
limit-rate.lua: |
local core = require("apisix.core")
local ngx = ngx
local type = type
local schema = {
type = "object",
properties = {
limit_rate_after = {type ="string"},
limit_rate = {type ="string"}
},
required = {"limit_rate_after","limit_rate"},
}
local plugin_name = "limit_rate"
local _M={
version = 0.1,
priority = 1004,
name = plugin_name,
schema = schema
}
function _M.check_schema(conf)
return core.schema.check(schema, conf)
end
function _M.access(conf,ctx)
ngx.var.limit_rate_after = conf.limit_rate_after
ngx.var.limit_rate = conf.limit_rate
end
function _M.log(conf, ctx)
core.log.warn("limit_rate_after: ", conf.limit_rate_after, ", limit_rate: ", conf.limit_rate)
end
return _M
{{- end }}
luaPath: 因为已经放在了默认插件目录,所以可以不需要配置
luaPath 的路径会默认添加 “/apisix/plugins”
chart comfigmap 逻辑 如果 plugins 不为空,会自动加载 .Values.apisix.customPlugins.plugins,所以 apisix.plugins 不用添加新加插件
vim apisix/values.yaml
apisix:
plugins:
- 略。。。
customPlugins:
enabled: true
#luaPath: "/usr/local/apisix/?.lua" # -> /usr/local/apisix/apisix/plugins/?.lua
luaPath: "/opt/custom_plugins/?.lua"
plugins:
- name: "limit-rate"
attrs: {}
configMap
name: "limit-rate"
mounts:
- key: "limit-rate.lua"
path: "/usr/local/apisix/apisix/plugins/limit-rate.lua"
八、wrk 压力测试
https://github.com/wg/wrk/tree/master/scripts
yum -y install gcc openssl-devel git
git clone https://github.com/wg/wrk.git wrk
cd wrk
make
cp wrk /usr/bin/
-t, --threads 线程
-c, --connections 连接数
-d, --duration 时间
--latency Print latency statistics
wrk -t10 -c1000 -d1h --latency http://apisix.ingress.org:30962/index.html
Avg 平均值
Stdev 标准方差
Max 最大值
Latency 延迟
Req/Sec 每秒请求数
Latency Distribution 延迟分布
Requests/sec 平均每秒处理完成请求个数
Transfer/sec 平均每秒读取数据量
Running 60m test @ http://apisix.ingress.org:30962/index.html
10 threads and 1000 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 48.95ms 78.86ms 2.00s 90.06%
Req/Sec 1.69k 334.68 3.68k 68.25%
Latency Distribution
50% 23.36ms
75% 31.49ms
90% 126.79ms
99% 379.73ms
60512663 requests in 60.00m, 222.33GB read
Socket errors: connect 0, read 2102, write 16, timeout 27480
Non-2xx or 3xx responses: 36
Requests/sec: 16808.64
Transfer/sec: 63.24MB
https://www.nginx-cn.net/blog/testing-performance-nginx-ingress-controller-kubernetes/
九、FAQ
https://apisix.apache.org/zh/docs/apisix/FAQ/
十、Nginx参数优化
https://gist.github.com/denji/8359866
https://www.cloudpanel.io/blog/nginx-performance/
events {
use epoll;
worker_connections 6000;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /usr/local/nginx/logs/access.log;
error_log /usr/local/nginx/logs/error.log;
proxy_connect_timeout 900;
proxy_read_timeout 900;
proxy_send_timeout 900;
proxy_cache_path /var/cache/nginx keys_zone=a_cache:10m inactive=10m max_size=10g;
gzip on;
gzip_static on;
gzip_buffers 40 4K;
gzip_comp_level 7;
gzip_min_length 1k;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg+xml;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
client_max_body_size 500M;
}
location / {
proxy_http_version 1.1;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Referer $http_referer;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Origin "";
client_body_buffer_size 128k;
client_max_body_size 500M;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 32 4k;
proxy_busy_buffers_size 64k;
}
{
"client-max-body-size": "500m",
"default-server-return": "https://192.168.0.127/error",
"keepalive-requests": "3000",
"keepalive-timeout": "65s",
"location-snippets": "proxy_set_header Origin \"\";\ngzip_static on;\nproxy_set_header Accept-Encoding gzip;\n",
"proxy-connect-timeout": "900s",
"proxy-read-timeout": "900s",
"proxy_send_timeout": "900s",
"worker-connections": "3000"
}
nginx:
workerRlimitNofile: "204800"
workerConnections: "204800"
workerProcesses: auto
enableCPUAffinity: true
keepaliveTimeout: 30
clientMaxBodySize: 500M
logs:
enableAccessLog: false
configurationSnippet:
httpStart: |
access_log off;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
gzip on;
gzip_static on;
gzip_min_length 10240;
gzip_comp_level 5;
gzip_vary on;
gzip_disable msie6;
#gzip_proxied expired no-cache no-store private auth;
gzip_proxied any;
gzip_types
text/css
text/javascript
text/xml
text/plain
text/x-component
application/javascript
application/x-javascript
application/json
application/xml
application/rss+xml
application/atom+xml
application/vnd.ms-fontobject
font/truetype
font/opentype
image/svg+xml;
reset_timedout_connection on;
keepalive_requests 100000;
client_body_buffer_size 128k;
client_header_buffer_size 3m;
httpSrvLocation: |
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
final
config.yaml: |-
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
apisix: # universal configurations
events: # Event distribution module configuration
module: lua-resty-events # Sets the name of the events module used.
# Supported module: lua-resty-worker-events and lua-resty-events
node_listen: # APISIX listening port
- 9080
enable_heartbeat: true
enable_admin: true
enable_admin_cors: true
enable_debug: false
extra_lua_path: /opts/custom_plugins/?.lua;
enable_control: true
control:
ip: 127.0.0.1
port: 9090
enable_dev_mode: false # Sets nginx worker_processes to 1 if set to true
enable_reuseport: true # Enable nginx SO_REUSEPORT switch if set to true.
enable_ipv6: true # Enable nginx IPv6 resolver
enable_http2: true
enable_server_tokens: true # Whether the APISIX version number should be shown in Server header
# proxy_protocol: # Proxy Protocol configuration
# listen_http_port: 9181 # The port with proxy protocol for http, it differs from node_listen and admin_listen.
# # This port can only receive http request with proxy protocol, but node_listen & admin_listen
# # can only receive http request. If you enable proxy protocol, you must use this port to
# # receive http request with proxy protocol
# listen_https_port: 9182 # The port with proxy protocol for https
# enable_tcp_pp: true # Enable the proxy protocol for tcp proxy, it works for stream_proxy.tcp option
# enable_tcp_pp_to_upstream: true # Enables the proxy protocol to the upstream server
proxy_cache: # Proxy Caching configuration
cache_ttl: 10s # The default caching time if the upstream does not specify the cache time
zones: # The parameters of a cache
- name: disk_cache_one # The name of the cache, administrator can be specify
# which cache to use by name in the admin api
memory_size: 50m # The size of shared memory, it's used to store the cache index
disk_size: 1G # The size of disk, it's used to store the cache data
disk_path: "/tmp/disk_cache_one" # The path to store the cache data
cache_levels: "1:2" # The hierarchy levels of a cache
# - name: disk_cache_two
# memory_size: 50m
# disk_size: 1G
# disk_path: "/tmp/disk_cache_two"
# cache_levels: "1:2"
router:
http: radixtree_host_uri # radixtree_uri: match route by uri(base on radixtree)
# radixtree_host_uri: match route by host + uri(base on radixtree)
# radixtree_uri_with_parameter: match route by uri with parameters
ssl: 'radixtree_sni' # radixtree_sni: match route by SNI(base on radixtree)
proxy_mode: http
stream_proxy: # TCP/UDP proxy
tcp: # TCP proxy port list
- 9100
udp: # UDP proxy port list
- 9200
# dns_resolver:
#
# - 127.0.0.1
#
# - 172.20.0.10
#
# - 114.114.114.114
#
# - 223.5.5.5
#
# - 1.1.1.1
#
# - 8.8.8.8
#
dns_resolver_valid: 30
resolver_timeout: 5
ssl:
enable: false
listen:
- port: 9443
enable_http3: false
ssl_protocols: "TLSv1.2 TLSv1.3"
ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA"
nginx_config: # config for render the template to genarate nginx.conf
error_log: "/dev/stderr"
error_log_level: "warn" # warn,error
worker_processes: "10"
enable_cpu_affinity: true
worker_rlimit_nofile: 8192 # the number of files a worker process can open, should be larger than worker_connections
worker_shutdown_timeout: 240s
max_pending_timers: 16384
max_running_timers: 4096
event:
worker_connections: 1024
http:
lua_shared_dict: # Nginx Lua shared memory zone. Size units are m or k.
lrucache-lock: 100m
prometheus-metrics: 200m
worker-events: 100m
enable_access_log: true
access_log: "/dev/stdout"
access_log_format: '$remote_addr - $remote_user [$time_local] $http_host \"$request\" $status $body_bytes_sent $request_time \"$http_referer\" \"$http_user_agent\" $upstream_addr $upstream_status $upstream_response_time \"$upstream_scheme://$upstream_host$upstream_uri\"'
access_log_format_escape: default
keepalive_timeout: "60s"
client_max_body_size: 500M
client_header_timeout: 60s # timeout for reading client request header, then 408 (Request Time-out) error is returned to the client
client_body_timeout: 60s # timeout for reading client request body, then 408 (Request Time-out) error is returned to the client
send_timeout: 30s # timeout for transmitting a response to the client.then the connection is closed
underscores_in_headers: "on" # default enables the use of underscores in client request header fields
real_ip_header: "X-Real-IP" # http://nginx.org/en/docs/http/ngx_http_realip_module.html#real_ip_header
real_ip_from: # http://nginx.org/en/docs/http/ngx_http_realip_module.html#set_real_ip_from
- 127.0.0.1
- 'unix:'
upstream:
keepalive: 320
keepalive_requests: 1000
keepalive_timeout: 60s
http_configuration_snippet: |
access_log on;
proxy_connect_timeout 900;
proxy_read_timeout 900;
proxy_send_timeout 900;
proxy_buffers 16 32k;
proxy_buffer_size 64k;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
gzip on;
gzip_static on;
gzip_min_length 1k;
gzip_buffers 16 8k;
gzip_comp_level 7;
gzip_vary on;
gzip_disable msie6;
gzip_proxied any;
gzip_types
text/css
text/javascript
text/xml
text/plain
text/x-component
application/javascript
pplication/x-javascript
application/json
application/xml
application/rss+xml
application/atom+xml
application/vnd.ms-fontobject
font/truetype
font/opentype
image/svg+xml;
reset_timedout_connection on;
keepalive_requests 1000;
client_body_buffer_size 128k;
client_header_buffer_size 3m;
http_server_location_configuration_snippet: |
proxy_connect_timeout 900;
proxy_read_timeout 900;
proxy_send_timeout 900;
proxy_buffers 16 32k;
proxy_buffer_size 64k;
set $limit_rate 0;
set $limit_rate_after 0;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_intercept_errors on;
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 = https://10.15.200.50:58043/notebook/error;
plugins: # plugin list
- cors
- proxy-rewrite
- limit-rate
- limit-conn
- limit-count
- limit-req
- gzip
- redirect
- response-rewrite
- prometheus
- limit-rate
plugin_attr:
prometheus:
export_addr:
ip: 0.0.0.0
port: 9091
export_uri: /apisix/prometheus/metrics
metric_prefix: apisix_
deployment:
role: traditional
role_traditional:
config_provider: etcd
admin:
allow_admin: # http://nginx.org/en/docs/http/ngx_http_access_module.html#allow
- 127.0.0.1/24
- 0.0.0.0/0
# - "::/64"
admin_listen:
ip: 0.0.0.0
port: 9180
# Default token when use API to call for Admin API.
# *NOTE*: Highly recommended to modify this value to protect APISIX's Admin API.
# Disabling this configuration item means that the Admin API does not
# require any authentication.
admin_key:
# admin: can everything for configuration data
- name: "admin"
key: edd1c9f034335f136f87ad84b625c8f1
role: admin
# viewer: only can view configuration data
- name: "viewer"
key: 4054f7cf07e344346cd3f287985e76a2
role: viewer
etcd:
host: # it's possible to define multiple etcd hosts addresses of the same etcd cluster.
- "http://192.168.0.127:2379" # multiple etcd address
timeout: 30
watch_timeout: 50
resync_delay: 5
health_check_timeout: 10
startup_retry: 2
prefix: "/apisix" # configuration prefix in etcd
timeout: 30 # 30 seconds
十一、default error return
httpSrv: |
location = /default-server-return {
proxy_pass https://192.168.0.127/error;
}
location /error-forward/ {
proxy_pass https://10.15.200.50:58043;
}
httpSrvLocation: |
proxy_intercept_errors on;
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 /default-server-return;
https://github.com/apache/apisix/issues/7987
configurationSnippet:
# Based on
# - https://blog.adriaan.io/one-nginx-error-page-to-rule-them-all.html
# - https://gist.github.com/lextoumbourou/d6221deb818da4f342ea
httpStart: |
more_clear_headers Server;
map $status $status_text {
400 'Bad Request';
401 'Unauthorized';
402 'Payment Required';
403 'Forbidden';
404 'Not Found';
405 'Method Not Allowed';
406 'Not Acceptable';
407 'Proxy Authentication Required';
408 'Request Timeout';
409 'Conflict';
410 'Gone';
411 'Length Required';
412 'Precondition Failed';
413 'Payload Too Large';
414 'URI Too Long';
415 'Unsupported Media Type';
416 'Range Not Satisfiable';
417 'Expectation Failed';
418 'I\'m a teapot';
421 'Misdirected Request';
422 'Unprocessable Entity';
423 'Locked';
424 'Failed Dependency';
425 'Too Early';
426 'Upgrade Required';
428 'Precondition Required';
429 'Too Many Requests';
431 'Request Header Fields Too Large';
451 'Unavailable For Legal Reasons';
500 'Internal Server Error';
501 'Not Implemented';
502 'Bad Gateway';
503 'Service Unavailable';
504 'Gateway Timeout';
505 'HTTP Version Not Supported';
506 'Variant Also Negotiates';
507 'Insufficient Storage';
508 'Loop Detected';
510 'Not Extended';
511 'Network Authentication Required';
default 'Something is wrong';
}
map $http_accept $extension {
default html;
~*application/json json;
}
httpSrv: |
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 @error_$extension;
location @error_json {
types { } default_type "application/json; charset=utf-8";
echo '{"error_msg": "$status_text"}';
}
location @error_html {
types { } default_type "text/html; charset=utf-8";
echo '<html><head><title>$status $status_text</title></head><body><center><h1>$status $status_text</h1></center></html>';
}
httpSrvLocation: |
proxy_intercept_errors on;
error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 421 422 423 424 425 426 428 429 431 451 500 501 502 503 504 505 506 507 508 510 511 = https://192.168.0.127/error;