K8s网络插件flannel与calico - 小雨淅淅o0 - 博客园

标签: | 发表时间:2021-06-18 17:13 | 作者:
出处:https://www.cnblogs.com

  Kubernetes的网络通信问题:
  1. 容器间通信: 即同一个Pod内多个容器间通信,通常使用loopback来实现。
  2. Pod间通信: K8s要求,Pod和Pod之间通信必须使用Pod-IP 直接访问另一个Pod-IP
  3. Pod与Service通信: 即PodIP去访问ClusterIP,当然,clusterIP实际上是IPVS 或 iptables规则的虚拟IP,是没有TCP/IP协议栈支持的。但不影响Pod访问它.
  4. Service与集群外部Client的通信,即K8s中Pod提供的服务必须能被互联网上的用户所访问到。

需要注意的是,k8s集群初始化时的service网段,pod网段,网络插件的网段,以及真实服务器的网段,都不能相同,如果相同就会出各种各样奇怪的问题,而且这些问题在集群做好之后是不方便改的,改会导致更多的问题,所以,就在搭建前将其规划好。

CNI(容器网络接口):
  这是K8s中提供的一种通用网络标准规范,因为k8s本身不提供网络解决方案。
  目前比较知名的网络解决方案有:
    flannel
    calico
    canel
    kube-router
    .......
等等,目前比较常用的时flannel和calico,flannel的功能比较简单,不具备复杂网络的配置能力,calico是比较出色的网络管理插件,单具备复杂网络配置能力的同时,往往意味着本身的配置比较复杂,所以相对而言,比较小而简单的集群使用flannel,考虑到日后扩容,未来网络可能需要加入更多设备,配置更多策略,则使用calico更好
所有的网络解决方案,它们的共通性:
  1. 虚拟网桥
  2. 多路复用:MacVLAN
  3. 硬件交换:SR-IOV(单根-I/O虚拟网络):它是一种物理网卡的硬件虚拟化技术,它通过输出VF(虚拟功能)来将网卡虚拟为多个虚拟子接口,每个VF绑定给一个VM后,该VM就可以直接操纵该物理网卡。

kubelet来调CNI插件时,会到 /etc/cni/net.d/目录下去找插件的配置文件,并读取它,来加载该插件,并让该网络插件来为Pod提供网络服务。

flannel网络插件要怎么部署?
 1. flannel部署到那个节点上?
  因为kubelet是用来管理Pod的,而Pod运行需要网络,因此凡是部署kubelet的节点,都需要部署flannel来提供网络,因为kubelet正是通过调用flannel来实现为Pod配置网络的(如:添加网络,配置网络,激活网络等)。

 2. flannel自身要如何部署?
  1》它支持直接运行为宿主机上的一个守护进程。
  2》它也支持运行为一个Pod
  对于运行为一个Pod这种方式:就必须将flannel配置为共享当前宿主机的网络名称空间的Pod,若flannel作为控制器控制的Pod来运行的话,它的控制器必须是DaemonSet,在每一个节点上都控制它仅能运行一个Pod副本,而且该副本必须直接共享宿主机的网络名称空间,因为只有这样,此Pod才能设置宿主机的网络名称空间,因为flannel要在当前宿主机的网络名称空间中创建CNI虚拟接口,还要将其他Pod的另一半veth桥接到虚拟网桥上,若不共享宿主机的网络名称空间,这是没法做到的。

