Cloud Native应用交付

  • 首页
  • 关于本站
  • 个人介绍
  • Downloads
  • Repo
    • Github
    • Container
  • F5
    • F5 Python SDK
    • F5-container
    • F5-LBaaS
  • 社交
    • 联系我
    • 微信/微博
    • 公众号
    • 打赏赞助
行至水穷处 坐看云起时
Cloud Native Application Services: cnadn.net
  1. 首页
  2. NGINX
  3. 正文

集群级Ingress Controller免重载动态性限流(2)

2020年03月19日 17195点热度 0人点赞 0条评论

在上一篇文章,利用NGINX的keyval,变量map,通过API接口实现了基于服务级别维度和域名维度进行了限流的动态控制。但是在很多情况下Ingress Controller都是多实例部署,那么限流就需要以集群整体来考量而不应该以单个实例来控制,特别是在IC数量动态性的情况下以单实例来控制会导致限流的不稳定。同时,引入IC集群级别不应该带来额外的复杂性,例如应该一个API call即可实现集群的整个体性动作而无需每个IC实例去控制。

IC集群级别限流

需求分析

  • 所有IC应能够形成一个集群并共享相关限流状态
  • 限流执行动作仅需一个API Call而无需向每个NGINX实例调用
  • 能实现限流状态的查看与输出
  • 能实现集群状态信息的查看与输出
  • 当k8s扩缩NGINX的IC实例后IC集群能自动化发现与移除

解决方案

  • 利用NGINX Plus的zone_sync模块实现集群配置,并在集群之间同步limit限流状态信息以及keyval同步
  • 利用NGINX Plus的API以及dashboard统计和观察限流状态及同步状态
  • 利用k8s的headless service实现IC集群成员的自动化发现与维护

实践演示

1. 首先来看一个伪配置,看要实现一个NGINX集群的最小配置是什么

1
2
3
4
5
6
7
8
stream {
         server {
            listen 12345;
            zone_sync;
            zone_sync_server 1.1.1.1:12345;
            zone_sync_server 2.2.2.2:12345;
        }
    }

可以看出,首先需要在NGINX中配置一个stream的四层配置,因为zone sync是依赖四层来通信的,在server配置块中最重要的就是zone_sync_server的配置,这里配置集群中所有的实例的IP机器监听的端口。

但是,显然上述配置在k8s的IC环境下是很难去实践的,如果使用的是Daemonset模式来部署IC,这里的server相对固定不会经常发生变化,可以手工来配置;如果是以deployment方式来不是IC,则这里的server就可能会经常随着deployment的变化而变化,根据pod的网络类型,有可能这里的IP会发生经常变化。 显然需要一个更加能与k8s兼容的自动化方式。

zone_sync模块提供了这样的能力,可以将上述配置的server IP改为使用域名,因此我们只需要配置相应的k8s中的一个headless svc的域名即可,因为只有使用headless svc才可以获得真实的pod ip,那么上述的配置将变成如下这样:

1
2
3
4
5
6
7
8
9
    stream {
        resolver 10.96.0.10 valid=5s;
 
        server {
            listen 12345;
            zone_sync;
            zone_sync_server nginx-ic-svc.nginx-ingress.svc.cluster.local:12345 resolve;
        }
    }

resolver配置的是DNS的IP,这里为k8s集群内的DNS svc IP,valid控制每次DNS解析结果缓存多久,为了能保证尽快发现pod的变化,这里不宜设置过大。zone_sync_server后则配置的是IC的headless svc的域名,域名后面的resolve参数非常重要,这个参数可以保证无法解析域名的时候配置可以正常启动同时又能让缓存结束后能再次查询域名从而确保能很快获取到DNS解析的变化。

2. 所以在集群里首先暴露IC的headless svc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@k8s-master-v1-16 deployment]# cat ingress-controller-svc.yaml
kind: Service
apiVersion: v1
metadata:
  namespace: nginx-ingress
  name: nginx-ic-svc
spec:
  selector:
    app: nginx-ingress
  clusterIP: None
  ports:
  - protocol: TCP
    port: 12345
    targetPort: 12345

