前言
本文仅代表作者魏新宇的个人观点;在书写过程中,笔者与同事郭跃军进行了技术讨论,大有裨益,在此表示感谢!
一、K8S vs OCP, 网络端口访问方式
我在上一篇文章《深度理解:Openshift端口方式全解析》中,分享了Openshift的网络端口访问方式:其中提到了:Hostport、Nodeport、Hostnetwork、router。
深度理解:Openshift端口方式全解析
而K8S有三种被外部访问方式:NodePort,LoadBalancer 和 Ingress。
我们先开看看OCP和K8S在网络访问方面的异同。
二、OCP的Service IP和K8S的Cluster IP
OCP中的service IP,对应的是K8S的 ClusterIP;无论是Service IP和ClusterIP,都无法被外部直接访问。
而Openshift的Nodeport和K8S的Nodeport是十分类似的;
Nodeport在OCP指的是:将service ip和端口,映射到OCP集群所有node的node ip和指定的端口号(通常是大端口:30000-32767)。
OCP:
在Openshift中,我们知道每个pod有一个IP,通常网段是10.开头的;同时OCP中还有service ip。而nodeport指的是:将service ip和端口,映射到OCP集群所有node的node ip和指定的端口号(通常是大端口:30000-32767)。
为什么将service ip和OCP中所有node做映射?
因为service ip在OCP中是跨node的。
我们看一个service的yaml配置文件,这是一个mysql的service:
这个配置的含义是,采用nodeport的方式,将mysql server的IP和node ip映射,serivce的源端口是3306,映射到node的端口是30306(大端口)。
这样配置完毕以后,外部要访问pod,访问的是nodeip:30306。然后访问请求通过iptables的NAT将nodeip和端口转化为:service ip和3306端口,最终请求通过service负载均衡到pod。
K8S:Nodeport在K8S的定义如下,从描述看,与OCP的nodeport相同:
NodePort: Exposes the service on each Node’s IP at a static port (the NodePort). A ClusterIP service, to which the NodePort service will route, is automatically created. You’ll be able to contact the NodePort service, from outside the cluster, by requesting <NodeIP>:<NodePort>.
在K8S中,还有一个概念:kube-proxy。为service增加proxy,是为了service在集群,被通过API方式访问:
$ kubectl proxy --port=8080
然后可以通过这种方式在内部访问服务:
http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/
k8s的最开始版本使用的userspace模式,所有的客户端请求svc,都需要先经过iptables,然后在经过kube-proxy到pod,性能很差。
所以在后期版本中K8S增加了iptables方式,在iptables方式下,客户端请求svc会直接经过iptabls转发到pod,而不需要再经过kube-proxy,提高了性能。
但是kube-proxy的缺点是仅支持轮询的负载方式,而且一样存在iptables规则过多导致的性能(iptables是自上而下的匹配,一旦规则多会很慢)。所以目前社区在研究IPVS方式。与iptables类似, ipvs也基于 netfilter 。但ipvs使用哈希表作为底层数据结构,并在内核空间工作,因此IPVS重定向交通速度更快,具有更好的性能。
IPVS支持如下负载均衡策略:
rr: round-robinlc: least connection
dh: destination hashing
sh: source hashing
sed: shortest expected delay
nq: never queue
目前,Openshift安装的时候,模式使用Proxy-mode: iptable模式,也可以修改为Proxy-mode: userspace模式,但没这个必要(因为userspace模式已废弃)。
目前Proxy-mode: ipvs由于在K8S 1.10目前是beta版本,因此在OCP中还没有支持。在K8S正式发布IPVS功能后,相信OCP会同步支持。
三、OCP的router和K8S的Ingress
OCP的router和K8S的Ingress是十分类似的,router和Ingress都是对外暴露http/https类域名。
OCP:
outer本质上,一个router是以hostnetwork方式运行在一个node上的容器化hproxy,它的pod ip就是所在node的ip,对外暴露的端口就是:80、443、1936。
客户端访问某一个应用,如在浏览器中输入http://productpage-istio-system.apps.example.com,首先外部DNS将这个域名解析成router所在node的IP,即:192.168.137.102。
然后,请求到达router所在的node以后,会查询到对应的route信息,查到route对应的service的名称:httpd。此时,通过查询etcd,获取到service和相关的信息。将请求通过service负载均衡发给后端的pod。
K8S:
区别是,OCP用的是容器化的haproxy做router;K8S默认用GCE/Nginx做这件事。
查看ingress的配置:
我们看一下router的dc,我们可以看到,router的安全策略更多一些。
四、K8S的Loadbalance模式
LoadBalancer是K8S借助于cloud provider提供的LoadBalancer,实现被外部网络访问。
LoadBalancer: Exposes the service externally using a cloud provider’s load balancer. NodePort and ClusterIP services, to which the external load balancer will route, are automatically created.
Service的Loadbalancer指定以后,Loadbalancer会将各类访问请求转发到service,HTTP,TCP,UDP,Websocket,gRPC 或其它任意种类。Loadbalancer将会被cloud provider分配一个IP地址。
我们来看一个service的yaml文件,其中制定了loadbalancer:
五、Openshift的路由安全
上面内容已经提到,OCP使用router方式对外暴露80/443/1936端口,为web类应用提供对外访问。
那么,路由的安全如何保证呢?
默认情况,我们expose server,会生成一个域名,这个域名的端口是80:
浏览器访问:
OCP提供三种路由安全策略:Edge Termination(边界终止)、Pass-through Termination(直通终止)、Re-encryption Termination(重加密终止)
Edge Termination(边界终止)的模式,是将安全证书加密到路由上。
Pass-through Termination(直通终止)。这种模式,安全加密不设置在路由上,而是设置在pod中通过证书加密。
Re-encryption Termination(重加密终止),这种模式指的是pod和路由上同时加密,但使用不同的证书。
无论使用哪种方式,创建安全路由以后,应用FQDN的80端口将不能被访问。
我们通过实验进行验证。
我们先生成一个key并进行签名:
然后将旧的路由删掉:
创建新的边界路由:
创建好以后,再度通过80端口方式,失败:
通过443访问,出现安全提示:
添加证书后,可以访问:
六、结论
Kubernetes vs Openshift,谁的网络更安全?
实际上,由于OCP是基于K8S,并且红帽写了大量的K8S代码(2017年K8S代码贡献量第一),因此OCP的网络架构和K8S可以说系出同源。
由于OCP是面向企业级的解决方案,因此会增加更多的安全方面的策略,Openshift的安全加固策略多达70项,如下文:
Openshift容器云安全加固措施70项
不仅仅是网络,Openshift还在其他几个方面做了安全加固:
企业级容器云安全,你需要考虑的九个方面!
参考资料: