一、介绍
k8s不提供网络通信,提供了CNI接口(Container Network Interface,容器网络接口),由CNI插件实现完成。
1.1 Pod通信
1.1.1 同一节点Pod通信
Pod通过虚拟Ethernet接口对(Veth Pair)与外部通信,Veth像一根网线,一端在Pod内部,一端在Pod外部。同一节点内的Pod通过网桥通信,如下图:veth的另一端连接到网桥,IP地址通过网桥动态获取,与网桥在同一网段,网桥负责转发所有非本地的流量,实现Pod内的互相访问。
1.1.2 不用节点Pod通信
k8s集群内不同节点访问Pod,需要保证Pod ip唯一,所以会给每个节点分配不同的IP,Pod通过网桥获取ip,从而保证Pod IP唯一。在不同节点Pod通过IP互相访问,网络插件大致分成三类:
Overlay模式、路由模式、Underlay模式三类。
- Overlay模式(独立网络)是在节点网络基础上通过隧道封装构建的独立网络,拥有自己独立的IP地址空间、交换或者路由的实现。VXLAN协议是目前最流行的Overlay网络隧道协议之一。
- 路由模式 采用VPC路由表的方式与底层网络相结合,能够更加便捷地连接容器和主机,在性能上会优于Overlay的隧道封装。
- Underlay模式 (直接访问Pod内部网卡)是借助驱动程序将节点的底层网络接口直接暴露给容器使用的一种网络构建技术,享有较高的性能,较为常见的解决方案有IP VLAN等。
二、Service
2.1 作用:解决Pod的访问问题
1、Pod可能被Deployment重建删除,造成Pod的Ip变化。
2、Pod的Ip只有在服务启动后才会被分配,无法预知。
3、一个镜像最后会变成多个Pod,Pod访问需要随机策略。
举个例子,假设有这样一个应用程序,使用Deployment创建了前台和后台,前台会调用后台做一些计算处理,如图1所示。前台一个Pod,后台运行了3个Pod,这些Pod是相互独立且可被替换的,当Pod出现状况被重建时,新建的Pod的IP地址是新IP,前台的Pod无法直接感知。
2.1 使用Service解决Pod的访问问题
k8s的Service就是为了解决Pod访问的问题而设计的。Service有一个固定的IP,Service流量转发给Pod,具体转发给哪些Pod由Label标签选择。Service可以给这些Pod做负载均衡。
添加Service后访问后,Pod访问如下图:
2.2 创建Service yaml示例
2.2.1 创建Deployment
创建一个3副本的Deployment,即3个Pod,且Pod上带有标签“app: nginx”,具体如下所示。
2.3 创建Service
创建一个名为“nginx”的Service,通过selector选择到标签“app:nginx”的Pod,目标Pod的端口为80,Service对外暴露的端口为8080。
访问服务只需要通过“服务名称:对外暴露的端口”接口,对应本例即“nginx:8080”。这样,在其他Pod中,只需要通过“nginx:8080”就可以访问到“nginx”关联的Pod。
执行创建指令
下面创建一个Pod并进入容器,使用ClusterIP访问Pod,可以看到能直接返回内容。
2.4 使用ServiceName访问Service
在创建CCE集群的时候,会默认要求安装CoreDNS插件,在kube-system命名空间下可以查看到CoreDNS的Pod。CoreDNS安装成功后会成为DNS服务器,当创建Service后,CoreDNS会记录Service的名称与IP,这样Pod就可以通过向CoreDNS查询Service名称获得Service的IP地址。
访问时通过nginx.<namespace>.svc.cluster.local访问,nginx为Service的名称,<namespace>为命名空间名称,svc.cluster.local为域名后缀,在实际使用中,在同一个命名空间下可以省略<namespace>.svc.cluster.local,直接使用ServiceName即可。
例如上面创建的名为nginx的Service,直接通过“nginx:8080”就可以访问到Service,进而访问后台Pod。
2.5 Service是如何做到服务发现的
kubectl describe命令查看Service的信息。
可以看到一个Endpoints,Endpoints同样也是Kubernetes的一种资源对象,可以查询得到。Kubernetes正是通过Endpoints监控到Pod的IP,从而让Service能够发现Pod。
172.16.2.132:80是Pod的IP:Port,通过如下命令可以查看到Pod的IP,与上面的IP一致。
如果删除一个Pod,Deployment会将Pod重建,新的Pod IP会发生变化。
再次查看Endpoints,会发现Endpoints的内容随着Pod发生了变化。
下面进一步了解这又是如何实现的。
Service的访问都是通过kube-proxy实现的,当一个Service创建时,API Server会通知所有的kube-proxy,kube-proxy将Service的ip和端口记录到iptables内,当节点内的Pod访问其他节点内的Pod时,通过iptable将目的地的ip:pord替换为真实的ip:pord,从而实现Service访问到Pod。kube-proxy还会记录Serivce和Endpoints的ip变化
2.6 Service的类型和使用场景
Service的类型有:ClusterIP、NodePort、LoadBalancer和Headless Service,这几种类型的Service有着不同的用途。
- ClusterIP:用于在集群内部互相访问的场景,通过ClusterIP访问Service。
- NodePort:用于从集群外部访问的场景,通过节点上的端口访问Service,详细介绍请参见NodePort类型的Service。
- LoadBalancer:用于从集群外部访问的场景,其实是NodePort的扩展,通过一个特定的LoadBalancer访问Service,这个LoadBalancer将请求转发到节点的NodePort,而外部只需要访问LoadBalancer,详细介绍请参见LoadBalancer类型的Service。
- Headless Service:用于Pod间的互相发现,该类型的Service并不会分配单独的ClusterIP, 而且集群也不会为它们进行负载均衡和路由。您可通过指定spec.clusterIP字段的值为“None”来创建Headless Service,详细介绍请参见Headless Service。
2.6.1 NodePort类型的Service
NodePort类型的Service可以让Kubernetes集群每个节点上保留一个相同的端口, 外部访问连接首先访问节点IP:Port,然后将这些连接转发给服务对应的Pod。如下图所示。
创建一个NodePord类型Service的yaml
创建后查看Pod列映射
此时,通过节点IP:端口访问Service可以访问到Pod,如下所示。
2.6.2 LoadBalancer类型的Service
LoadBalancer是NodePort的扩展。通过LB访问Service,LB将请求转发到NodePort。
下面是一个创建LoadBalancer类型的Service。可以通过ELB的IP:Port访问到后台Pod。
2.7 Headless Service
HeadLess Service解决了如下两个问题:
- 同时访问所有Pod
- 一个Service内部的Pod互相访问
Headless Service并不会分配单独的ClusterIP,在进行DNS查询时会返回所有Pod的DNS记录,这样就可查询到每个Pod的IP地址。有状态负载(StatefulSet)中StatefulSet正是使用Headless Service解决Pod间互相访问的问题。
创建完成后可以查询Service。
# kubectl create -f headless.yaml
service/nginx-headless created# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-headless ClusterIP None <none> 80/TCP 5s
创建一个Pod来查询DNS,可以看到能返回所有Pod的记录,这就解决了访问所有Pod的问题了。
三、Ingress
Service是基于四层TCP和UDP协议转发的,而Ingress可以基于七层的HTTP和HTTPS协议转发,可以通过域名和路径做到更细粒度的划分,如下图所示。
3.1 Ingress工作机制
要想使用Ingress功能,必须在Kubernetes集群上安装Ingress Controller。Ingress Controller有很多种实现,最常见的就是Kubernetes官方维护的NGINX Ingress Controller;
外部请求首先到达Ingress Controller,Ingress Controller根据Ingress的路由规则,查找到对应的Service,进而通过Endpoint查询到Pod的IP地址,然后将请求转发给Pod。
3.2 创建Ingress
Ingress中还可以设置外部域名,这样您就可以通过域名来访问到ELB,进而访问到后端服务。
3.3 路由到多个服务
Ingress可以同时路由到多个服务,配置如下所示。
- 当访问“http://foo.bar.com/foo”时,访问的是“s1:80”后端。
- 当访问“http://foo.bar.com/bar”时,访问的是“s2:80”后端。