设为首页 收藏本站
查看: 1188|回复: 0

[经验分享] [Kubernetes]Kubernetes的网络模型

[复制链接]

尚未签到

发表于 2018-1-4 13:51:10 | 显示全部楼层 |阅读模式
  Kubernetes的网络模型从内至外由四个部分组成:


  • Pod内部容器所在的网络
  • Pod所在的网络
  • Pod和Service之间通信的网络
  • 外界与Service之间通信的网络
DSC0000.jpg

  建议在阅读本文之前先了解Docker的网络模型。可以参看作者的前两篇文章[Kubernetes]Docker的网络模型和[Kubernetes]Docker的overlay网络模型。

1. Pod内部容器所在的网络和Pod所在的网络
  Kubernetes使用了一种“IP-per-pod”网络模型:为每一个Pod分配了一个IP地址,Pod内部的容器共享Pod的网络空间,即它们共享Pod的网卡和IP。Kubernetes是怎么做的呢?聪明的读者一定想到了[Kubernetes]Docker的网络模型里介绍的Docker的container网络。Kubernetes在创建Pod时,先在Node节点的Docker上创建了一个运行在bridge网络的“pod容器”,为这个pod容器创建虚拟网卡eth0并分配IP地址。而Pod里的容器(称为app容器),在创建时使用--net=container:来共享pod容器的网络空间。
  例如,笔者手里有一个Kubernetes Node主机PT-169124, IP地址为192.168.169.124. 笔者的环境用flannel作为了Docker的bridge网络驱动,用ifconfig命令可以看到flannel网络设备:
  

flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1472  
        inet 172.17.17.0  netmask 255.255.0.0  destination 172.17.17.0
  
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
  
        RX packets 7988  bytes 410094 (400.4 KiB)
  
        RX errors 0  dropped 0  overruns 0  frame 0
  
        TX packets 12681  bytes 17640033 (16.8 MiB)
  
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  

  这个flannel0是Kubelet用flannel创建出来的bridge,并在Docker进程启动时,作为了--bridge参数值:--bridge=flannel0,这样使得Docker里创建的容器默认都使用flannel0网段里的IP地址。查看这个主机上运行的Docker容器(受限于格式,这里只显示容器的ID和名字):
  

# docker ps
  
CONTAINER>  
7672d97e01d1       k8s_kubernetes-dashboard.979fa630_kubernetes-dashboard-4164430742-lqhcg_kube-system_a08a0d66-57bf-11e6-84b8-5cf3fcba84a8_086f7305
  
431338595af6       k8s_POD.42430ae1_kubernetes-dashboard-4164430742-lqhcg_kube-system_a08a0d66-57bf-11e6-84b8-5cf3fcba84a8_e96d8681
  

  

  这两个容器即是作者在[Kubernetes]Kubernetes集群和Docker私有库搭建(CentOS 7)一文里搭建的kubernetes-dashboard所创建出来的pod容器和app容器。其中pod容器就运行在由flannel驱动的bridge网络里:
  

# docker network inspect bridge  
[
  
    {
  
        "Name": "bridge",
  
        "Id": "6031ecf132905a10b6500a6911d914aff2e15ca8894225aa59ca34bf965b902e",
  
        "Scope": "local",
  
        "Driver": "bridge",
  
        "IPAM": {
  
            "Driver": "default",
  
            "Options": null,
  
            "Config": [
  
                {
  
                    "Subnet": "172.17.17.1/24",
  
                    "Gateway": "172.17.17.1"
  
                }
  
            ]
  
        },
  
        "Containers": {
  
            "431338595af6236a3feb661129e17a4aed4d8331c173903bc2aa7a788d494c6d": {
  
                "Name": "k8s_POD.42430ae1_kubernetes-dashboard-4164430742-lqhcg_kube-system_a08a0d66-57bf-11e6-84b8-5cf3fcba84a8_e96d8681",
  
                "EndpointID": "6f22b9c24be10bf069973e0ba651efafdc68e13177e9cbbe3f41b6b4e963eff1",
  
                "MacAddress": "02:42:ac:11:11:03",
  
                "IPv4Address": "172.17.17.3/24",
  
                "IPv6Address": ""
  
            }
  
        },
  
        "Options": {
  
            "com.docker.network.bridge.default_bridge": "true",
  
            "com.docker.network.bridge.enable_icc": "true",
  
            "com.docker.network.bridge.enable_ip_masquerade": "true",
  
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
  
            "com.docker.network.bridge.name": "docker0",
  
            "com.docker.network.driver.mtu": "1472"
  
        }
  
    }
  
]
  

  再用docker inspect来查看kubernetes-dashboard app容器的详细信息,能看到NetworkMode值为 "container:431338595af6236a3feb661129e17a4aed4d8331c173903bc2aa7a788d494c6d",说明app容器共享pod容器的网络空间,即它们有相同的网卡和IP地址。
  Kubernetes这种“IP-per-pod”网络模型,能让Pod里的容器相互之间通过loopback(127.0.0.1, localhost)网络访问,同时也意味着Pod里的容器在端口分配上不能发生冲突,而Pod里的容器根本不用担心和其他Pod里的容器发生端口冲突。
  更有意思的是,Kubernetes把各Node主机上的Docker的bridge网络“外包”给了flannel,flannel在这些主机上创建的flannel0网络使用的是同一个子网的不同区间。例如本文的环境里,flannel在两台Node主机上创建的flannel0网络分别是:
  主机PT-169121, IP地址为192.168.169.121:
  

flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1472  
        inet 172.17.13.0  netmask 255.255.0.0  destination 172.17.13.0
  
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
  
        RX packets 12684  bytes 17640285 (16.8 MiB)
  
        RX errors 0  dropped 0  overruns 0  frame 0
  
        TX packets 7991  bytes 410346 (400.7 KiB)
  
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  

  主机PT-169124, IP地址为192.168.169.124:
  

flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1472  
        inet 172.17.17.0  netmask 255.255.0.0  destination 172.17.17.0
  
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
  
        RX packets 7988  bytes 410094 (400.4 KiB)
  
        RX errors 0  dropped 0  overruns 0  frame 0
  
        TX packets 12681  bytes 17640033 (16.8 MiB)
  
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  

  flannel通过etcd,将各Node主机上的Docker bridge网络联合了起来,实现了:


  • 所有的容器都能相互通信,不管容器是否运行在同一个Node主机上
  • 所有的容器和Node主机都能相互通信,不管容器是否运行在该Node主机上。
2. Pod和Service之间通信的网络
  Kubernetes里的Pod不是一个“长生”的家伙,它会由于各种原因被销毁和创造。比如在垂直扩容和滚动更新过程中,旧的Pod会被销毁,被新的Pod代替。这期间,Pod的IP地址甚至会发生变化。所以Kubernetes引进了Service.Service是一个抽象的实体,Kubernetes在创建Service实体时,为其分配了一个虚拟的IP,当我们需要访问Pod里的容器提供的功能时,我们不直接使用Pod的IP地址和端口,而是访问Service的这个虚拟IP和端口,由Service把请求转发给它背后的Pod.
  Kubernetes在创建Service时,根据Service的标签选择器(Label Selector)来查找Pod,据此创建与Service同名的EndPoints对象。当Pod的地址发生变化时,EndPoints也随之变化。Service接受到请求时,就能通过EndPoints找到请求转发的目标地址。
  例如,作者在搭建kubernetes-dashboard是创建出的服务如下图所示,背后有两个Pod在支撑。
DSC0001.jpg

  通过kubectl get命令分别查看一下Service和EndPoints的信息:
  

# kubectl get services/kubernetes-dashboard --namespace=kube-system -o yaml  

  
apiVersion: v1
  

  
kind: Service
  

  
metadata:
  

  
  creationTimestamp: 2016-08-01T08:12:02Z
  

  
  labels:
  

  
    app: kubernetes-dashboard
  

  
  name: kubernetes-dashboard
  

  
  namespace: kube-system
  

  
  resourceVersion: "18293"
  

  
  selfLink: /api/v1/namespaces/kube-system/services/kubernetes-dashboard
  

  
  uid: a0953fa0-57bf-11e6-84b8-5cf3fcba84a8
  

  
spec:
  

  
  clusterIP: 10.254.213.209
  

  
  portalIP: 10.254.213.209
  

  
  ports:
  

  
  - nodePort: 31482
  

  
    port: 80
  

  
    protocol: TCP
  

  
    targetPort: 9090
  

  
  selector:
  

  
    app: kubernetes-dashboard
  

  
  sessionAffinity: None
  

  
  type: NodePort
  

  
status:
  

  
  loadBalancer: {}
  

  

# kubectl describe endpoints/kubernetes-dashboard --namespace=kube-system  
Name:        kubernetes-dashboard
  
Namespace:    kube-system
  
Labels:        app=kubernetes-dashboard
  
Subsets:
  
  Addresses:        172.17.13.2,172.17.17.3
  
  NotReadyAddresses:    <none>
  
  Ports:
  
    Name    Port    Protocol
  
    ----    ----    --------
  
    <unset>    9090    TCP
  

  
