首页 > Web开发 > 详细

kubernetes 配置网络插件 flannel

时间:2019-08-20 23:19:52      阅读:181      评论:0      收藏:0      [点我收藏+]

概述

在学习docker时知道docker有四种常用的网络模型

  • bridge:桥接式网络
  • joined:联盟式网络,共享使用另外一个容器的网络名称空间
  • opened:容器直接共享使用宿主机的网络名称空间
  • none:不使用任何网络名称空间

  无论是哪一种网络方式都会导致如果我们跨节点之间的容器之间进行通信时必须要使用NAT机制来实现,任何pod在访问出去之前因为自己是私有网络中的地址,在离开本机时候必须要做源地址转换以确保能够拿着物理机的地址出去,而后每一个pod要想被别人所访问或者每一个容器在上下文当中它也访问不到我们还来做什么?从下图中可以看到,第一个节点上我们有container1,container1自己使用虚拟网卡(纯软件)的方式生成一个网络接口,它通常是一个v1th格式的网络接口,一半在容器上一半在宿主机上并关联到docker0桥上,所以他是一个私网地址,我们使用172.17.0.2这样的地址,很显然在这个地址出去访问其它物理机地址的时候物理机能收到请求没有问题因为它的网关有可能都已经通过打开核心转换要通过eth0即宿主机的网络发出来,但是对端主机收到以后响应给谁?是不是没法响应了,因为这是私网地址,而且是nat背后的私网地址,或者是位于某个服务器背后的私有地址,因此为了确保能够响应到我们任然能送回这个主机,我们需要在本地做原地址转换,同样的,如果container2希望被别人访问到我们需要在宿主机上的物理接口上做dnat将服务暴露出去,因此被别人访问时,假如有个物理机要访问docker2时就应该访问其宿主机上的eth0上的某一端口,再目标地址转换至container2的eth0的地址上来,所以如果我们刚好是container1和container2通信,那就是两级nat转换了,首先,对container1来讲,其报文离开本机的时候要做snat,然后这个报文接入物理网络发给container2的宿主机的时候我们还需要dnat一次然后到container2,container2响应的报文也是一样的逻辑。当前,dnat和snat都是都是自动实现的,不需要手动设置。这个过程是必不可少的

  这样的话就会导致我们网络通信性能很差不说,并且container1其实一直不知道自己访问的是谁,他访问的是container2但实际上他的目标地址指向的是eth0的地址,并且container2一直不知道访问自己的是谁,因为他收到的请求是左侧eth0的,他实际上是被container1所访问

技术分享图片

技术分享图片

k8s之上的网络通讯模型

  所以这种通信方式实在是让人觉得效率低而且很难去构建我们自己真正需要的网络通讯模型。因此k8s作为一个编排工具来讲他本身就必须需要让我们容器工作在多个节点之上,而且是pod的形式,各pod之间是需要进行通信的,而且在k8s之上要求我们pod之间通信大概存在以下情形

  •  容器间通信:同一个Pod内的多个容器间的通信: lo
  •  pod间通信:pod间通信k8s要求他们之间的通信必须是所见即所得,即一个pod的IP到另一个pod的IP之间通信不经过任何NAT转换,要直达
  • pod与service通信:即pod IP  与cluster IP之间直接通信,他们其实不在同一个网段,但是他们通过我们本地的IPVS或者iptables规则能实现通信,而且我们知道1.11上的kube-proxy也支持IPVS类型的service,只不过我们以前没有激活过。即pod IP与cluster IP通信是通过系统上已有的iptables或ipvs规则来实现的,这里特别提醒一下ipvs取代不了iptables,因为ipvs只能拿来做负载均衡,做nat转换这个功能就做不到
  •  service与集群外部客户端的通信;使用ingress 或nodeport或loadblance类型的service来实现

   我们此前说过利用一个新的环境变量能够在部署的时候就能够实现IPVS后来发现这种方式不行,其实在我们使用kubeadm部署k8s集群时不需要这么做,最简单的办法就是直接改kube-proxy的配置文件。我们去往每一个节点都已经默认加载了ipvs内核模块,调度算法模块等等,还有连接追踪模块。我们来看一下kube-system名称空间的configmap,可以看到一个叫做kube-proxy,这里面定义了我们kube-proxy到底使用哪种模式在工作,将其中的mode定义为ipvs再重载一下即可

kubectl get configmap -n kube-system

技术分享图片

技术分享图片
apiVersion: v1
data:
  config.conf: |-
    apiVersion: kubeproxy.config.k8s.io/v1alpha1
    bindAddress: 0.0.0.0
    clientConnection:
      acceptContentTypes: ""
      burst: 10
      contentType: application/vnd.kubernetes.protobuf
      kubeconfig: /var/lib/kube-proxy/kubeconfig.conf
      qps: 5
    clusterCIDR: 10.244.0.0/16
    configSyncPeriod: 15m0s
    conntrack:
      max: null
      maxPerCore: 32768
      min: 131072
      tcpCloseWaitTimeout: 1h0m0s
      tcpEstablishedTimeout: 24h0m0s
    enableProfiling: false
    healthzBindAddress: 0.0.0.0:10256
    hostnameOverride: ""
    iptables:
      masqueradeAll: false
      masqueradeBit: 14
      minSyncPeriod: 0s
      syncPeriod: 30s
    ipvs:
      excludeCIDRs: null
      minSyncPeriod: 0s
      scheduler: ""
      syncPeriod: 30s
    kind: KubeProxyConfiguration
    metricsBindAddress: 127.0.0.1:10249
    mode: "" #将此处改为ipvs即可
    nodePortAddresses: null
    oomScoreAdj: -999
    portRange: ""
    resourceContainer: /kube-proxy
    udpIdleTimeout: 250ms
  kubeconfig.conf: |-
    apiVersion: v1
    kind: Config
    clusters:
    - cluster:
        certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        server: https://192.168.10.10:6443
      name: default
    contexts:
    - context:
        cluster: default
        namespace: default
        user: default
      name: default
    current-context: default
    users:
    - name: default
      user:
        tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
kind: ConfigMap
metadata:
  creationTimestamp: 2019-05-08T10:02:16Z
  labels:
    app: kube-proxy
  name: kube-proxy
  namespace: kube-system
  resourceVersion: "239"
  selfLink: /api/v1/namespaces/kube-system/configmaps/kube-proxy
  uid: 5c27af66-7178-11e9-be24-000c29d142be
kubectl get configmap kube-proxy -n kube-system -o yaml

  k8s最有意思的是他的网络实现不是自己来实现的,而是要靠网络插件。即CNI(容器网络接口)接口插件标准接入进来的其它插件来实现,即k8s自身并不提供网络解决方案,他允许去使用去托管第三方的任何解决方案,代为解决k8s中能解决这四种通信模型中需要执行通信或解决任何第三方程序都可以,这种解决方案是非常非常多的,有几十种,目前来讲比较流行的就是flannel,calico,以及二者拼凑起来的canel,事实上我们k8s自己也有据说性能比较好的插件比如kube-router等等,但无论是哪一种插件他们试图去解决这四种通信时所用到的解决方案无非就这么几种 

  1  虚拟网桥:brdige,用纯软件的方式实现一个虚拟网络,用一个虚拟网卡接入到我们网桥上去。这样就能保证每一个容器和每一个pod都能有一个专用的网络接口,从而实现每一主机组件有网络接口。每一对网卡一半留在pod之上一半留在宿主机之上并接入到网桥中。甚至能接入到真实的物理网桥上能顾实现物理桥接的方式 

  2  多路复用: MacVLAN,基于mac的方式去创建vlan,为每一个虚拟接口配置一个独有的mac地址,使得一个物理网卡能承载多个容器去使用。这样子他们就直接使用物理网卡并直接使用物理网卡中的MacVLAN机制进行跨节点之间进行通信了

  3  硬件交换:使用支持单根IOV(SR-IOV)的方式,一个网卡支持直接在物理机虚拟出多个接口来,所以我们称为单根的网络连接方式,现在市面上的很多网卡都已经支持单根IOV的虚拟化了。它是创建虚拟设备的一种很高性能的方式,一个网卡能够虚拟出在硬件级多个网卡来。然后让每个容器使用一个网卡 

  相比来说性能肯定是硬件交换的方式效果更好,不过很多情况下我们用户期望去创建二层或三层的一些逻辑网络子网这就需要借助于叠加的网络协议来实现,所以会发现在多种解决方案中第一种叫使用虚拟网桥确实我们能够实现更为强大的控制能力的解决方案,但是这种控制确实实现的功能强大但多一点,他对网络传输来讲有额外的性能开销,毕竟他叫使用隧道网络,或者我们把它称之为叠加网络,要多封装IP守护或多封装mac守护,不过一般来讲我们使用这种叠加网络时控制平面目前而言还没有什么好的标准化,那么用起来彼此之间有可能不兼容,另外如果我们要使用VXLAN这种技术可能会引入更高的开销,这种方式给了用户更大的腾挪的空间

  如果我们期望去使用这种所谓的CNI插件对整个k8s来讲非常简单,只需要在kubelete配置文件或在启动时直接通过一个目录路径去加载插件配置文件, /etc/cni/net.d/,因此我们只要把配置文件扔到这个目录中去他就可以被识别并加载为我们插件使用

