BLOG | NGINX

使用 NGINX Plus 实现动态 A/B Kubernetes 多集群负载均衡和安全控制

NGINX-Part-of-F5-horiz-black-type-RGB
Chris Akker 缩略图
Chris Akker
Published February 15, 2024

作为一名现代平台运维或 DevOps 工程师,您不仅使用一系列开源工具(和一些商业工具)来为开发团队测试、部署及管理新应用和容器,而且还选用 Kubernetes 在开发、测试、模拟和生产环境中运行这些容器和 pod。您已经引入了微服务架构和概念,而且在大多数情况下,它很好用,但也不可避免地存在一些问题。

例如,当您构建和部署新集群、服务及应用时,如何在不弄丢任何流量的情况下轻松地将这些新资源整合或迁移到生产环境中呢?在更改 DNS 记录、负载均衡器、防火墙及代理的配置时,需要重新加载或重启传统网络设备。由于更新 DNS、负载均衡器及防火墙规则需要“中断服务”或“维护窗口”,因此无法在不造成停机的情况下重新配置这些更改。通常情况下,您必须不厌其烦地提交服务工单,然后等待另一个团队来核实和更改。

维护窗口会使您的团队陷入困境并拖延应用交付,让您大呼:“一定有更好的方法来管理流量!”下面我们来探讨一种能够让您重回快车道的解决方案。

 

双活多集群负载均衡

如果您有多个 Kubernetes 集群,最佳方法是同时将流量路由到两个集群。最好是执行 A/B、灰度或蓝绿流量精分,并发送一小部分流量作为测试。为此,您可以使用 NGINX Plus 的 ngx_http_split_clients_module。

K8s with NGINX Plus diagram

HTTP Split Clients 模块由 NGINX 开源版编写而成,允许基于一个键按比例分配请求。在此用例中,集群就是 NGINX 的“上游”。因此,当客户端请求到达时,流量将会分配给两个集群。用于确定客户端请求的键可以是任何可用的 NGINX 客户端 $variable。不过,要控制每个请求,请使用 $request_id 变量,这是 NGINX 分配给每个传入请求的唯一编号。

若需配置精分比例,请确定要分配给每个集群的百分比。在本例中,我们将 K8s 集群 1 作为“大型集群”用于生产环境,并将集群 2 作为“小型集群”用于生产前测试。如有一个用于测试的小型集群,您可以使用 90:10 的比例在该集群上测试 10% 的流量,以确保一切正常运行,然后再对大型集群实施新变更。如果这听起来风险太高,您可将比例改为 95:5。事实上,您可以从 0 到 100% 之间选择任何比例。

对于大多数实时生产流量,您可能需要使用 50:50 的比例,即两个集群分配的流量相等。但您也可以根据集群大小或其他细节轻松设置其他比例。您可轻松地将比例设置为 0:100(或 100:0),在不造成停机的情况下升级、修补、修复甚至更换整个集群。当您解决一个集群上的问题时,让 NGINX split_clients 将请求路由到另一个在线集群。


# Nginx 多集群负载均衡
# 针对集群 1:集群 2 比例的 HTTP Split Clients 配置
# 提供 100、99、50、1、0% 的比例(按需添加/更改)
# 基于
# https://www.nginx-cn.net/blog/dynamic-a-b-testing-with-nginx-plus/
# Chris Akker — 2024 年 1 月
#

split_clients $request_id $split100 {
     * cluster1-cafe; # 将所有流量发送到集群 1
     }

split_clients $request_id $split99 {
     99% cluster1-cafe; # 99% 分配给集群 1,1% 分配给集群 2
     * cluster2-cafe;
     }

split_clients $request_id $split50 {
    50% cluster1-cafe; # 50% 分配给集群 1,50% 分配给集群 2
    * cluster2-cafe;
    }

split_clients $request_id $split1 {
    1.0% cluster1-cafe; # 1% 分配给集群 1,99% 分配给集群 2
    * cluster2-cafe;
    }

split_clients $request_id $split0 {
    * cluster2-cafe; # 将所有流量发送到集群 2
    }

# 根据比例选择上游集群

map $split_level $upstream {
       100 $split100;
       99 $split99;
       50 $split50;
       1.0 $split1;
       0 $split0;
      default $split50;
}


您可以添加或编辑上述配置,以匹配所需的比例(例如 90:10、80:20、60:40 等)。

注:NGINX 还有一个支持 stream 上下文中 TCP 连接的 Split Clients 模块,可用于非 HTTP 流量。该模块将根据新的 TCP 连接而非 HTTP 请求来精分流量。

 

