kubernetes学习笔记23:网络访问
k8s通过pod部署应用,但是pod生命周期短暂,删除了重启之后IP地址就变了,这时需要service服务发现,对内的话对所有pod提供统一的访问入口,让pod网络暴露出去,对外的话提供统一的访问地址,包含负载均衡。
创建完成service有一个唯一的ClusterIP字段,它通过service的唯一服务名称和clusterIP地址可以被其他pod访问,并提供统一的访问入口和服务发现,不会因为pod重启了,pod的IP地址变了,就访问不到运行在容器中的应用了,比如Tomcat应用。endpoints(podIp+containerPort,比如Tomcat的8080端口,就是Dockerfile中EXPOSE出来的端口)保存所有支持服务的IP/port列表,也就是说service的selector选择哪些pod,以及pod的状态,这时service的port属性最好和pod的containerPort保持一致,不然会找不到,如果实在不一致,则定义service的yaml文件中需要指定targetPort=pod中的containerPort。
如何将port的端口号映射到node节点上:定义pod的时候除了containerPort之外,还要加上hostPort,如果不加hostPort的话,可以用hostNetwork=true,也可以映射到node节点上,这样访问容器服务的时候,就是nodeIP(开通了对外访问的节点的ExternailIP)+containerPort。
如何将service的端口号映射到node节点上:定义service的时候除了port之外,还要加上nodePort属性,type属性也要改成NodePort,这样访问service的时候就是nodeIP(开通了对外访问的节点的ExternalIP)+nodePort,另外要打通主机防火墙,让外包服务通过主机端口号能访问到内部服务,但是节点访问有2个弊端,一个就是该节点挂了,网络就不通了,还有一个就是服务一旦多起来,NodePort在每个节点上开启的端口会越来越庞大,而且难以维护,所以需要负载均衡LoadBalancer。注意不要混淆使用hostPort的pod和通过NodePort服务暴露的pod,它们是不同的,对于一个使用hostPort的pod,到达宿主节点的端口的连接被直接转发到pod对应的端口上,然而在NodePort服务中,到达宿主节点的连接将被转发到随机选取的pod上(这个pod可能在其他节点上),另一个区别是对于使用hostPort的pod,仅有运行了这类pod的节点会绑定到对应的端口,而NodePort类型的服务会在所有节点上绑定端口,即使这个节点上没有运行对应的pod,很重要一点就是如果一个pod绑定宿主节点上一个特定端口,每个宿主节点只能调度一个这样的pod实例,因为两个pod实例不能绑定宿主节点上点同一个端口,调度器会考虑的,所以不会把两个这样的pod调度到同一节点上,也就是说,假如要在3个节点上部署4个这样的pod副本,只有三个副本能够部署成功,剩余一个保持pending状态,不会被调度器调用成功。还有一种就是通过LoadBalancer映射云服务厂商提供的LoadBalancer的IP地址,这种只能针对设置service的场景。
tyoe: LoadBalancer loadBalancerIp:1.1.1.1 externaTrafficPolicy: Cluster/Local status: loadBalancer: ingress: - ip: 1.1.1.1
在集群里面,其他pod访问service方式:之间通过pod_ip和端口号访问,通过service名称和端口号访问,不同的namespace需要加上namespace,通过环境变量访问三种方式。
在集群外面,service通过nodePort(向集群节点的宿主机暴露节点端口,相当于在节点一个端口上面访问到之后再去转发到虚拟IP地址上面,就是service的IP地址)和nodeIP访问,也可以通过loadbalancer(在nodePort上做转发,就是在节点上做负载均衡,通过clusterIP和端口访问)访问,只要把service的type=NodePort改为type=LoadBalancer,k8s通过Servuce Controller自动创建一个外部LB并配置安全组供外部客户端使用,而对集群内访问,kube-proxy用iptables或ipvs实现云服务提供商LB的部分功能进行L4转发和安全规则等,终上所述,LoadBalancer包含NodePort功能,NodePort又包含ClusterIP功能。
k8s有master节点和worker节点,在master节点里面有APIserver,就是统一管理k8s所有对象的地方,所有组件都会注册到APIserver上监听对象变化,比如pod生命周期的变化,最重要组件有cloud controller manager(负责配置loadbalancer均衡器给外部使用),coredns(k8s的域名解析服务,dnsPolicy默认是ClusterFirst,有Default等选项,用来观测pod变化,并配置DNS解析,实现通过service名字访问),在每个node里有kube-proxy(配置node pod或者虚拟IP地址访问),用它实现负载均衡,是实现类,虽然通过kube-proxy可以帮助实现集群内外的pod相互通信,但是随着service的增多,nodeIP越来越多,并且kube-proxy生成的规则链也会越来越多,对Linux内核也是负担,因此引入loadbalancers,但是kube-proxy在7层网络架构中,只能限制到第四层,也就是传输层,对应用层无能为力,而且LoadBalancer需要自己提供负载均衡器,比如NGINX(使用方法就是用NGINX监听一个端口,按照域名向后转发,这种方式有个问题,就饿每次有新服务加入怎么改NGINX配置,要重启),以及独有的公有IP,而Ingress只需要公有IP,还能提供Service(只能提供session亲和性)不能提供的cookie亲和性,另外Ingress会保存客户端IP,而且通过Ingress Controller与Kubernetes API交互,动态的感知集群中Ingress规则变化,然后读取它,按照它自己模板生成一段NGINX配置再写到NGINX pod中,最后reload一下,相当于使NGINX动态的感知规则变化。所以引入ingress。