Kubernetes网络简析之三:Ingress

前言

上两篇文章我们分别对Pod和Service的网络模型进行了分析:
Kubernetes 网络简析之一:Pods
Kubernetes网络简析之二:Services
对于pod,其内部的container都是和一个pause的container共享的网络。
而对于cluster,其内部的pod则是通过构造类型为ClusterIP的service来进行通信和均衡的。而service本身也不是一个设备实体,它仅仅是由一些netfilter和iptables的规则构造而成。而真正起作用的还是netfilter和kube-proxy。
那么对于来自cluster之外的请求,我们应该如何配置k8s,让请求能够到达我们希望的地址呢?

从service 网络说起

service网络模型
在上一篇分析service网络模型的时候,我们知道当发向service IP(10.3.241.152)的报文到达node的eth0时候,netfilter会根据iptables规则将其转发给一个有效的后端pod(10.0.1.2)。
那么如果我们想从cluster外部访问service后面的pod的功能怎么办呢?或许这个时候大家脑子里可能会有一个一闪而过的想法:既然任何到达eth0的想访问service IP(10.3.241.152)的报文最后都会由iptables规则进行转发,而且外部环境是能够访问得到网关10.100.0.1的,那么我们为何不在网关上配置一个路由规则10.3.241.152->10.100.0.3。这样当外部请求就会被网关转发到node(10.100.0.3),然后node的eth0上面的netfilter则会对请求进行进一步转发到对应的pod。
添加网关路由
那么这种想法能工作么?答案是:是的!这种方案确实能工作。
但是这种设计并不稳定。因为我们知道node和pod一样都一种暂态的存在。虽然它不像pod那样变动的很频繁,但是也是有可能会被迁移、增加或者删除。而网关是无法根据这种变动来实时调整自己的路由规则的。同时,将所有要访问一个service的请求转发到单一的node上也不是很好的分布式设计方案。
虽然上述方案并不成熟,但是它确实实现了外部应用访问内部pod的功能。那我们应该怎么进行改进呢?有没有什么方法可以实时稳定地维护一个规则,让外部请求能够到达一个正常运行的node,同时请求能够在各个node之间随机分布呢?
其实k8s已经有这么一套成熟的工具来满足我们上述的需求,这也就是k8s内部的负载均衡器ingress。

NodePort Services

接着上面说,我们知道负载均衡器Loadbalancer的作用就是将请求分别转发到对应的node IP上面。但是使用Loadbalancer的前提是后端的node端口上面有能够处理这样请求的服务在监听。
LoadBalancer
如上图所示,如果我们只是给k8s配置一个LoadBalancer,并提供给外部应用一个IP地址。当外部应用想访问LoadBalancer的80端口时,LoadBalancer会把请求转发到node上eth0的80端口。但是我们没有在80端口上配置监听的服务,这样就会导致请求收到错误返回信息ECONNREFUSED。
我们知道node的eth0上的netfilter是监听着对service 10.3.241.152:80端口的请求的。那我们为何不在eth0上搭一座桥,让所有访问eth0 80端口的请求都转发到10.3.241.152:80端口,这样不就OK了么?其实k8s内部就是这么做的,它就是NodePort service。
从上一篇文章我们知道,我们可以配置ClusterIP的service用于cluster内部pod的通信,而这种类型是service的默认类型,所以如果我们不指定类型,service就会按照这种类型创建。那让我们看一下NodePort service的创建示例:

kind: Service
apiVersion: v1
metadata:
  name: service-test
spec:
  type: NodePort
  selector:
    app: service_test_pod
  ports:
  - port: 80
    targetPort: http

从示例上看,NodePort service 其实就比ClusterIP service多配置一个type而已。从功能上讲,NodePort service其实就是对ClusterIP service的扩展,它不仅拥有ClusterIP service的功能(配置一个cluster ip 用于cluster内部访问),同时它还能够在node的eth0上特定的端口被访问到,并且能把请求转发到其对应的cluster ip 对应的端口上。这一配置工作仍然是由kube-proxy来完成的,它首先在每一个node上随机分配一个范围在30000–32767内的端口,并监听这个端口,这个端口就是NodePort。所有发向这个端口的报文都会被转发到service的cluster ip 监听的端口上。
我们通过查看service的信息就可以看到service开启的node的端口:

$ kubectl get svc service-test
NAME           CLUSTER-IP     EXTERNAL-IP   PORT(S)           AGE
service-test   10.3.241.152   <none>        80:32213/TCP      1m

NodePort
如上图所示,当我们配置好LoadBalancer的路由规则后,再从外部访问LoadBalancer的32213端口时,请求会被转发到node的32213端口。由于kube-proxy在监听这个端口,它又会把请求转发到service的cluster IP上,然后再根据netfilter的路由规则转发到对应的pod上。
这种方案的缺点是它暴露给loadbalancer的端口并不是一个标准的端口,而且2768对于大型的cluster来说也是比较紧张的资源。当然这些都可以通过一些方法来改进,比如不标准的nodeport可以在loadbalancer上进行映射,从而提供给客户一个标准的端口。
但是这种方案毕竟不够完整,因为我们终究要在外部提供一个loadbalancer来辅助才行。那我们为何不直接在k8s内部构建一个loadbalancer呢?

LoadBalancer Services and Ingress Resources

经过上面的分析,其实我们很希望在k8s内部能提供一个只需要通过简单配置就能生效的loadbalancer,而不需要我们自己在手工配置。很幸运,k8s内部确实提供了这样的loadbalancer配置。这就是LoadBalancer Services and Ingress Resources。

LoadBalancer Services

首先我们来看LoadBalancer Services。从名字看我们就知道它是另外一种service。而这种service包含了NodePort service的所有功能,并能够构建一个完善的请求转发路径及所需的服务和资源。


kind: Service
apiVersion: v1
metadata:
  name: service-test
spec:
  type: LoadBalancer
  selector:
    app: service_test_pod
  ports:
  - port: 80
    targetPort: http

需要注意的是这种类型的service目前基本上只有在诸如AWS,AZURE或者GCE上面能用。本地如果不安装特定的controller的话,这种模式是无法生效的。
而在云端上,当我们配置了这个service之后,云端服务器会为我们分配外部的IP地址、转发规则、一个目标代理以及后端的service。而我们可以通过命令行查看其状态:

$ kubectl get svc service-test
NAME      CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
openvpn   10.3.241.52     35.184.97.156   80:32213/TCP     5m

可以看到这个时候service多了一个external IP。这样外部的应用就能通过这个外部的IP来访问应用了。

Ingress Resources

上面说到的LoadBalancer Services作为service的一种,它只会做IP层的转发。所以我们无法通过增加配置让它能够完成诸如http等更高层面的路由,如基于虚拟主机或者基于路径的路由转发。而且它无法通过一个LoadBalancer 完成多个service的转发功能。所以这里我们就需要一种资源实现更为复杂的转发功能,它就是Ingress。
Ingress是独立于service的一种单独的资源。它通过配置load balancer可以完成 基于TLS termination,virtual hosts和 path-based 路由规则的转发。同时它可以设置一个load balancer完成多个service的功能。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
  annotations:
    kubernetes.io/ingress.class: "gce"
spec:
  tls:
    - secretName: my-ssl-secret
  rules:
  - host: testhost.com
    http:
      paths:
      - path: /*
        backend:
          serviceName: service-test
          servicePort: 80

如上配置,我们通过在GCE上添加一个ingress然后指定了当前ingress的路由规则,其中包括了多种规则的配置。而当k8s内部的ingress controller收到创建ingress的消息时会根据其配置分别去配置和添加相关资源。
而现在市面上的controller诸如GCE,AZURE的load balancers,一些知名的proxy如nginxhaproxy都提供了相应的controller供我们选用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值