在某些情况下,我们希望将 Amazon EKS 中的流量复制到其他 EKS 集群或 Kubernetes 集群,以实现流量分发和复制的目的。以下是一些常见的场景:
- 测试新版本:在部署新版本的应用程序时,可以将生产流量复制到测试环境中的新版本应用程序,以测试其性能和稳定性,同时不会影响生产环境应用。
- 故障分析:当需要进行数据分析或故障排除时,可以将流量复制到测试环境中,以进行更有效的排错分析。此时,可以在测试环境中运行特定的工具或添加调试信息来帮助解决问题,而不会影响生产环境。
- 迁移/容量规划:当需要进行迁移或评估应用程序的容量时,可以将流量发送到不同的目标进行基准测试和性能分析。此时,可以通过将流量复制到测试环境中,来模拟不同的负载和流量模式,并分析测试结果来进行容量规划或迁移决策。
通过 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
本篇作者