其实操作到这里,有必要深入的了解K8s的网络运行机制和基本结构,否则当真的遇到问题的时候会比较郁闷。

首先,要理解K8s的用处其实是容器的编排和管理,最小组成其实不是容器,是pod,物理机或者虚拟机叫node,pod是基础单元,pod里可以有多个容器,也可以只有一个容器,同一个pod的容器彼此是共享网络和主机配置的,换句话说,彼此是可以直接localhost通信的,类似于同一台机器上进行通信,所以这里面是无所谓隔离和安全一说,对外而言就是一个环境,所以pod就是这个环境的业务实体。所以,第一个问题来了,同一个pod的不同容器可以位于不同的node上吗?当然不行,必须在同一个node上,因为共享主机和网络。那么怎么才能知道一个pod有多个容器?kubectl exec的时候是否可以指定需要运行的容器?当然可以,参考如下指令:

# 查看一个pod中有哪些容器,例如查看pod/coredns-fb8b8dccf-gf7hr下的容器镜像

$ kubectl get pod coredns-fb8b8dccf-gf7hr -n kube-system -o jsonpath="{$.spec.containers[*].image} {$.spec.containers[*].name}"

k8s.gcr.io/coredns:1.3.1 coredns

# 所以这个pod里有一个容器,镜像是k8s.gcr.io/coredns:1.3.1, 名子是coredns

# 这个和docker ps查看到的docker container 的name是不一致的,需要注意

# 进入pod中的特定容器,如果只有一个容器则默认进入第一个,否则需要指定一个容器来进入

$ kubectl exec POD [-c CONTAINER] -- COMMAND [args...]

# 进入coredns的容器

$ kubectl -n kube-system exec -it coredns-fb8b8dccf-gf7hr -c coredns /bin/bash

所以,这里可以忽略容器的概念,单单考虑pod,毕竟pod才是k8s最小的调度单元。那pod和pod是怎么通信的呢?

pod和pod之间的通信

pod的通信离不开K8s的网络模型:

pod上的container之间的通信

同一个pod内部的容器通信.jpg

pod和pod在同一个node

同一个node内的不同pod通信.jpg

pod和pod在不同的node

不同node内的不同pod通信.jpg

flannel到底做了什么?

flannel组建一个大二层扁平网络,pod的ip分配由flannel统一分配,通讯过程也是走flannel的网桥。

每个node上面都会创建一个flannel0虚拟网卡,用于跨node之间通讯。所以容器直接可以直接使用pod id进行通讯。

跨节点通讯时,发送端数据会从docker0路由到flannel0虚拟网卡,接收端数据会从flannel0路由到docker0。

为什么会有Service?

如果Pod是一组应用容器的集合,那Service是不是就没有意义了,他的意义在于当应用服务需要做负载、需要做全生命周期的跟踪和管理时就体现出来了,所以Service是一个抽象的概念,它定义了Pod逻辑集合和访问这些Pod的策略。

一个非常常见的场景,当一个Pod因为某种原因停止运行了,kubelet根据deployment的需求重新启动一个新的Pod来提供之前Pod的功能,但是flannel会给这个新的Pod分配一个新的IP,这会带来很大的Effort,应用服务的很多配置项都需要调整,如果有了Service呢,这就不是问题,看下Service的运行原理。

k8s网络通信原理.jpg

KubeProxy的实现模式

这张图解释了Service的运行机制,当Service A创建的时候,Service Controller和EndPoints Controller就会被触发更新一些资源,例如基于Service中配置的Pod的selector给每一个Pod创建一个EndPoint资源并存入etcd,kube-proxy还会更新iptables的chain规则生成基于Service的Cluster IP链路到对应Pod的链路规则,接下来集群内的一个pod想访问某个服务,直接cluster ip:port即可基于iptables的链路将请求发送到对应的Pod,这一层有两种挑选pod的算法,轮询(Round Robin)和亲和度匹配(Session Affinity)。当然,除了这种iptabels的模式,还有一种比较原始的方式就是用户态的转发,Kube-Proxy 会为每个 Service 随机监听一个端口 (Proxy Port),并增加一条 IPtables 规则。从客户端到 ClusterIP:Port 的报文都会被重定向到 Proxy Port,Kube-Proxy 收到报文后,通过 Round Robin (轮询) 或者 Session Affinity(会话亲和力,即同一 Client IP 都走同一链路给同一 Pod 服务)分发给对应的 Pod。

当然,新版本的k8s开始基于ipvs来替换iptables了,但是形式和iptables是类似的。

概念图可以参看:

UserSpace

这是最原始的方式,参看下图:

userspace方式.jpg

Iptables

iptables方式.jpg

Ipvs

IPVS是 LVS 项目的一部分,是一款运行在 Linux Kernel 当中的 4 层负载均衡器,性能异常优秀。使用调优后的内核,可以轻松处理每秒 10 万次以上的转发请求。目前在中大型互联网项目中,IPVS 被广泛的用于承接网站入口处的流量。

参考资料

Logo

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

更多推荐