3. flannel的工作方式有3种:
  1) VxLAN:
   而VxLAN有两种工作方式:
    a. VxLAN: 这是原生的VxLAN,即直接封装VxLAN首部,UDP首部,IP,MAC首部这种的。
    b. DirectRouting: 这种是混合自适应的方式, 即它会自动判断,若当前是相同二层网络
       (即:不垮路由器,二层广播可直达),则直接使用Host-GW方式工作,若发现目标是需要跨网段
       (即:跨路由器)则自动转变为使用VxLAN的方式。
  2) host-GW: 这种方式是宿主机内Pod通过虚拟网桥互联,然后将宿主机的物理网卡作为网关,当需要访问其它Node上的Pod时,只需要将报文发给宿主机的物理网卡,由宿主机通过查询本地路由表,来做路由转发,实现跨主机的Pod通信,这种模式带来的问题时,当k8s集群非常大时,会导致宿主机上的路由表变得非常巨大,而且这种方式,要求所有Node必须在同一个二层网络中,否则将无法转发路由,这也很容易理解,因为如果Node之间是跨路由的,那中间的路由器就必须知道Pod网络的存在,它才能实现路由转发,但实际上,宿主机是无法将Pod网络通告给中间的路由器,因此它也就无法转发理由。
  3) UDP: 这种方式性能最差的方式,这源于早期flannel刚出现时,Linux内核还不支持VxLAN,即没有VxLAN核心模块,因此flannel采用了这种方式,来实现隧道封装,其效率可想而知,因此也给很多人一种印象,flannel的性能很差,其实说的是这种工作模式,若flannel工作在host-GW模式下,其效率是非常高的,因为几乎没有网络开销。

4. flannel的网络配置参数:
  1) Network: flannel使用的CIDR格式的网络地址,主要用于为Pod配置网络功能。
   如: 10.10.0.0/16 --->
    master: 10.10.0.0/24
    node01: 10.10.1.0/24
    .....
    node255: 10.10.255.0/24

  2) SubnetLen: 把Network切分为子网供各节点使用时,使用多长的掩码来切分子网,默认是24位.
  3) SubnetMin: 若需要预留一部分IP时,可设置最小从那里开始分配IP,如:10.10.0.10/24 ,这样就预留出了10个IP
  4) SubnetMax: 这是控制最多分配多个IP,如: 10.10.0.100/24 这样在给Pod分配IP时,最大分配到10.10.0.100了。
  5) Backend: 指定后端使用的协议类型,就是上面提到的:vxlan( 原始vxlan,directrouter),host-gw, udp

flannel的配置:
  .....
  net-conf.json: |
    {
     "Network": "10.10.0.0/16",
     "Backend": {
     "Type": "vxlan",    #当然,若你很确定自己的集群以后也不可能跨网段,你完全可以直接设置为 host-gw.
     "Directrouting": true  #默认是false,修改为true就是可以让VxLAN自适应是使用VxLAN还是使用host-gw了。
     }
    }

#在配置flannel时,一定要注意,不要在半道上,去修改,也就是说要在你部署k8s集群后,就直接规划好,而不要在k8s集群已经运行起来了,你再去修改,虽然可能也不会出问题,但一旦出问题,你就!!

  

  #在配置好,flannel后,一定要测试,创建新Pod,看看新Pod是否能从flannel哪里获得IP地址,是否能通信。

 

Calico:
  Calico是一种非常复杂的网络组件,它需要自己的etcd数据库集群来存储自己通过BGP协议获取的路由等各种所需要持久保存的网络数据信息,因此在部署Calico时,早期是需要单独为Calico部署etcd集群的,因为在k8s中,访问etcd集群只有APIServer可以对etcd进行读写,其它所有组件都必须通过APIServer作为入口,将请求发给APIServer,由APIServer来从etcd获取必要信息来返回给请求者,但Caclico需要自己写,因此就有两种部署Calico网络插件的方式,一种是部署两套etcd,另一种就是Calico不直接写,而是通过APIServer做为代理,来存储自己需要存储的数据。通常第二种使用的较多,这样可降低系统复杂度。
  当然由于Calico本身很复杂,但由于很多k8s系统可能存在的问题是,早期由于各种原因使用了flannel来作为网络插件,但后期发现需要使用网络策略的需求,怎么办?
  目前比较成熟的解决方案是:flannel + Calico, 即使用flannel来提供简单的网络管理功能,而使用Calico提供的网络策略功能。


