概述

在学习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所访问

kubernetes 配置网络插件 flannel

kubernetes 配置网络插件 flannel

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

kubernetes 配置网络插件 flannel

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

相关文章: