目录复制

前言

简介

k8s中将网络大致分为四种

  • Service Mesh 即服务网格,它将分布式服务的通信抽象为单独一层,在这一层中实现负载均衡、服务发现、认证授权、监控追踪、流量控制等分布式系统所需要的功能
  • service网络,是对ip的命名,相当于域名之于ip。负责服务发现,负载均衡,集群内外的端口暴露
  • pod网络,基于节点网络,为每个pod赋予一个ip,并相互之间通过这个ip组成网络
  • Node节点网络,基于真实物理机的网络,是通常意义上的网络

Node节点网络

是k8s节点之间通信的网络,一般由云厂商提供,无需我们多做处理

Pod 网络

我们的程序以容器的方式运行在k8s中,通常称之为pod,k8s为每个pod赋予一个ip,那么通过这种podip通讯,pod间性形成一个网络,我们称之为pod网络。

同一个节点

在同一个节点pod间通讯可以通过docker的网络来实现,如下图

  • eth0:节点的网卡,负责节点与节点之间的通讯
  • docker0 :虚拟网桥,简单理解为虚拟交换机负责pod间通讯
  • veth0: pod1 的虚拟网卡 支持pod内 容器间通讯,如图三个容器共享这个网卡,他们可以通过localhost相互访问。veth0的id是由docker0来分配
  • pause:负责容器间共享网络,参考docker的container网络模式
    在这里插入图片描述

不同节点

k8s首先对pod的ip进行统一管理,确保ip按照一定规则分配,如图的172.17.0.2172.17.1.3

在这里插入图片描述
上图中?的部分负责连通两个节点,只要它能够根据podip进行网络转发,那么就可以实现pod间网络通讯。基于此有两种方法

路由方案

在节点之间增加一个路由器,并配置其根据podip转发流量到对应机器,如下图:

  • 性能开销比较小
    在这里插入图片描述

覆盖网络

在不改变路由器的情况下,通过隧道封包的技术,先组建虚拟网络,再基于这个虚拟网络建设pod网络。常用的工具有flannel,weavenet等,如下图

隧道封包
- 在流量包从节点发出之前,先将流量包封装成一个新的流量包,并将ip指定为对应节点ip
- 在接收到流量包后,先将流量包解封成原本的样子,再进行后续操作
  • 虽然这样去掉了对底层网络设备的依赖,但是却会增加额外的性能开销(封包解包等)
    在这里插入图片描述

CNI

k8s在设计的时候,允许通过CNI(container network interface)这种plugin的方式解耦底层网络。
也就是说,具体如何组网由插件来实现,kubelet在进行创建和删除pod的时候,调用组件进行网络处理。
CNI 这种pod网络集成标准 简化了不同网络技术和k8s之间的集成
在这里插入图片描述

Service

我们的服务通常以deployment的方式部署在k8s中,有多个pod运行这个应用程序。所有对服务的发现与负载是极为重要的,service就负责解决这个问题。
k8s通过对服务进行抽象,来解决上述问题。
如下图,我们部署了一个account服务,通过抽象一个ClusterIp(虚拟ip)来解决服务发现与负载问题。

  • client不需要知道具体的podid,只需要知道clusterip(account-service)就可以访问这个服务
  • podip是不固定的,随着pods伸缩而改变,cluster会监控这些变化,并向client屏蔽掉这些变化。
    在这里插入图片描述

service网络原理

k8s中每个slave节点都部署两个组件 kubelet和kubeproxy,它们和master节点共同实现了service,流程大致如下

  • kubelet在创建pod时,会将这个pod的ip列表发送给master
  • 创建service时,master会给service分配一个虚拟ip clusterip,同时对应一个serviceName
  • master会将这个service的信息发送给每个节点的kubeproxy,kubeproxy会将这个clusterIp->podip的对应关系通过节点的iptables写入到netfilter中
  • 当一个pod想访问另一个pod的时候,只知道serviceName,先通过serviceName拿到clusterip,然后根据这个ip发送请求
  • 流量在经过netfilter的时候,改变clusterip为真实的podip,然后经过pod网络发出去
    如下图:
    在这里插入图片描述

service的四种类型

1 ClusterIP

上面我们理解的service都是ClusterIP的方式,即集群内部应用间的相互访问。

2 NodePort

当集群外的应用想要访问集群内的服务时,service需要开放节点端口(30000~32767)给外部服务,并将这个端口和内部服务端口映射起来。
如下图,端口实际是通过kubeproxy开放出去的
在这里插入图片描述

2 LoadBalancer

一般来说云厂商会提供k8s服务的时候也会提供负载均衡,LoadBalancer类型的service就是和云厂商的负载均衡配套的。

3 ExternalName

ExternalName 类型的service,是将外部的域名映射到集群中来。
比如有个一个数据库mysql,它的地址是我们不想暴露出来的,可以将这个数据库的域名映射成我们集群内部的域名mysql001,在pod中,使用这个修改后的域名访问mysql数据库

Ingress

为了对流量代理转发,k8s中定义了ingress这种资源描述。ingress指明了集群中的网关应该通过怎样的规则进行代理,如下图:

  • ingress并不具备代理分发功能,需要部署nginx-ingress来负载真正的流量,所有我们可以自己实现ingress,从而做更复杂的操作,如鉴权,过滤,限流,熔断等等。
    在这里插入图片描述

kube proxy

kube-proxy负责节点网络的代理转发,是k8s网络中最重要的一环,它的实现过程经历了这样三个阶段。

usespace

早期的k8s中,clusterip到podip的流量转发是由kubeproxy来完成的。大致过程如下图:

  • kubeproxy 会设置netfilter 将指定clusterip的流量转发给自己,然后由kubeproxy自身来负载均衡到对应的pod
  • netfilter:linux提供的一种钩子hooks,所有经过网卡的流量都会经过netfilter。

在这里插入图片描述

iptables

由于usespace方式,会将流量从内核转发到kubeproxy工作的用户空间,所以性能并不是很理想。
后来k8s通过iptables设置netfilter,将指定clusterip的流量直接转发出去,不再经过用户空间,如下图:
在这里插入图片描述

IPVS

在大规模集群(例如10,000个服务)中,iptables 操作会显着降低速度。
在k8sv1.11版本之后,使用IPVS 模式,IPVS 专为负载平衡而设计,并基于内核内哈希表实现,可以大大减少同步路由规则的开销。
因此,可以通过基于 IPVS 的 kube-proxy 在大量服务中实现性能一致性。同时,基于 IPVS 的 kube-proxy 具有更复杂的负载平衡算法(最小连接,局部性,加权,持久性)。

service mesk

ingress+service 对于一般性的服务网络需求已经足够支持了,但是对于更复杂的网络需求就难以处理了,比如更精细的流量控制,无侵入的监控,grpc这样的长链接负载等。于是service mesk 应运而生,他在pod网络之上又抽象出一层,用于解决上述的问题。

未完待续。。。

其他

服务调试

我们部署在k8s中的应用,如果我们想远程调试它,可以通过以下方式。

proxy

kubectl 具有反向代理功能,通过如下命令,代理端口到集群

kubectl proxy --port=[port]
port-forward

想要将pod或者service的端口映射出来,可以使用如下命令:

kubectl port-forward POD [LOCAL_PORT:]REMOTE_PORT [...[LOCAL_PORT_N:]REMOTE_PORT_N] [options]

如我想访问testname命名空间下的名字为testapp的service的8000端口

kubectl -n testname port-forward services/testapp 8000
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