亚马逊AWS官方博客

在 Amazon EKS 上利用 Nginx ingress mirror 功能实现流量复制

在某些情况下,我们希望将 Amazon EKS 中的流量复制到其他 EKS 集群或 Kubernetes 集群,以实现流量分发和复制的目的。以下是一些常见的场景:

  1. 测试新版本:在部署新版本的应用程序时,可以将生产流量复制到测试环境中的新版本应用程序,以测试其性能和稳定性,同时不会影响生产环境应用。
  2. 故障分析:当需要进行数据分析或故障排除时,可以将流量复制到测试环境中,以进行更有效的排错分析。此时,可以在测试环境中运行特定的工具或添加调试信息来帮助解决问题,而不会影响生产环境。
  3. 迁移/容量规划:当需要进行迁移或评估应用程序的容量时,可以将流量发送到不同的目标进行基准测试和性能分析。此时,可以通过将流量复制到测试环境中,来模拟不同的负载和流量模式,并分析测试结果来进行容量规划或迁移决策。

通过 Nginx Ingress 中的 mirror 功能,可以很方便的将请求镜像到其他的环境中,Mirror 目标的响应将被忽略,此功能非常有用,可以查看请求在“测试”后端中的反应。

在本文中,我们将部署两个 EKS 集群用于演示 Nginx mirror 的效果,EKS-Source-Cluster 用作源集群,EKS-Destination-Cluster 用作目标集群,两个集群均部署 nginx-ingress 及 httpbin 应用用于测试。

前提条件

本文使用环境信息如下,不同版本配置会有差异:

Amazon EKS: 1.25

Nginx-ingress:v1.7.0

AWS Load Balancer Controler: v2.5.1

在两个 EKS 集群中部署 aws load balancer controller,可以参考链接:https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/aws-load-balancer-controller.html

分别在两个 EKS 集群中部署Nginx-ingress:

方案部署步骤

helm upgrade --install ingress-nginx ingress-nginx \ 
    --repo https://kubernetes.github.io/ingress-nginx \ 
    --namespace ingress-nginx --create-namespace

查看目标集群 EKS-Destination-Cluster 中 nginx-ingress 的 external-ip 并记录下来:

$ kubectl get svc -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP       EXTERNAL-IP                                                               PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   172.20.246.159   a3fa8caf2f1ee4427852c0c9dc1d4249-1800757104.us-east-1.elb.amazonaws.com   80:30606/TCP,443:31247/TCP   29m
ingress-nginx-controller-admission   ClusterIP      172.20.129.253   <none>                                                                                                                               

在两个 EKS 集群中部署 httpbin 应用:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin
spec:
  selector:
    matchLabels:
      app: httpbin
  replicas: 1
  template:
    metadata:
      labels:
        app: httpbin
    spec:
      containers:
      - name: httpbin
        image: kennethreitz/httpbin
        ports:
        - containerPort: 80

在两个 EKS 集群中部署 httpbin-svc:

apiVersion: v1
kind: Service
metadata:
  name: httpbin-svc
spec:
  selector:
    app: httpbin
  type: ClusterIP
  ports:
  - name: http
    port: 80
    targetPort: 80

在 Amazon EKS 上部署 ingress 资源

创建 mirror-source-ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: httpbin-source-ingress
  annotations:
    # 指定使用nginx-ingress
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
    # mirror-target填入EKS-Destination-Cluster的nginx-ingress external-ip域名
    nginx.ingress.kubernetes.io/mirror-target: https://a3fa8caf2f1ee4427852c0c9dc1d4249-1800757104.us-east-1.elb.amazonaws.com/$request_uri
spec:
  rules:
  # host填入EKS-Source-Cluster的nginx-ingress external-ip域名
  - host: a1008e8ef462544b9ba6fb7e68352f7d-92988604.us-east-1.elb.amazonaws.com
    http:
      paths:
      - path: /httpbin
        pathType: Prefix
        backend:
          service:
            name: httpbin-svc
            port:
              name: http

源集群 EKS-Source-Cluster 中创建 httpbin-source-ingress:

kubectl apply -f mirror-source-ingress.yaml
$ kubectl get ingress
NAME              CLASS    HOSTS                                                                   ADDRESS   PORTS   AGE
httpbin-ingress   <none>   a1008e8ef462544b9ba6fb7e68352f7d-92988604.us-east-1.elb.amazonaws.com             80      10s

创建 mirror-destination-ingress.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: httpbin-destination-ingress
  annotations:
    # 指定使用nginx-ingress
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  # host填入EKS-Destination-Cluster的nginx-ingress external-ip域名
  - host: a3fa8caf2f1ee4427852c0c9dc1d4249-1800757104.us-east-1.elb.amazonaws.com
    http:
      paths:
      - path: /httpbin
        pathType: Prefix
        backend:
          service:
            name: httpbin-svc
            port:
              name: http

目标集群 EKS-Destination-Cluster 中创建 httpbin-destination-ingress:

kubectl apply -f mirror-source-ingress.yaml
$ kubectl get ingress
NAME                     CLASS    HOSTS                                                                   ADDRESS   PORTS   AGE
httpbin-source-ingress   <none>   a1008e8ef462544b9ba6fb7e68352f7d-92988604.us-east-1.elb.amazonaws.com             80      5s

注释:nginx.ingress.kubernetes.io/mirror-target: https://a3fa8caf2f1ee4427852c0c9dc1d4249-1800757104.us-east-1.elb.amazonaws.com/$request_uri 可以把所有该 ingress 的请求都转发到 a3fa8caf2f1ee4427852c0c9dc1d4249-1800757104.us-east-1.elb.amazonaws.com 上。

验证 mirror 效果

访问 httpbin-source-ingress:

curl http://a1008e8ef462544b9ba6fb7e68352f7d-92988604.us-east-1.elb.amazonaws.com/httpbin

EKS-Destination-Cluster 中查看 nginx-ingress 是否接收到 mirror 过来的请求:

kubectl logs --tail=0 -f ingress-nginx-controller-6b8bfd7f69-8jb7d -n ingress-nginx

其他配置项

默认情况下,请求正文被发送到镜像后端,但可以通过应用以下命令将其关闭:

nginx.ingress.kubernetes.io/mirror-request-body: "off"

默认情况下,镜像请求的标头 Host 将设置为与 mirror-target 注释中 uri 的主机部分相同,可以通过 mirror-host 注释来覆盖它:

nginx.ingress.kubernetes.io/mirror-host: "test.env.com"

总结

使用 Nginx ingress mirror 功能在 AWS EKS 集群上实现流量复制可以帮助我们更有效地进行性能测试、问题排查和功能开发。在不影响生产环境的前提下,我们可以在镜像环境中不断接收和分析实际流量。本文提供了在 EKS 集群上实现这一功能的详细步骤,希望能为您的开发提供帮助。

参考链接

https://kubernetes.github.io/ingress-nginx/deploy/

https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/aws-load-balancer-controller.html

https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#mirror

本篇作者

陈嘉俊

亚马逊云科技解决方案架构师,目前主要负责帮客户进行云架构设计和技术咨询,对容器化等技术方向有深入的了解。