第11章 流量路由Ingress(二)
11.2 场景化需求
11.2.1 多入口访问Ingress
Nginx Ingress Controller和其入口SLB是解耦,若要增删改查Ingress,控制器就会去配置Nginx,但不会影响入口SLB。所以我们可以通过创建多个入口SLB的方式(即LoadBalance类型的Service),把Ingress暴露在集群之外。
为了节约SLB的费用,可以将Ingress入口SLB改成内网类型,然后手动在SLB上绑定一个弹性公网IP地址,这样内网和外网都可以访问Ingress,同时只需要一个SLB。
11.2.2 部署多套Ingress Controller
有时需要部署多套Ingress Controller,一套给VPC内网使用,另一套给公网使用。
若集群有多套Ingress控制器,在创建Ingress的时候,怎么区分由哪一个控制器来配置Ingress呢?那就要通过IngressClass来区分。
部署Ingress Controller的时候,会传入一个–ingress-class来标记控制器,然后在创建Ingress的时候,通过在Annotation中加入kubernetes.io/ingress.class参数,Ingress控制器将kubernetes.io/ingress.class参数的值和设定的 –ingress-class的值相比较,如匹配得上,则由自己来负责配置Ingress,如匹配不上,则忽略这个Ingress,同时,日志中会打印出类似“ignoring add fot ingress test-second-nginx based on annotation kubetnetes.io/ingress.class with value”这样的记录。
当然,集群会有默认的控制器,如果Ingress并未添加kubernetes.io/ingress.class这个注解,则由默认的控制器来解析ingress。此外,新的控制器也会有自己的一套“nginx-configuration”,用于对Ingress-nginx的全局配置。
11.3 获取客户端真实IP地址
11.3.1 理解客户端真实IP地址的传递过程
以阿里的K8s为例,最简单的访问链路是:client->SLB->Ingress-nginx->Pod。分两种情况说明:
第一种情况:SLB配置为四层(默认),如下图所示。
(1)第1步,通过客户端访问SLB,源IP地址为1.1.1.1,假设源端口为随机端口42000,目的IP地址为SLB的IP地址2.2.2.2,目的端口为80。
(2)第2步,Ingress-nginx收到来自SLB的报文,源IP地址为1.1.1.1,源端口为42000,目的IP地址为3.3.3.3,目的端口为80.即Ingress-nginx”看到”的是Client在访问自己,而非SLB,因此Ingress-nginx能获取到客户端的真实IP地址,无须做任何配置改动。
接着Ingress-nginx会将客户端真实IP地址放在X-Real-IP和X-Forward-For这两个Header里传给Pod。虽然Ingress-nginx的remote-addr也会存放客户端真实的IP地址,但remote-addr并不会作为Header传递下去,Pod中不能以此Header作为获取客户端IP地址的方式。
为了简化原理,第2步省去了SLB转发给节点,再由节点转发给Ingress-nginx的中间环节,事实上,某些情况下SLB也确实能直接转发给Pod,不经过节点。
第二种情况:SLB配置为七层,如下图所示。此种情况下,Client发请求到SLB,SLB会将Client的IP地址放到X-Forwarded-For(阿里云的SLB七层监听默认开启了X-Forwarded-For)这个Header里,然后传递给Ingress-nginx。而Ingress-nginx收到请求报文的源IP地址是SLB内部的IP地址,因此默认情况下,Ingress-nginx会将SLB的内部IP地址视为客户端真实IP地址,需要配置Ingress-nginx来开启X-Forwarded-For特性。
下面来说明开启X-Forearded-For后,X-Forwarded-For的传递过程。
(1)第1步,一级代理Tenginx收到Client的请求,Tenginx会将Client的IP地址“append”到X-Forward-For中(此时看到的就是:“X-Forwarded-For:1.1.1.1″)并且将此Header一起发送给二级代理Ingress-nginx。
(2)第2步,二级代理Ingress-nginx收到请求,会继续将前一级代理的IP地址(这里是2.2.2.2)”append“到X-Forwarded-For中(此时看到的是”X-Forwarded-For:1.1.1.1,2.2.2.2″)并将此Header通过请求一并发送到Pod。这里有两点要注意:每经过一层代理,Nginx都会把前一级的IP地址“append”到X-Forward-For中,而不是直接覆盖;“append”意为追加,即把前一级的IP地址追加到后面,所以无论经过多少级代理,Client的真实IP地址都是放在X-Forwarded-For中的第一个IP地址。
11.3.2 ExternalTrafficPolicy的影响
ExternalTrafficPolicy字段通常出现在LoadBalancer类型的服务中,它有两个值:Local和Cluster。下面用两张图解释一下LocalBalancer类型的服务中,它有两个值:Local和Cluster。下面用两张图解释一下Local和Cluster的区别,如下图所示。
在Local模式下,SLB会将流量发往Pod所在的节点,即节点1和节点3,然后转发到本节点的Pod上。
在Cluster模式下,SLB会将流量随机转发到任意一个Worker节点,然后Worker节点再随机转发到其中一个Pod上,既可能是转发到本届点的Pod上,有可能是转发到其他节点的Pod上。跨节点转发是由SNAT实现的,而SNAT会修改掉报文的Source IP地址,Pod收到的报文的Source IP地址就是节点的IP地址,这样就把前一级的真实IP地址替换掉了。前面讲过,SLB再四层的情况下,Client的真实IP地址是透传(不经过代理修改,直接转发)的。因此,Ingress-nginx无法获取客户端的真实IP地址。
11.3.3 如何获取客户端真实IP地址
根据上节所讲,需要将ExternelTrafficPolicy的值设置为Local,才能保证Ingress-nginx可以获取客户端的真实IP地址。这里分两种情况。
(1)SLB为四层转发时,Ingress-nginx可以正确获取到客户端真实IP地址,不需要做任何改动,Pod需要从Header里获取客户端真实IP地址。
(2)SLB为七层转发时,Tenginx会将客户端真实IP地址放到X-Forwarded-For里,同样,Ingress-nginx也会添加Tenginx的IP地址到X-Forwarded-For并传递给Pod。当Tenginx前面有多层代理时也是一样的。同时,我们需要再SLB和Ingress-nginx上开启X-Forwarded-For。SLB默认开启,Ingress-nginx开启X-Forwarded-For需要修改nginx-configuration,在data中添加:
use-forwarded-headers: “true”
compute-full-forwarded-for: “true”
forwarded-for-header: X-Forwarded-For
11.4 白名单功能
Nginx Ingress Controller官方网站给出了Ingress白名单配置的一般方法:
-通过Annotation配置单个Ingress,作用范围时本Ingress,对应的Annotation: nginx.ingress.kubernetes.io/whitelist-source-range,值填写CIDR,用逗号分隔符分割,如“192.168.0.0/24,10/0/0/10”。
-配置到nginx-configuration里,作用范围为全局,参数:whitelist-source-range。要说明的一点是,全局参数会被Annotation的设置覆盖。
Ingress白名单的原理是判断客户端真实IP地址是否在白名单列表里,所以Ingress-nginx能否正确获取客户端的真实IP地址,是白名单能否生效的关键。因此,只要解决了Ingress-nginx如何获取客户端真实IP地址的问题,那么Ingress白名单问题就迎刃而解。
前面讲了Ingress-nginx无法获取客户端真实IP地址的一些典型场景,比如:nginx-ingress-lb的ExternalTrafficPolicy是Cluster,需要改为Local;nginx-ingress-lb的SLB是七层的,需要手动设置X-Forwarded-For;nginx-ingress-lb前面还存在代理等。前面已经讲过如何获取客户端真实IP地址,这里不再赘述。
Ingress-nginx的新版本实现比较简单,Ingress控制器直接在nginx.conf的location下面添加:
allow 110.110.0.0/24
deny all;
© 著作权归作者所有,转载或内容合作请联系作者
没有回复内容