查看下结果,可以看到headless svc已经成功, 解析对应域名也能获得两个pod地址:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master-v1-16 deployment]# kubectl describe svc nginx-ic-svc -n nginx-ingress
Name:              nginx-ic-svc
Namespace:         nginx-ingress
Labels:            <none>
Annotations:       <none>
Selector:          app=nginx-ingress
Type:              ClusterIP
IP:                None
Port:              <unset>  12345/TCP
TargetPort:        12345/TCP
Endpoints:         10.244.1.60:12345,10.244.2.68:12345
Session Affinity:  None
Events:            <none>
1
2
3
4
5
#nslookup nginx-ic-svc.nginx-ingress.svc.cluster.local.
 
Name:      nginx-ic-svc.nginx-ingress.svc.cluster.local.
Address 1: 10.244.2.68 10-244-2-68.nginx-ic-svc.nginx-ingress.svc.cluster.local
Address 2: 10.244.1.60 10-244-1-60.nginx-ic-svc.nginx-ingress.svc.cluster.local

3. 由于我们要用TCP 12345用于集群间状态通信,因此在IC的deployment里需要暴露容器的12345端口,修改配置并执行,确认配置成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
      - image: myf5/nginx-plus-ingress-opentracing:1.6.3
        imagePullPolicy: IfNotPresent
        name: nginx-plus-ingress
        ports:
        - name: http
          containerPort: 80
          hostPort: 80
        - name: https
          containerPort: 443
          hostPort: 443
        - name: prometheus
          containerPort: 9113
        - name: apiport
          containerPort: 8888
          hostPort: 8888
        - name: apiport-write
          containerPort: 9999
          hostPort: 7777
        - name: ic-cluster-sync
          containerPort: 12345

4.将对应的stream下的配置注入NGINX里,由于配置的命令都是在stream段落下,因此在NGINX启动所使用的configmap里增加stream-snippets即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
kind: ConfigMap
apiVersion: v1
metadata:
  name: nginx-config
  namespace: nginx-ingress
data:
  stream-snippets: |
    resolver 10.96.0.10 valid=5s;
    server {
       listen 12345;
       zone_sync;
       zone_sync_server nginx-ic-svc.nginx-ingress.svc.cluster.local:12345 resolve;
    }

应用该configmap,NGINX将自动更新配置。可以通过查看相关NGINX实例的log确认没有错误信息,此时如果NGINX无法解析上述域名,则会在日志中报出错误提示,如果一切正常,日志里可以看到相关集群间建立连接的日志信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
2020/03/19 14:08:51 [notice] 65#65: resolving discovered new node "10.244.2.69"
2020/03/19 14:08:51 [notice] 65#65: resolving discovered new node "10.244.1.61"
2020/03/19 14:08:51 [notice] 65#65: *59 connected to peer "10.244.2.69", node: 10.244.2.69
2020/03/19 14:08:51 [notice] 65#65: *59 node is online, node: 10.244.2.69
2020/03/19 14:08:51 [notice] 66#66: *61 accepted client 10.244.2.69, client: 10.244.2.69, server: 0.0.0.0:12345
2020/03/19 14:08:51 [notice] 65#65: *59 zone "limitreq_uri" done while sending snapshots, node: 10.244.2.69
2020/03/19 14:08:51 [notice] 65#65: *59 zone "limitper_server" done while sending snapshots, node: 10.244.2.69
2020/03/19 14:08:51 [notice] 66#66: *61 detected local connection id, closing, client: 10.244.2.69, server: 0.0.0.0:12345
10.244.2.69 [19/Mar/2020:14:08:51 +0000] TCP 200 0 29 0.000
2020/03/19 14:08:51 [notice] 65#65: *59 node is offline: ignore self while sending snapshots, node: 10.244.2.69
2020/03/19 14:08:51 [notice] 65#65: *60 connected to peer "10.244.1.61", node: 10.244.1.61
2020/03/19 14:08:51 [notice] 65#65: *60 node is online, node: 10.244.1.61
2020/03/19 14:08:51 [notice] 65#65: *60 zone "limitreq_uri" done while sending snapshots, node: 10.244.1.61
2020/03/19 14:08:51 [notice] 65#65: *60 zone "limitper_server" done while sending snapshots, node: 10.244.1.61

5. 在上一篇文章中,在配置keyval_zone, limit_req_zone的时候其实并没有指定这些zone需要同步,因此要想在集群里实现两者的同步,编辑nginx对应的configmap文件,并更新配置:

