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

在本文中,我们将部署两个 EKS 集群用于演示 Nginx mirror 的效果,EKS-Source-Cluster 用作源集群,EKS-Destination-Cluster 用作目标集群,两个集群均部署 nginx-ingress 及 httpbin 应用用于测试。
# **前提条件**
本文使用环境信息如下,不同版本配置会有差异:
[Amazon EKS](https://aws.amazon.com/cn/eks/?trk=cndc-detail): 1.25
Nginx-ingress:v1.7.0
Amazon Load Balancer Controler: v2.5.1
在两个 EKS 集群中部署 Amazon Load Balancer Controller,可以参考链接:
https\://docs.aws.amazon.com/zh_cn/eks/latest/userguide/aws-load-balancer-controller.html?trk=cndc-detail
分别在两个 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?trk=cndc-detail
可以把所有该 ingress 的请求都转发到
[a3fa8caf2f1ee4427852c0c9dc1d4249-1800757104.us-east-1.elb.amazonaws.com](a3fa8caf2f1ee4427852c0c9dc1d4249-1800757104.us-east-1.elb.amazonaws.com?trk=cndc-detail ) 上。
# **验证 mirror 效果**
访问 httpbin-source-ingress:
```
curl http\\://a1008e8ef462544b9ba6fb7e68352f7d-92988604.us-east-1.elb.amazonaws.com/httpbin
```
在 **EKS-Destination-Cluste**r 中查看 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 功能在 [Amazon EKS](https://aws.amazon.com/cn/eks/?trk=cndc-detail) 集群上实现流量复制可以帮助我们更有效地进行性能测试、问题排查和功能开发。在不影响生产环境的前提下,我们可以在镜像环境中不断接收和分析实际流量。本文提供了在 EKS 集群上实现这一功能的详细步骤,希望能为您的开发提供帮助。
# **参考链接**
https\://kubernetes.github.io/ingress-nginx/deploy/?trk=cndc-detail
https\://docs.aws.amazon.com/zh_cn/eks/latest/userguide/aws-load-balancer-controller.html?trk=cndc-detail
https\://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#mirror?trk=cndc-detail
### **本篇作者**

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