ls /etc/cni/net.d/

技术分享图片

技术分享图片
{
  "name": "cbr0",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}
cat /etc/cni/net.d/10-flannel.conflist

  任何其它网络插件部署上来也是如此,把配置文件扔到这个目录下从而被kubelete所加载,从而能够被kubelete作为必要时创建一个pod,这个pod应该有网络和网卡,那么它的网络和网卡怎么生成的呢?kubelet就调用这个目录下的由配置文件指定的网络插件,由网络插件代为实现地址分配,接口创建,网络创建等各种功能。这就是CNI,CNI是一个JSON格式的配置文件,另外他有必要有可能还会调IP地址管理一些二层的模块来实现一些更为强大的管理功能。

  通常来讲CNI本身只是一种规范,CNI的插件是说我们的容器网络插件应该怎么定义,网络接口应该怎么定义等等,目前来讲我们CNI插件分为三类,了解即可。不同的网络插件在实现地址管理时可能略有不同,而flannel,calico,canel,kube-router等等都是解决方案,据统计,flannel目前来讲份额还是最大的。但是其有个缺陷,在k8s上网络插件不但要实现网络地址分配等功能,网络管理等功能,他还需要实现网络策略,可以去定义pod和pod之间能不能通信等等,大家知道我们在k8s上是存在网络名称空间的,但是这个名称空间他并不隔离Pod的访问,虽然隔离了用户的权限,比如我们定义说rolebinding以后我们一个用户只能管理这个名称空间的资源,但是,他却能够指挥着这个pod资源去访问另一个名称空间的pod资源,pod和pod之间在网络上都属于同一网段,他们彼此之间没有任何隔离特性,万一你的k8s集群有两个项目,彼此之间不认识,万一要互害的时候是没有隔离特性的。所以我们需要确保网络插件能够实现辅助设置pod和pod之间是否能够互相访问的网络策略,但是flannel是不支持网络策略的。calico虽然部署和配置比flannel麻烦很多,但是calico即支持地址分配又支持网络策略,因此其虽然复杂,但是却很受用户接受。还有一点就是calico在实现地址转发的方式中可以基于bgp的方式实现三层网络路由,因此在性能上据说比flannel要强一些。但是flannel也支持三种网络方式。默认是叠加的,我们使用host gw其实可能比我们想象的功能要强大的多  

  这是介绍的网络插件,我们经常使用时可以兼顾使用flannel的简单,借助于calico实现网络策略,也没必要直接部署canel,可以直接部署flannel做平时的网络管理功能若需要用到网络策略时再部署一个calico,只让其部署网络策略,搭配起来使用,而不用第三方专门合好的插件

 配置和使用flannel

 

kubernetes 配置网络插件 flannel

原文:https://www.cnblogs.com/crazymagic/p/11386180.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!