Calico网络策略:

  

  Egress:是出站的流量,即自己是源,远端为服务端,因此我自己的源IP可确定,但端口不可预知, 目标的端口和IP都是确定的,因此to 和 ports都是指目标的IP和端口。
  Ingress:是入站的流量,即自己为目标,而远端是客户端,因此要做控制,就只能对自己的端口 和 客户端的地址 做控制。
我们通过Ingress 和 Egress定义的网络策略是对一个Pod生效 还是 对一组Pod生效?
这个就要通过podSelector来实现了。
而且在定义网络策略时,可以很灵活,如:入站都拒绝,仅允许出站的; 或 仅允许指定入站的,出站都允许等等。
另外,在定义网络策略时,也可定义 在同一名称空间中的Pod都可以自由通信,但跨名称空间就都拒绝。

网络策略的生效顺序:
  越具体的规则越靠前,越靠前,越优先匹配

网络策略的定义:
  kubectl explain networkpolicy
  spec:
   egress: <[]Object> :定义出站规则
   ingress: <[]Object>: 定义入站规则
   podSelector: 如论是入站还是出站,这些规则要应用到那些Pod上。
   policyType:[Ingress|Egress| Ingress,Egress] :
     它用于定义若同时定义了egress和ingress,到底那个生效?若仅给了ingress,则仅ingress生效,若设置为Ingress,Egress则两个都生效。
        注意:policyType在使用时,若不指定,则当前你定义了egress就egress生效,若egress,ingress都定义了,则两个都生效!!
    还有,若你定义了egress, 但policyType: ingress, egress ; egress定义了,但ingress没有定义,这种要会怎样?
    其实,这时ingress的默认规则会生效,即:若ingress的默认规则为拒绝,则会拒绝所有入站请求,若为允许,则会允许所有入站请求,
    所以,若你只想定义egress规则,就明确写egress !!

  egress:<[]Object>
      ports: <[]Object> :因为ports是有端口号 和 协议类型的,因此它也是对象列表
       port :
    protocol: 这两个就是用来定义目标端口和协议的。
   to :<[]Object>
       podSelector: <Object> : 在控制Pod通信时,可控制源和目标都是一组Pod,然后控制这两组Pod之间的访问。
      ipBlock:<[]Object> : 指定一个Ip地址块,只要在这个IP范围内的,都受到策略的控制,而不区分是Pod还是Service。
      namespaceSelector: 这是控制对指定名称空间内的全部Pod 或 部分Pod做访问控制。

  Ingress:
      from: 这个from指访问者访问的IP
      ports: 也是访问者访问的Port

#定义网络策略:
vim   networkpolicy-demo.yaml
apiVersion:  networking.k8s.io/v1  
    #注意:虽然kubectl  explain networkpolicy中显示为 extensions/v1beta1 ,但你要注意看说明部分.
kind:  NetworkPolicy
metadata:
     name:  deny-all-ingressnamespace:  dev
spec:
     podSelector:  {}  #这里写空的含义是,选择指定名称空间中所有Pod
     policyTypes:-Ingress        #这里指定要控制Ingress(进来的流量),但又没有指定规则,就表示全部拒绝,只有明确定义的,才是允许的。
                       #egress: 出去的流量不控制,其默认规则就是允许,因为不关心,所以爱咋咋地的意思。
    
#写一个简单的自主式Pod的定义:
vim  pod1.yaml
    apiVersion:  v1
    kind: Pod
    metadata: 
      name:  pod1
    spec:
      containers:-name:  myapp
        image:  harbor.zcf.com/k8s/myapp:v1

#创建dev名称空间,并应用规则
kubectl apply-f networkpolicy-demo.yaml -n dev