NGINX Plus 键值存储

还有一个可用特性是 NGINX Plus 键值存储。这是 NGINX 共享内存区中的键值对象,可用于许多不同的数据存储用例。此处,我们用它来存储上一节中提到的精分比例值。NGINX Plus 允许您更改任何键值记录,而无需重新加载 NGINX。这样,您就可以通过调用 API 来更改此精分值,从而创建动态精分函数。

本例如下所示:

{“cafe.example.com”:90}

该键值记录如下:
键为“cafe.example.com”主机名

值为“90”,表示精分比例

您可以使用键值内存,而非在 NGINX 配置文件中对精分比例进行硬编码。这样,在 NGINX 中更改静态精分值时就无需重新加载 NGINX。

在本例中,NGINX 被配置为使用 90:10 的精分比例,其中大型集群 1 占 90%,小型集群 2 占 10%。因为这是键值记录,所以您可以使用 NGINX Plus API 动态更改这一比例,而无需重新加载配置!在您更改了新的比例值后,Split Clients 模块便会立即在下一次请求中使用该值。

创建键值记录,开始时比例为 50/50:

通过向 NGINX Plus 发送 API 命令,将新记录添加到键值存储中:

curl -iX POST -d '{"cafe.example.com":50}' http://nginxlb:9000/api/8/http/keyvals/split

更改键值记录,改为 90/10 比例:

使用 HTTP PATCH 方法更新内存中的键值记录,将键值精分比例改为 90:

curl -iX PATCH -d '{"cafe.example.com":90}' http://nginxlb:9000/api/8/http/keyvals/split

接下来,生产前测试团队验证新的应用代码已准备就绪,然后您将其部署到大型集群 1,并将比例改为 100%。这会立即将所有流量发送到集群 1,您的新应用随之“上线”,既不会中断流量或服务,也不会出现维护窗口或大量故障,亦无需重启或重新加载。只需调用一次 API,便可在您选择的时间更改精分比例。

从 90% 改为 100% 如此简单,意味着您可以轻松地将比例从 100:0 改为 50:50(甚至 0:100)。这样一来,您将得到一个热备份集群,也可以利用新资源横向扩展集群。在需求飙升时,您甚至可以使用最新软件、硬件及软件补丁构建一个全新集群,然后部署应用并分期迁移流量——不会中断任何连接!

用例

结合使用 HTTP Split Clients 模块和动态键值存储,便可实现以下用例:

  • Active-active 双活负载均衡 – 用于对多个集群进行负载均衡。
  • Active-passive 负载均衡 – 用于对主集群、备份集群和灾难恢复集群及应用进行负载均衡。
  • A/B、蓝绿和灰度测试 – 用于新的 Kubernetes 应用。
  • 横向集群扩展 – 添加更多集群资源,并可随时更改比例。
  • 无中断集群升级 – 可在升级、修补或修复一个集群的同时使用另一个集群。
  • 即时故障切换 – 如果一个集群出现严重问题,则可通过更改比例来使用另一个集群。

配置示例

以下是键值配置示例:


# 定义键值存储、备份状态文件及超时并启用同步 keyval_zone zone=split:1m state=/var/lib/nginx/state/split.keyval timeout=365d sync; keyval $host $split_level zone=split;

以下是 cafe.example.com 应用配置示例:


# 使用 TLS 为 cafe.example.com 定义 server 和 location 代码块
server {
     listen 443 ssl;
     server_name cafe.example.com;

     status_zone https://cafe.example.com;

     ssl_certificate /etc/ssl/nginx/cafe.example.com.crt;
     ssl_certificate_key /etc/ssl/nginx/cafe.example.com.key;

     location / {
     status_zone /;

     proxy_set_header Host $host;
     proxy_http_version 1.1;
     proxy_set_header "Connection" "";
     proxy_pass https://$upstream; # 精分到 upstream 代码块的流量

     }

# 定义 2 个 upstream 代码块,每个集群一个
# 由 NLK 动态管理的服务器,状态文件备份

# 集群 1 上游

upstream cluster1-cafe {
      zone cluster1-cafe 256k;
      least_time last_byte;
      keepalive 16;
      #由 NLK 控制器管理服务器
      state /var/lib/nginx/state/cluster1-cafe.state;
}

# 集群 2 上游

upstream cluster2-cafe {
      zone cluster2-cafe 256k;
      least_time last_byte;
      keepalive 16;
      #由 NLK 控制器管理服务器
      state /var/lib/nginx/state/cluster2-cafe.state;
}


上游服务器 IP:port 由 NGINX Loadbalancer for Kubernetes 进行管理。这是一款新型控制器,也使用 NGINX Plus API 来动态配置 NGINX Plus。详情请参见下一节

下面我们使用常用的监控和可视化工具 Grafana 来查看 HTTP 精分流量随时间的变化情况。您可以使用 NGINX Prometheus Exporter (基于njs)导出所有 NGINX Plus 指标,然后通过 Grafana 进行收集并绘制图表。有关 Prometheus 和 Grafana 配置的详细信息,请点击此处

图中有四个上游服务器:两个用于集群 1,两个用于集群 2。我们使用 HTTP 负载生成工具来创建 HTTP 请求,并将其发送到 NGINX Plus。

在下面的三个图表中,您可以看到初始精分比例为 50:50。

LB Upstream Requests diagram

然后,在 12:56:30 时,该比例变为 10:90。

LB Upstream Requests diagram

在 13:00:00 时,又变为 90:10。

LB Upstream Requests diagram

您可以在 NGINX Loadbalancer for Kubernetes GitHub 代码库中找到 Prometheus 和 Grafana 的工作配置。

 

动态 HTTP 上游:NGINX Loadbalancer for Kubernetes

借助 NGINX Plus API 和 NGINX Loadbalancer for Kubernetes 控制器,您可将静态 NGINX 上游配置更改为动态集群上游。这是一款免费的 Kubernetes 控制器,可监控 NGINX Ingress Controller,并自动更新针对 TCP/HTTP 负载均衡配置的外部 NGINX Plus 实例。它的设计非常简单,易于安装和操作。有了此解决方案,您便可在 Kubernetes 环境中实现 TCP/HTTP 负载均衡,确保新应用和服务能即时被检测到并可接收流量,而无需重新加载。

架构和流程

NGINX Loadbalancer for Kubernetes 位于 Kubernetes 集群内部,已在 Kubernetes 中注册,可监控 NGINX Ingress Controller (nginx-ingress) 服务。当 Ingress controller(Ingress 控制器)发生变化时,NGINX Loadbalancer for Kubernetes 会收集 Worker IP 和 NodePort TCP 端口号,然后通过 NGINX Plus API 将 IP:port 发送到 NGINX Plus。

NGINX 上游服务器无需重新加载即可更新,NGINX Plus 会将流量负载均衡到正确的上游服务器和 Kubernetes NodePort。可添加额外的 NGINX Plus 实例来实现高可用性

NGINX Loadbalancer in action

NGINX Loadbalancer for Kubernetes 用例快照

下面截图中的两个窗口显示 NGINX Loadbalancer for Kubernetes 已部署完毕并正执行其作业:

  1. service 类型 – 适用于 nginx-ingress 的 LoadBalancer
  2. 外部 IP – 连接到 NGINX Plus 服务器
  3. 端口 – NodePort 映射到 443:30158 及匹配的 NGINX 上游服务器(如 NGINX Plus 实时仪表盘所示)
  4. 日志 – 表示 NGINX Loadbalancer for Kubernetes 成功地将数据发送到 NGINX Plus

NGINX Plus window 注:在本例中,Kubernetes worker 节点为 10.1.1.8 和 10.1.1.10

添加 NGINX Plus 安全功能

随着越来越多在 Kubernetes 中运行的应用暴露在开放互联网中,必须增强安全防护。幸运的是,NGINX Plus 具有企业级安全功能,可用于创建多层深度防御架构。

有了 NGINX Plus 在集群前面执行 split_clients 函数,何不物尽其用,添加一些可靠的安全功能呢?下面列出了一些可用于增强安全防护的 NGINX Plus 功能,并提供了其他文档的链接和参考资料,可用来配置、测试及部署这些功能。

 

立即开始

如果您正苦于应对 Kubernetes 集群边缘的网络挑战,不妨试试这款 NGINX 多集群解决方案。

欢迎试用 NGINX Loadbalancer for Kubernetes 软件,并分享您的感想。这款软件是开源软件(使用 Apache 2.0 许可),所有安装说明均可在GitHub 上找到

如希望给我们提供反馈,请在 GitHub 仓库中留言,或微信添加小 N 助手(微信号:nginxoss)加入官方微信群与与我们直接交流。


"This blog post may reference products that are no longer available and/or no longer supported. For the most current information about available F5 NGINX products and solutions, explore our NGINX product family. NGINX is now part of F5. All previous NGINX.com links will redirect to similar NGINX content on F5.com."