No events.
  

  

  可以看到,Service的targetPort和Pod的IP地址都记录在了与Service同名的EndPoints里。我们再深入看看当通过Service的虚拟IP和端口访问Service时,请求是如何到达Pod的。
  前面说过,Service只是一个虚拟的实体,真正完成请求转发的是运行在Node节点上的kube-proxy.Service的虚拟IP就是由kube-proxy实现的。kube-proxy有两种请求转发模式:userspace模式和iptables模式。在Kubernetes v1.1版本之前默认是userspace模式,v1.2版本后默认是iptables模式。
  userspace模式:当创建Service时,所有Node节点上的kube-proxy都会在其所在的本地节点上随机开放一个端口(称为代理端口),然后建立一个iptables规则(一种linux包处理逻辑),iptables会完成<服务的虚拟IP, 端口>与代理端口的流量转发,再从EndPoints里选择一个Pod,把代理端口的流量转给该Pod. 当EndPoints下有多个Pod时,选择Pod的算法有两种:1 依次循环,如果一个Pod没有响应,就试下一个(service.spec.sessionAffinity值为"None");2 选择与请求来源IP更接近的Pod(service.spec.sessionAffinity值为"ClientIP").
DSC0002.jpg

  userspace模式的缺点是:只适用于规模较小的集群;会对Pod屏蔽请求的source IP,使得部分基于source IP的防火墙失效。
  iptables模式:当创建Service时,所有Node节点上的kube-proxy都会建立两级iptables规则,一级为Service创建,目的是将<服务虚拟IP,端口>的流量转给后端,另一级为EndPoints创建,目的是用于选择Pod. 当service.spec.sessionAffinity值为"ClientIP"时,iptables模式选择Pod的算法和userspace模式相同。当service.spec.sessionAffinity值为"None"时,随机选择Pod,所以如果被选择的Pod没有响应,不会尝试选择另一个Pod.
DSC0003.jpg

  例如,作者的Kubernetes环境是v1.2版本,用iptables -vL --line-numbers -t nat命令能看到创建的iptables规则:
  kube-proxy为kubernetes-dashboard服务创建的iptables规则:
DSC0004.jpg

  kube-proxy为kubernetes-dashboard EndPoints创建的iptables规则:

  iptables模式相比userspace模式更快更稳定,也不存在请求的source IP的问题。
  我们介绍了Kubernetes是如何用Service来“代理”Pod,那么被创建的Service如何被其他Pod感知到呢?比如说,一个前端的Pod如何找到后端的Service?Kubernetes提供了两种方法:环境变量和DNS.这部分的内容,Kubernetes的官网有所介绍。

3. 外界与Service之间通信的网络
  如果想把服务暴露给外界(为什么不直接暴露Pod呢?相信读者自己有答案。),有三种方式:

Service的类型
  如果不指定Service的spec.type的值,创建的Service的类型默认为ClusterIP类型。这种类型的Service只会得到虚拟的IP和端口,只能在Kubernetes集群内部被访问。
  如果指定Service的spec.type的值为“NodePort”,创建的Service的类型默认为NodePort类型。这种类型的Service除了会得到虚拟的IP和端口,Kubernetes还会在所有Node节点上为其分配端口。分配的端口的值可以通过spec.ports
  • .nodePort指定,或由Knubernetes在配置好的区间里分配(默认为30000-32767)。这种Service即可以从Kubernetes集群通过虚拟IP:端口访问,也可以从集群外部通过Node节点的IP:nodePort访问,例如,作者创建的kubernetes-dashboard服务就是NodePort类型,Kubernetes为其分配的nodePort为31482,通过任意节点的IP(192.168.169.121或192.168.169.124)都能访问。

      如果指定Service的spec.type的值为“LoadBalancer”,创建的Service的类型默认为LoadBalancer类型。这种类型的Service除了会得到虚拟的IP和端口,Kubernetes还会在所有Node节点上为其分配端口,然后为其开通负载均衡。这种Service即可以从Kubernetes集群通过虚拟IP:端口访问,也可以从集群外部通过Node节点的IP:nodePort访问,还可以通过负载均衡的IP访问。

    绑定外部IP
      通过指定Service的spec.externalIPs
  • ,可以将Service暴露在节点的外部IP上。外界通过这个IP和Service的端口可以访问到该Service.

    使用Ingress
      先参见Kubernetes官方文档。待作者亲手完成环境验证后补上。

  • 运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
    2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
    3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
    4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
    5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
    6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
    7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
    8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

    所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-431523-1-1.html 上篇帖子: Kubernetes与容器设计模式 下篇帖子: Kubernetes中的垃圾回收机制
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    扫码加入运维网微信交流群X

    扫码加入运维网微信交流群

    扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

    扫描微信二维码查看详情

    客服E-mail:kefu@iyunv.com 客服QQ:1061981298


    QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


    提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


    本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



    合作伙伴: 青云cloud

    快速回复 返回顶部 返回列表