k8s网络模型 k8s三种网络模式
K8s中pod的数据通讯
记得加上 -nk8s的网络通讯方式
k8s网络模型 k8s三种网络模式
k8s网络模型 k8s三种网络模式
因此,为了实现以上两个需求,K8s提供了CNI(Container Network Intece)供第三方实现从而进行网络管理。由此出现了一系列开源的Kubernetes中的网络插件与方案,包括:flannel,calico,cilium等等。这些网络插件集中解决了以下需求:
k8s的网络模型定是所有Pod都在一个可以直接联通的扁平的网路空间,我们需要自己实现这个网络设,将不同上的Docker容器之间的互相访问先打通,然后运行K8s。
同一个Pod内的多个容器: 同一个pod共享一个网络命名空间,共享同一个linux协议栈
同一个各pod之间的通讯: 通过docker0网桥直接发送数据,不通过flannel
pod与serv之间的通讯: 各的iptables规则。
pod到外网: pod向外网发送请求,查找路由表转发数据包到宿主机的网卡,宿主机网卡完成路由选择后,iptables执行Masquerade,把源IP更改为著网卡的IP,然后向外网发送请求。
一个覆盖网络(OverlayNetwork),通过这个覆盖网络,将数据包原封不动传递到目标容器内部。
不同这里的etcd与flannel的关系:的pod之间的访问:
etcd中每个pod的实际地址,并在内存中建立维护pod路由表。
flannel启动以后会向etcd中插入需要分配的网段以及这些网段分别分配在哪个上。
【K8s 精选】无法解析 Serv
kubectl get 命令可以列出 k8s 中的资源,而 kubectl get pod 是非常常用的查看 pod 的命令。而 -n 参数则可以指定 pod 所在的命名空间。步骤 1 :找集群 dns 的 serv
步骤 2 :查看 serv 详情
步骤 3 :查看 endpoint 对应的 pod 状态
步骤 1 :pod 里 c 一下 dns 的 53 端口,参考 c 命令详解
步存储管理flannel可分配的IP地址段资源骤 2 :如果网络不通,需要排查一下网络配置
① 检查 Pod 所在的安全组,需要对容器网络开放 53 端口
② 检查防火墙规则 iptables,参考 【K8s 精选】深入剖析 Kubernetes 网络模型
Kubernetes之NetworkPolicy,Flannel和Calico
如果你想查看一个 pod 的具体日志,就可以通过 kubectl logs来查看。注意,这个只能查看 pod 的日志。通过添加 -f 参数可以持续查看日志。例如,查看 kube- 命名空间中某个 flannel pod 的日志,注意修改 pod 名称:
Pod是Kubernetes调度的最小单元。一个Pod可以包含一个或多个容器,因此它可以被看作是内部容器的逻辑宿主机。Pod的设计理念是为了支持多个容器在一个Pod享网络和文件系统。那么为什么Pod内的容器能够共享网络,IPC和PID命名空间?
原因:Kubernetes在每个Pod启动时,会自动创建一个镜像为gcr.io/google_containers/pause:version的容器,所有处于该Pod中的容器在启动时都会添加诸如--net=container:pause --ipc=contianer:pause --pid=container:pause的启动参数,因此Pod内所有容器共用pause容器的network,IPC和PID命名空间。所有容器共享pause容器的IP地址,也被称为Pod IP。因此处于同一个Pod内的容器,可以通过localhost进行相互访问。
Docker引擎在启动时,会在宿主机上创建一个名为docker0的虚拟网桥,这个虚拟网桥负责给所有容器分配不重复的ip地址以及容器间的网络通信。首先,Docker在创建一个容器时,会执行以下作:
通过这个docker0网桥,同一宿主机上的容器可以互相通信。然而由于宿主机的IP地址与容器v pair的 IP地址均不在同一个网段,故仅仅依靠v pair和namespace的技术,还不足以使宿主机以外的网络主动发现容器的存在。为了使外界可以访问容器中的进程,docker采用了端口绑定的方式,也就是通过iptables的NAT,将宿主机上的端口端口流量转发到容器内的端口上。
K8s 默认不提供网络功能,所有Pod的网络功能,都依赖于宿主机上的Docker。因此,Pod IP即是依靠docker0网桥分配给pause容器的虚拟IP。
同一个Node内,不同的Pod都有一个docker0网桥分配的IP,可以直接通过这个IP进行通信。Pod IP和docker0在同一个网段。因此,当同上的Pod-A发包给Pod-B时,包传送路线如下:
不同的Node之间,Node的IP相当于外网IP,可以直接访问,而Node内的docker0和Pod的IP则是内网IP,无法直接跨Node访问。因此,不同Node上的Pod间需要通信,需要满足以下两个条件:
CNI的介绍请参考这篇文章:
在默认的Docker配置中,每个上的Docker服务会分别负责所在容器的IP分配。这样导致的一个问题是,不同上容器可能获得相同的内外IP地址首先,在node上会安装flanneld的守护进程,这个进程会一个端口,这个端口是用于接收和转发数据包的端口,flanneld进程启动以后,会开启一个网桥叫flannel0,flannel0会抓取docker0转发的数据包,docker0会分配自己的IP到对应的pod上,如果是同一台主机中的不同pod的话,他们之间的通讯走的是docker0网桥。如果是不同之间的pod进行通讯,数据包源地址写自己的ip,目标地址写目标地址的ip,然后将数据发送到docker0网桥也就是,此时flannel0有自己钩子函数,将数据从docker0抓取,flannel0是flanneld开启端口,数据到了flanneld之后会将数据报文进行一个封装,然后将数据转发到目标,然后到了目标之后会将数据进行一次解封,到达目标的flanneld,然后数据会进行二次解封,flanneld会通过自己的端口将数据发送到docker0网桥,然后在对数据进行转发,从而发送到相应的目标pod。。
Flannel实质上是一种“覆盖网络(overlay network)”,也就是将TCP数据包装在另一种网络包里面进行路由转发和通信,目前已经支持UDP、VxLAN、AWS VPC和GCE路由等数据转发方式,默认的间数据通信方式是UDP转发。下图展示了数据包在flannel中的流转:
Flannel是一种典型的Overlay网络,它将已有的物理网络(Underlay网络)作为基础,在其上建立叠加的逻辑网络,实现网络资源的虚拟化。Overlay网络有一定额外的封包和解包等网络开销,对网络通信的性能有一定损耗。
Calico是纯三层的SDN 实现,它基于BPG 协议和Linux自身的路由转发机制,不依赖特殊硬件,容器通信也不依赖iptables NAT或Tunnel 等技术。能够方便的部署在物理、虚拟机(如 OpenStack)或者容器环境下。同时calico自带的基于iptables的ACL管理组件非常灵活,能够满足比较复杂的安全隔离需求。
Calico 还基于 iptables 还提供了丰富而灵活的网络 policy, 保证通过各个上的 ACLs 来提供 workload 的多租户隔离、安全组以及其他可达性限制等功能。
核心问题是,nodeA怎样得知下一跳的地址?是node之间通过BGP协议交换路由信息。
每个node上运行一个软路由软件bird,并且被设置成BGP Speaker,与其它node通过BGP协议交换路由信息。
可以简单理解为,每一个node都会向其它node通知这样的信息:
我是X.X.X.X,某个IP或者网段在我这里,它们的下一跳地址是我。
通过这种方式每个node知晓了每个workload-endpoint的下一跳地址。
K8s NetworkPoclicy 用于实现Pod间的网络隔离。在使用Network Policy前,必须先安装支持K8s NetworkPoclicy的网络插件,包括:Calico,Romana,Wee Net,Trireme,OpenContrail等。
在未使用NetworkPolicy前,K8s中所有的Pod并不存在网络隔离,他们能够接收任何网络流量。一旦使用NetworkPolicy选中某个namespace下的某些Pod,那么这些Pod只能接收特定来源的流量(由Ingress属性定义),并且只能向特定出口发送网络请求(由Egress属性定义)。其他未被这个NetworkPolicy选中的Pod,依然不具备网络隔离。
下面是一个NetworkPolicy的例子:
下面的例子表示默认禁止所有Pod间的Ingress流量:
默认拒绝所有 Pod 之间 Egress 通信的策略为:
而默认允许所有 Pod 之间 Ingress 通信的策略为:
默认允许所有 Pod 之间 Egress 通信的策略为:
以 calico 为例看一下 Network Policy 的具体用法。首先配置 kubelet 使用 CNI 网络插件:
安装 calio 网络插件:
首先部署一个 nginx 服务,此时,通过其他 Pod 是可以访问 nginx 服务的:
开启 default namespace 的 Dekubectl get 可以列出 k8s 中所有资源faultDeny Network Policy 后,其他 Pod(包括 namespace 外部)不能访问 nginx 了:
再创建一个运行带有 access=true label的 Pod 访问的网络策略:
K8s的网络详解
flannel的功能是让集群中的不同主机创建的Docker容器具有集群的虚拟IP地址,能够在这些Ip地址之间建立其实作到这里,有必要深入的了解K8s的网络运行机制和基本结构,否则当真的遇到问题的时候会比较郁闷。
首先,要理解K8s的用处其实是容器的编排和管理,最小组成其实不是容器,是pod,物理机或者虚拟机叫node,pod是基础单元,pod里可以有多个容器,也可以只有一个容器,同一个pod的容器彼此是共享网络和主机配置的,换句话说,彼此是可以直接localhost通信的,类似于同一台机器上进行通信,所以这里面是无所谓隔离和安全一说,对外而言就是一个环境,所以pod就是这个环境的业务实体。所以,个问题来了,同一个pod的不同容器可以位于不同的node上吗?当然不行,必须在同一个node上,因为共享主机和网络。那么怎么才能知道一个pod有多个容器?kubectl exec的时候是否可以指定需要运行的容器?当然可以,参考如下指令:
所以,这里可以忽略容器的概念,单单考虑pod,毕竟pod才是k8s最小的调度单元。那pod和pod是怎么通信的呢?
pod的通信离不开K8s的网络模型:
flannel组建一个大二层扁平网络,pod的ip分配由flannel统一分配,通讯过程也是走flannel的网桥。
每个node上面都会创建一个flannel0虚拟网卡,用于跨node之间通讯。所以容器直接可以直接使用pod id进行通讯。
跨通讯时,发送端数据会从docker0路由到flannel0虚拟网卡,接收端数据会从flannel0路由到docker0。
一个非常常见的场景,当一个Pod因为某种原因停止运行了,kubelet根据deployment的需求重新启动一个新的Pod来提供之前Pod的功能,但是flannel会给这个新的Pod分配一个新的IP,这会带来很大的Effort,应用服务的很多配置项都需要调整,如果有了Serv呢,这就不是问题,看下Serv的运行原理。
这张图解释了Serv的运行机制,当Serv A创建的时候,Serv Controller和EndPoints Controller就会被触发更新一些资源,例如基于Serv中配置的Pod的selector给每一个Pod创建一个EndPoint资源并存入etcd,kube-proxy还会更新iptables的chain规则生成基于Serv的Cluster IP链路到对应Pod的链路规则,接下来集群内的一个pod想访问某个服务,直接cluster ip:port即可基于iptables的链路将请求发送到对应的Pod,这一层有两种挑选pod的算法,轮询(Round Robin)和亲和度匹配(Session Affinity)。当然,除了这种 iptabels的模式 ,还有一种比较原始的方式就是 用户态的转发 ,Kube-Proxy 会为每个 Serv 随机一个端口 (Proxy Port),并增加一条 IPt如果Pod是一组应用容器的,那Serv是不是就没有意义了,他的意义在于当应用服务需要做负载、需要做全生命周期的跟踪和管理时就体现出来了,所以Serv是一个抽象的概念,它定义了Pod逻辑和访问这些Pod的策略。ables 规则。从客户端到 ClusterIP:Port 的报文都会被重定向到 Proxy Port,Kube-Proxy 收到报文后,通过 Round Robin (轮询) 或者 Session Affinity(会话亲和力,即同一 IP 都走同一链路给同一 Pod 服务)分发给对应的 Pod。
当然,新版本的k8s开始基于 ipvs来替换iptables 了,但是形式和iptables是类似的。
概念在讲K8s Pod间通信前,我们先复习一下Docker容器间的网络通信。默认情况下,Docker使用一种名为bridge的网络模型。如下图所示:图可以参看:
这是最原始的方式,参看下图:
IPVS是 LVS 项目的一部分,是一款运行在 Linux Kernel 当中的 4 层负载均衡器,性能异常。使用调优后的内核,可以轻松处理每秒 10 万次以上的转发请求。目前在中大型互联网项目中,IPVS 被广泛的用于承接网站入口处的流量。
k8s 基本使用(上)
内部镜像信息本文将介绍 k8s 中的一些最基本的命令,并辅以解释一些基本概念来方便理解,也就是说,本文是一篇偏向实用性而非学术性的文章,如果你想提前了解一下 k8s 相关的知识的话,可以通过以下链接进行学习:
Flannel的设计目的就是为集群中的所有重新规划IP地址的使用规则,从而使得不同上的容器能够获得“同属一个内网”且”不重复的”IP地址,并让属于不同上的容器能够直接通过内网IP通信。k8s 是经典的一对多模型,有一个主要的管理 和许多的工作 sler 。当然,k8s 也可以配置多个管理,拥有两个以上的管理被称为 高可用 。k8s 包括了许多的组件,每个组件都是单运行在一个 docker 容器中,然后通过自己规划的虚拟网络相互访问。你可以通过 kubectl get pod -n kube- 查看所有上的组件容器。
在管理中会比工作运行更多的 k8s 组件,我们就是靠着这些多出来的组件来对工作发号施令。他们都叫什么这里就不详细提了。反正对于”基本使用“来说,这些名字并不重要。
要想理解一个东西就要先明白它的内在理念。通俗点就是,k8s 做了什么?为了提供更加可靠的服务,就要增加的数量,减少每个的体量来平摊负载,而越来越多的虚拟机就会带来越来越高的运维成本。如何让少量的运维人员就可以管理数量众多的及其上的服务呢?这就是 k8s 做的工作。
k8s 把数量众多的重新抽象为一个统一的资源池 ,对于运维人员来说,他们面前没有1、2的概念,而是一个统一的资源池,增加新的对运维人员来说,只是增加自资源池的可用量。不仅如此,k8s 把所有能用的东西都抽象成了资源的概念,从而提供了一套更统一,更简洁的管理方式。
接下来,我会把每个基本命令当做一节来进行介绍,并辅以介绍一些基本概念。本文介绍的命令涵盖了增删改查四方面,可参加下面表格,因为篇幅较长,我们将 create 及之后的不那么常用的命令放在下一篇文章 k8s 基本使用(下) 里讲:
接下来进入正题,首先来了解一下 k8s 中最最最常用的命令 kubectl get ,要记住,k8s 把所有的东西都抽象成了资源,而 kubectl get 就是用来查看这些资源的。最常见的资源就是 pod 。
不仅我们自己的服务是要包装成 pod 的,就连 k8s 自己也是运行在一堆 pod 上。接下来就让我们查看一下 k8s 的 pod :
-n 参数指定了要查看哪个命名空间下的 pod 。 k8s 所有的 pod 都被放置在 kube- 命名空间下。
执行了 kubectl get pod -n kube- 命令后,你就可以看到如下内容:
其中每一行就是一个资源,这里我们看到的资源是 pod 。你看到的 pod 数量可能和我的不一致,因为这个列表里包含了 k8s 在所有上运行的 pod ,你加入的越多,那么显示的 pod 也就越多。我们来一列一列的看:
这里只介绍了如何用 kubectl 获取 pod 的列表。但是不要把 get 和 pod 绑定在一起,pod 只是 k8s 中的一种服务,你不仅可以 get pod ,还可以 get svc ( 查看服务 )、 get rs ( 查看副本 )、 get deploy ( 查看部署 )等等等等,虽然说 kubectl get pod 是最常用的一个,但是如果想查看某个资源而又不知道命令是什么, kbuectl get <资源名> 就对了。
如果你想看更多的信息,就可以指定 -o wide 参数,如下:
加上这个参数之后就可以看到资源的所在 ip 和所在 node 了。
-n 可以说是 kubectl get 命令使用最频繁的参数了,在正式使用中,我们永远不会把资源发布在默认命名空间。所以,永远不要忘记在 get 命令后面加上 -n 。
kubectl describe 命令可以用来查看某一资源的具体信息,他同样可以查看所有资源的详情, 不过最常用的还是查看 pod 的详情 。他也同样可以使用 -n 参数指定资源所在的命名空间。
举个例子,我们可以用下面命令来查看刚才 pod 列表中的某个 pod,注意不要忘记把 pod 名称修改成自己的:
然后你就可以看到很多的信息,咱们分开说,首先是基本属性,你可以在详细信息的开头找到它:
基本属性
其中几个比较常用的,例如 Node 、 labels 和 Controlled By 。通过 Node 你可以快速定位到 pod 所处的机器,从而检查该机器是否出现问题或宕机等。通过 labels 你可以检索到该 pod 的大致用途及定位。而通过 Controlled By ,你可以知道该 pod 是由那种 k8s 资源创建的,然后就可以使用 kubectl get <资源名> 来继续查找问题。例如上文 DaemonSet/kube-flannel-ds-amd64 ,就可以通过 kubectl get DaemonSet -n kube- 来获取上一节资源的信息。
在中间部分你可以找到像下面一样的 Containers 段落。该段落详细的描述了 pod 中每个 docker 容器的信息,常用的比如 Image 字段,当 pod 出现 ImagePullBackOff 错误的时候就可以查看该字段确认拉取的什么镜像。其他的字段名都很通俗,直接翻译即可。
在 describe 查看详情的时候,最常用的信息获取处就是这个 Event 段落了,你可以在介绍内容的末尾找到它,如下:
是的,如果你看到上面这样,没有任何 Events 的话,就说明该 pod 一切正常。当 pod 的状态不是 Running 时,这里一定会有或多或少的问题,长得像下面一样,然后你就可以通过其中的信息分析 pod 出现问题的详细原因了:
kubectl describe <资源名> <实例名> 可以查看一个资源的详细信息,最常用的还是比如 kubectl describe pod
如果你发现某个 pod 的服务有问题,但是状态还是显示 Running ,就可以使用 kubectl logs 来查看其详细日志。-n <命名空间> 来获取一个 pod 的基本信息。如果出现问题的话,可以在获取到的信息的末尾看到 Event 段落,其中记录着导致 pod 故障的原因。
然后就可以看到如下输出:
在本篇文章里,我们了解了 k8s 的宗旨和一些基本概念,并知道了最为常用的 get 、 descibe 及 logs 命令,知道了这三条命令之后就几乎可以从 k8s 中获取所有常用信息了。接下来的 k8s 基本使用(下) 里,我们会更深一步,来了解 k8s 中如何创建、修改及删除资源。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系 836084111@qq.com 删除。