1
2
3
4
5
6
    keyval_zone zone=limitreq_uri:64k timeout=2h type=prefix sync;
    keyval_zone  zone=limitper_server:64k timeout=2h sync;
  
    limit_req_zone $limit_key zone=req_zone_10:1m rate=10r/s sync;
    limit_req_zone $limit_key zone=req_zone_20:1m rate=20r/s sync;
    limit_req_zone $limit_key_servername zone=perserver:10m rate=50r/s sync;

6. 至此,集群的配置工作就完成了,此时进入NGINX的dashboard界面可以看到类似如下

可以看到cluster信息

如果点入cluster可以看到如下界面,注意界面显示的Nodes online数量并不包含自己,由于测试环境只部署了2个IC,所以图中显示为1

具体的cluster信息

测试

通过API,更新一个keyval来测试一下,这里假设对limiter_server进行限流

curl -X POST "http://172.16.10.212:7777/api/6/http/keyvals/limitper_server" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"cafe.example.com\": \"1\"}"

在对172.16.10.212执行API call更新limitper_server后,来查看确认一些组内另一台172.16.10.211 NGINX上是否接受到了同步与状态更新,可以看到此台中的limitper_server zone接受到了一条记录更新:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
curl -X GET "http://172.16.10.211:7777/api/5/stream/zone_sync/" -H "accept: application/json"
 
{
  "status": {
    "nodes_online": 1,
    "msgs_in": 3,
    "msgs_out": 0,
    "bytes_in": 126,
    "bytes_out": 0
  },
  "zones": {
    "limitreq_uri": {
      "records_total": 0,
      "records_pending": 0
    },
    "limitper_server": {
      "records_total": 1, <<<<已接受到更新
      "records_pending": 0
    },
    "req_zone_10": {
      "records_total": 0,
      "records_pending": 0
    },
    "req_zone_20": {
      "records_total": 0,
      "records_pending": 0
    },
    "perserver": {
      "records_total": 0,
      "records_pending": 0
    }
  }
}

接下来对172.16.10.211上的IC发起一些访问激活限流,看限流信息是否可以同步到172.16.10.212上,首先看上述的输出内容中perserver zone是没有记录的, 执行流量测试后,可以看到以下输出中显示已经接收到状态更新:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
curl -X GET "http://172.16.10.212:7777/api/6/stream/zone_sync/" -H "accept: application/json"
 
{
  "status": {
    "nodes_online": 1,
    "msgs_in": 34,
    "msgs_out": 1,
    "bytes_in": 1434,
    "bytes_out": 68
  },
  "zones": {
    "limitreq_uri": {
      "records_total": 0,
      "records_pending": 0
    },
    "limitper_server": {
      "records_total": 1,
      "records_pending": 0
    },
    "req_zone_10": {
      "records_total": 0,
      "records_pending": 0
    },
    "req_zone_20": {
      "records_total": 0,
      "records_pending": 0
    },
    "perserver": {
      "records_total": 1,
      "records_pending": 0
    }
  }
}

再来具体看下211这台NGINX的限流统计, 可以看到perserver zone中的被拒绝的访问数量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
curl -X GET "http://172.16.10.211:7777/api/6/http/limit_reqs/" -H "accept: application/json"
 
{
"perserver": {
"passed": 219,
"delayed": 0,
"rejected": 1781,
"delayed_dry_run": 0,
"rejected_dry_run": 0
},
"req_zone_20": {
"passed": 0,
"delayed": 0,
"rejected": 0,
"delayed_dry_run": 0,
"rejected_dry_run": 0
},
"req_zone_10": {
"passed": 0,
"delayed": 0,
"rejected": 0,
"delayed_dry_run": 0,
"rejected_dry_run": 0
}
}

总结

通过设置NGINX Plus的集群同步能力,实现了在IC的集群级别限流,同时对限流动作的API调用只需调用一个,简化了操作。通过与k8s的headless svc配合,实现了当部署的NGINX实例发生变化时候IC集群能能自动发现与删除,无需人工操作,实现了整体配置的在k8s维度的原生性,更为重要的是限流的状态同样自适应实例的扩缩而自动化同步和调整。NGINX的API接口本身提供了集群状态、限流结果的输出,dashboard也可以以图形化的方式展示集群状态。