# kubectl describe-n dev networkpolicies
    Name:         deny-all-ingress
    Namespace:    dev
   ........................
    Spec:
      PodSelector:<none> (Allowing the specific traffic to all podsinthisnamespace)
      Allowing ingress traffic:<none> (Selected pods are isolatedforingress connectivity)
      Allowing egress traffic:<none> (Selected pods are isolatedforegress connectivity)


#查看dev名称空间中的网络规则:
kubectlgetnetworkpolicy -n dev     
 或   
 kubectlgetnetpol  -n  dev

#然后在dev 和 prod 两个名称空间中分别创建pod
kubectl  apply-f  pod1.yaml   -n   dev
kubectl  apply-f  pod1.yaml   -n   prod

#接着测试访问这两个名称空间中的pod
kubectlgetpod  -n  dev   -o   wide
    
    #测试访问:
        curl   http://POD_IPkubectlgetpod  -n  prod   -o   wide

    #测试访问:
        curl   http://POD_IP#通过以上测试,可以看到,dev名称空间中的pod无法被访问,而prod名称空间中的pod则可被访问。
#测试放行所有dev的ingress入站请求。
# vim  networkpolicy-demo.yaml
    apiVersion:  networking.k8s.io/v1   
    kind:  NetworkPolicy
    metadata:
       name: allow-all-ingressnamespace:  dev
    spec:
       podSelector:  {}
       ingress:-{}      #这就表示允许所有,因为定义了规则,但规则是空的,即允许所有。
       policyTypes:-Ingress

#接着测试,和上面测试一样,也是访问dev 和 prod两个名称空间中的pod,若能访问,则成功。
# kubectl describe-n dev netpol
    Name:         deny-all-ingress
    Namespace:    dev
    .....................
    Spec:
      PodSelector:<none> (Allowing the specific traffic to all podsinthisnamespace)
      Allowing ingress traffic:
        To Port:<any>(traffic allowed to all ports)
        From:<any>(traffic not restricted by source)
      Allowing egress traffic:<none> (Selected pods are isolatedforegress connectivity)
      Policy Types: Ingress

  #测试定义一个仅允许访问dev名称空间中,pod标签 app=myapp 的一组pod的80端口

  

#先给pod1打上app=myapp的标签
#kubectl label pod pod1 app=myapp -n dev
    
vim  allow-dev-80.yaml
 apiVersion: networking.k8s.io/v1
 kind: NetworkPolicy
 metadata:
    name: allow-myapp-ingress
 spec:
   podSelector:
      matchLabels:
        app: myapp
     ingress:-from:-ipBlock:
            cidr:10.10.0.0/16except:-10.10.1.2/32ports:-protocol:  TCP
         port:88-protocol:  TCP
         port:443#查看定义的ingress规则
kubectlgetnetpol  -n  dev

#然后测试访问 dev 名称空间中的pod
curl  http://Pod_IPcurl  http://Pod_IP:443curl   http://Pod_IP:88

上图测试:1. 先给dev名称空间打上标签
  kubectl   labelnamespacedev   ns=dev2. 编写网络策略配置清单
  vim  allow-ns-dev.yaml
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: allow-ns-dev
    spec:
      podSelector: {}
      ingress:-from:-namespaceSelector:
              matchLabels:
                ns: dev
      egress:-to:-namespaceSelector:
             matchLabels:
               ns: dev



#要控制egress,也是如此,只是将ingress替换为egress即可,然后在做测试。
另外,关于网络策略,建议:
 名称空间内:
     拒绝所有出站,入站流量
     仅放行出站目标为当前名称空间内各Pod间通信,因为网络策略控制的颗粒度是Pod级别的,不是名称空间级别。
     具体的网络策略,要根据实际需求,来定义ingress 和 egress规则。

 

相关 [k8s 网络 插件] 推荐:

K8s网络插件flannel与calico - 小雨淅淅o0 - 博客园