另:

对于上篇文章提到的keyval持久性问题,由于但新的NGINX加入实例后会自动被当前正在运行的实例来更新状态,所以实际上无需考虑状态的持久化。如果希望实现的是当首次整体部署IC的时候就自动启动写入相关keyval的内容,那么就需要考虑持久化,配置也很简单,在keyval_zone指令里增加state参数即可:

1
2
    keyval_zone zone=limitreq_uri:64k state=/your-store-mount-path/limitreq_uri.keyval timeout=2h type=prefix sync;
    keyval_zone  zone=limitper_server:64k state=/your-store-mount-path/limitper_server timeout=2h sync;

具体存储路径可以通过挂载共享存储到容器目录后来统一存储。

原创文章,转载请注明

https://myf5.net

相关文章

  • 集群级Ingress Controller免重载动态性限流(1)
  • Helm 3 部署NGINX Ingress Controller
  • Better Alignment:多可用区双层负载下,如何借助F5避免局部NGINX后业务实例过载
  • 扩展或影响nginx(Ingress Controller)配置的方法
  • [记录]nginx etag在proxy下的一些行为
本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可
标签: api ingress controller keyval limit_req_zone nginx rate limiting
最后更新:2020年03月24日

纳米

linjing.io

打赏 点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理。

页面AI聊天助手
文章目录
  • 需求分析
  • 解决方案
  • 实践演示
  • 测试
  • 总结

纳米

linjing.io

☁️迈向Cloud Native ADC ☁️

认证获得:
TOGAF: ID 152743
Kubernetes: CKA #664
Microsoft: MCSE MCDBA
Cisco: CCNP
Juniper: JNCIS
F5:
F5 Certified Solution Expert, Security
F5 Certified Technology Specialist, LTM/GTM/APM/ASM
F5 Certified BIG-IP Administrator
  • 点击查看本博技术要素列表
  • 归档
    分类
    • AI
    • Automation
    • Avi Networks
    • Cisco ACI
    • CISCO资源
    • F5 with ELK
    • F5-Tech tips
    • F5技术
    • Juniper
    • Linux
    • NGINX
    • SDN
    • ServiceMesh
    • WEB编程
    • WINDOWS相关
    • 业界文章
    • 交换机技术
    • 化云为雨/Openstack
    • 协议原理
    • 容器/k8s
    • 我的工作
    • 我的生活
    • 网站技术
    • 路由器技术
    • 项目案例
    标签聚合
    network bigip envoy k8s flannel neutron istio docker F5 gtm irule nginx api DNS openstack
    最近评论
    汤姆 发布于 8 个月前(09月10日) 嗨,楼主,里面的json怎么下载啊,怎么收费啊?
    汤姆 发布于 8 个月前(09月09日) 大佬,kib的页面可以分享下吗?谢谢
    zhangsha 发布于 1 年前(05月12日) 资料发给我下,谢谢纳米同志!!!!lyx895@qq.com
    李成才 发布于 1 年前(01月02日) 麻烦了,谢谢大佬
    纳米 发布于 1 年前(01月02日) 你好。是的,因为以前下载系统插件在一次升级后将所有的下载生成信息全弄丢了。所以不少文件无法下载。DN...
    浏览次数
    • Downloads - 183,680 views
    • 联系我 - 118,966 views
    • 迄今为止最全最深入的BIGIP-DNS/GTM原理及培训资料 - 116,205 views
    • Github - 103,557 views
    • F5常见log日志解释 - 79,729 views
    • 从传统ADC迈向CLOUD NATIVE ADC - 下载 - 74,510 views
    • Sniffer Pro 4 70 530抓包软件 中文版+视频教程 - 74,320 views
    • 迄今为止最全最深入的BIGIP-DNS/GTM原理及培训资料 - 67,770 views
    • 关于本站 - 60,808 views
    • 这篇文档您是否感兴趣 - 55,463 views
    链接表
    • F5SE创新
    • Jimmy Song‘s Blog
    • SDNlab
    • Service Mesh社区
    • 三斗室
    • 个人profile
    • 云原生社区

    COPYRIGHT © 2023 Cloud Native 应用交付. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang

    京ICP备14048088号-1

    京公网安备 11010502041506号