- -
Kubernetes的网络通信问题:. 容器间通信: 即同一个Pod内多个容器间通信,通常使用loopback来实现. Pod间通信: K8s要求,Pod和Pod之间通信必须使用Pod-IP 直接访问另一个Pod-IP. Pod与Service通信: 即PodIP去访问ClusterIP,当然,clusterIP实际上是IPVS 或 iptables规则的虚拟IP,是没有TCP/IP协议栈支持的.

k8s 重置,更换网络插件_云深不知处的技术博客_51CTO博客

- -
在master节点删除flannel. 安装完毕后使用docker images 查看容器镜像可以看见如下以calico打头的镜像.

k8s网络之Flannel网络 - 金色旭光 - 博客园

- -
一、k8s网络之设计与实现. 二、k8s网络之Flannel网络. 三、k8s网络之Calico网络. Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址. 在默认的Docker配置中,每个节点上的Docker服务会分别负责所在节点容器的IP分配.

使用kube-proxy让外部网络访问K8S service的ClusterIP

- - zzm
kubernetes版本大于或者等于1.2时,外部网络(即非K8S集群内的网络)访问cluster IP的办法是:. 修改master的/etc/kubernetes/proxy,把KUBE_PROXY_ARGS=”“改为KUBE_PROXY_ARGS=”–proxy-mode=userspace”.

K8S的SDN容器网络解决方案及其价值

- - SegmentFault 最新的文章
编者按:关于容器网络的解决方案业界已经有较多的讨论,笔者无意继续赘述. K8S及其网络模型体现了鲜明的解耦设计思想,采用SDN技术实现K8S容器网络,并与相应的生态组件形成SDN监管控一体化解决方案,可以更好地提高整个系统的运营水平,更有效地提升企业的核心竞争力. 本文拟抛砖引玉,从K8S的网络实现入手,重点阐述SDN在容器网络中的应用价值.

k8s网络原理之flannel - 渡边彻 - 博客园

- -
首先当你创建一个k8s集群后一般会存在三种IP分别是,Pod IP,Node IP,Cluster IP. (这部分的知识我们在docker网络当中有详细的讲解,不了解的同学可以查看之前的微博. 那么不同Node节点下的Pod又是如何进行通信的呢. 本文重点要讲的flannel网络插件就是用来解决这个问题的.

CentOS7 安装 K8S

- - 企业架构 - ITeye博客
前提:VirtualBox CentOS7. 物理机IP   192.168.18.8. 虚拟机1IP:192.168.18.100(VMaster master). 虚拟机2IP:192.168.18.101(VServer1 node1). 虚拟机3IP:192.168.18.102(VServer2 node2).

SocialBa! – 社交网络同步插件[Chrome]

- - 小众软件
如今登陆社交网站、发点心情、吐点槽,已经成为很多人每天必做的事情,好比吃饭,一天不吃饿得慌. 是一款 Chrome 插件,可以帮助以上人群同步几乎所有主流社交网站的心情和吐槽,包括新浪微博、腾讯微博、人人网、Google+、Facebook、Twitter、VKontakte、开心网、QQ空间、Linkedin、Plurk.

k8s docker集群搭建 - CSDN博客

- -
一、Kubernetes系列之介绍篇.     - 一次构建,到处运行. 2.什么是kubernetes.   首先,他是一个全新的基于容器技术的分布式架构领先方案. Kubernetes(k8s)是Google开源的容器集群管理系统(谷歌内部:Borg). 在Docker技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性.

深入掌握K8S Pod - Yabea - 博客园

- -
K8S configmap介绍. Pod是k8s中最小的调度单元,包含了一个“根容器”和其它用户业务容器. 如果你使用过k8s的话,当然会了解pod的基本使用,但是为了更好的应用,你需要深入了解pod的配置、调度、升级和扩缩容等. pod包含一个或多个相对紧密耦合的容器,处于同一个pod中的容器共享同样的存储空间、IP地址和Port端口.