openshift封装了k8s,在网络上结合ovs实现了多租户隔离,对外提供服务时报文需要经过ovs的tun0接口。下面就如何通过tun0访问pod(172.30.0.0/16)进行解析(下图来自理解OpenShift(3):网络之 SDN,删除了原图的IP)

openshift版本如下:

# openshift version
openshift v3.6.173.0.5
kubernetes v1.6.1+5115d708d7
etcd 3.2.

首先在查看openshift上pod(该pod为elasticsearch)的路由,默认网关为10.131.2.1,出接口为eth0(IP:10.131.2.45)

sh-4.2$ ip route
default via 10.131.2.1 dev eth0
10.128.0.0/14 dev eth0
10.131.2.0/23 dev eth0 proto kernel scope link src 10.131.2.45
224.0.0.0/4 dev eth0

其次查看node节点的路由,到达pod service的cluster ip(172.30.229.30)的网段(172.30.0.0)出接口为tun0,因此外部流量首先会达到tun0,然后通过tun0转发到pod

[root@dt-infra1 home]# ip route
default via 10.122.70.1 dev eth0 proto static metric 100
10.122.70.0/24 dev eth0 proto kernel scope link src 10.122.70.72 metric 100
10.128.0.0/14 dev tun0 proto kernel scope link
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.30.0.0/16 dev tun0 scope link

查看node节点的接口信息如下(已删减无关接口信息),可以看到vethd0d3571b就是pod中eth0接口的对端,tun0 IP地址也为pod中的默认网关,

[root@dt-infra1 home]# ip a
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 50:6b:8d:d4:25:db brd ff:ff:ff:ff:ff:ff
inet 10.122.70.72/24 brd 10.122.70.255 scope global dynamic eth0
valid_lft 2137631556sec preferred_lft 2137631556sec
inet6 fe80::748f:487f:6bf1:685c/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
inet6 fe80::8fab:527e:43dd:f1b1/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
inet6 fe80::f2d6:994f:f43:cce5/64 scope link tentative dadfailed
valid_lft forever preferred_lft forever
5: br0: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN qlen 1000
link/ether 8e:13:86:1d:ab:43 brd ff:ff:ff:ff:ff:ff
9: vxlan_sys_4789: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65470 qdisc noqueue master ovs-system state UNKNOWN qlen 1000
link/ether d6:48:30:3a:bb:d0 brd ff:ff:ff:ff:ff:ff
inet6 fe80::d448:30ff:fe3a:bbd0/64 scope link
valid_lft forever preferred_lft forever
10: tun0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN qlen 1000
link/ether a6:02:fb:84:24:d0 brd ff:ff:ff:ff:ff:ff
inet 10.131.2.1/23 scope global tun0
valid_lft forever preferred_lft forever
inet6 fe80::a402:fbff:fe84:24d0/64 scope link
valid_lft forever preferred_lft forever
53: vethd0d3571b@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master ovs-system state UP
link/ether 0e:7d:3a:9f:ff:6e brd ff:ff:ff:ff:ff:ff link-netnsid 3
inet6 fe80::c7d:3aff:fe9f:ff6e/64 scope link
valid_lft forever preferred_lft forever

查看该pod的接口信息,可以看出eth0为一对veth pair,对应所在node节点编号为if53的veth

sh-4.2$ ip link
: lo: <LOOPBACK,UP,LOWER_UP> mtu qdisc noqueue state UNKNOWN mode DEFAULT qlen
link/loopback ::::: brd :::::
: eth0@if53: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu qdisc noqueue state UP mode DEFAULT
link/ether 0a::0a:::2d brd ff:ff:ff:ff:ff:ff link-netnsid

从上图中可以看到tun0和pod的veth pair是连接到了一个bridge上,该bridge使用ovs创建的(ip link show type bridge 不可见),使用如下命令可以查看位于br0的ports信息,上面连接了tun0和pod veth的对端

[root@dt-infra1 home]# ovs-vsctl show
b9e6f9ba-efb4-4d5f-97f0-e53191ccf174
Bridge "br0"
fail_mode: secure
Port "vxlan0"
Interface "vxlan0"
type: vxlan
options: {key=flow, remote_ip=flow}
Port "br0"
Interface "br0"
type: internal
Port "vethd0d3571b"
Interface "vethd0d3571b"
Port "tun0"
Interface "tun0"
type: internal
ovs_version: "2.7.2"

使用如下命令可以查看该环境上的ovs bridge,当前环境只有一个br0

[root@dt-infra1 home]# ovs-vsctl list-br
br0

使用如下命令查看当前环境的port编号,该编号在openflow处理时用于指定接口

[root@dt-infra1 home]# ovs-ofctl -O OpenFlow13 dump-ports-desc br0
OFPST_PORT_DESC reply (OF1.) (xid=0x2):
(vxlan0): addr:aa:fd:ab:::ed
config:
state:
speed: Mbps now, Mbps max
(tun0): addr:a6::fb:::d0
config:
state:
speed: Mbps now, Mbps max
(vetha739667c): addr:9e:::9c:6e:
config:
state:
current: 10GB-FD COPPER
speed: Mbps now, Mbps max
(veth6c630c72): addr:2e:f7:::b6:fb
config:
state:
current: 10GB-FD COPPER
speed: Mbps now, Mbps max
(vethd0d3571b): addr:0e:7d:3a:9f:ff:6e
config:
state:
current: 10GB-FD COPPER
speed: Mbps now, Mbps max
LOCAL(br0): addr:8e:::1d:ab:
config: PORT_DOWN
state: LINK_DOWN
speed: Mbps now, Mbps max

与上述pod相关的iptables如下,在进入tun0之前会将ip DNAT为10.131.2.45:9200,即Container IP:ContainerPort

-A KUBE-SERVICES -d 172.30.229.30/ -p tcp -m comment --comment "logging/logging-es: cluster IP" -m tcp --dport  -j KUBE-SVC-BWSQUABZDDFLJOKN
-A KUBE-SVC-BWSQUABZDDFLJOKN -m comment --comment "logging/logging-es:" -j KUBE-SEP-H2SZLG7QT6WVYISM
-A KUBE-SEP-H2SZLG7QT6WVYISM -s 10.131.2.45/ -m comment --comment "logging/logging-es:" -j KUBE-MARK-MASQ
-A KUBE-SEP-H2SZLG7QT6WVYISM -p tcp -m comment --comment "logging/logging-es:" -m tcp -j DNAT --to-destination 10.131.2.45:

从pod中出来的报文会传输到br0进行流表处理,然后选择出接口tun0。ovs流表在处理时有如下规则:

table : 根据输入端口(in_port)做入口分流,来自VXLAN隧道的流量转到表10并将其VXLAN VNI 保存到 OVS 中供后续使用,从tun0过阿里的(来自本节点或进本节点来做转发的)流量分流到表30,将剩下的即本节点的容器(来自veth***)发出的流量转到表20;
table : 做入口合法性检查,如果隧道的远端IP(tun_src)是某集群节点的IP,就认为是合法,继续转到table 30去处理;
table : 做入口合法性检查,如果数据包的源IP(nw_src)与来源端口(in_port)相符,就认为是合法的,设置源项目标记,继续转到table 30去处理;如果不一致,即可能存在ARP/IP欺诈,则认为这样的的数据包是非法的;
table : 数据包的目的(目的IP或ARP请求的IP)做转发分流,分别转到table ~ 去处理;
table : 本地ARP的转发处理,根据ARP请求的IP地址,从对应的端口(veth)发出;
table : 远端ARP的转发处理,根据ARP请求的IP地址,设置VXLAN隧道远端IP,并从隧道发出;
table : Service的转发处理,根据目标Service,设置目标项目标记和转发出口标记,转发到table 80去处理;
table : 对访问本地容器的包,做本地IP的转发处理,根据目标IP,设置目标项目标记和转发出口标记,转发到table 80去处理;
table : 做本地的IP包转出合法性检查,检查源项目标记和目标项目标记是否匹配,或者目标项目是否是公开的,如果满足则转发;(这里实现了 OpenShift 网络层面的多租户隔离机制,实际上是根据项目/project 进行隔离,因为每个项目都会被分配一个 VXLAN VNI,table 只有在网络包的VNI和端口的VNI tag 相同才会对网络包进行转发)
table : 对访问远端容器的包,做远端IP包转发“寻址”,根据目标IP,设置VXLAN隧道远端IP,并从隧道发出;
table : 做出外网的转出处理,将数据包从tun0发出。

该pod对应有如下两条规则,对应arp和ip协议的处理。第一条为arp处理,直接转发到port 45,即pod的veth0对端;后两条为ip处理,第二条首先对目的地址进行判断,然后将0x2d加载到NXM_NX_REG2中,第三条接着处理,对源地址10.131.2.1(即tun0)的报文转发到NXM_NX_REG2[](即0x2d,十进制值为45,为pod的veth对端)

1 cookie=0x0, duration=.378s, table=, n_packets=, n_bytes=, priority=,arp,arp_tpa=10.131.2.45 actions=output:
2 cookie=0x0, duration=.373s, table=, n_packets=, n_bytes=, priority=,ip,nw_dst=10.131.2.45 actions=load:->NXM_NX_REG1[],load:0x2d->NXM_NX_REG2[],goto_table:
3 cookie=0x0, duration=.683s, table=, n_packets=, n_bytes=, priority=,ip,nw_src=10.131.2.1 actions=output:NXM_NX_REG2[]

总结:

报文从外部到pod的整个流程为:node route->iptables->ovs流表->pod。需要注意的是pod内部通信走的是vxlan。全流程参见SDN Flows Inside a Node

TIPS:

  • pod间通信是通过vxlan进行的,ovs网桥中会进行vxlan的封包,到达pod的报文转发到vxlan端口中,将目的node IP作为报文外部目的地址(tun_dst表示outer ip dst),参见OpenShift SDN
  • 外部访问pod是通过router接受流量转换为内部pod之间的通信,即vxlan方式
  • 本机访问本机的pod根据路由转发到tun0

参考:

https://cloud.tencent.com/developer/article/1070415

https://blog.51cto.com/c2014/1829179

http://www.cnblogs.com/sammyliu/p/10064450.html

http://www.openvswitch.org/support/dist-docs-2.5/ovs-ofctl.8.html

http://www.openvswitch.org/support/dist-docs/ovs-fields.7.txt

https://www.ibm.com/developerworks/cn/cloud/library/1401_zhaoyi_openswitch/index.html

https://www.ibm.com/developerworks/cn/linux/l-tuntap/

openshift pod对外访问网络解析的更多相关文章

  1. LINUX开启允许对外访问的网络端口

    LINUX开启允许对外访问的网络端口  LINUX通过下面的命令可以开启允许对外访问的网络端口: /sbin/iptables -I INPUT -p tcp --dport 8000 -j ACCE ...

  2. 在Linux上使用iptables命令开启对外访问的网络端口

    如果linux下没有开启对某端口访问权限,你可以通过下面的命令可以开启允许对外访问的网络端口,示例如下: [root@asg76 sysconfig]# iptables -I INPUT -p tc ...

  3. LINUX开启允许对外访问的网络端口命令

    LINUX通过下面的命令可以开启允许对外访问的网络端口: /sbin/iptables -I INPUT -p tcp --dport 8000 -j ACCEPT #开启8000端口 /etc/rc ...

  4. Kubernetes pod网络解析

    在Kubernetes中,会为每一个pod分配一个IP地址,pod内的所有容器都共享这个pod的network namespace,彼此之间使用localhost通信. 那么pod内所有容器间的网络是 ...

  5. Android异步加载访问网络图片-解析json

    来自:http://www.imooc.com/video/7871 推荐大家去学习这个视频,讲解的很不错. 慕课网提供了一个json网址可以用来学习:http://www.imooc.com/api ...

  6. .Net程序员安卓学习之路2:访问网络API

    做应用型的APP肯定是要和网络交互的,那么本节就来实战一把Android访问网络API,还是使用上节的DEMO: 一.准备API: 一般都采用Json作为数据交换格式,目前各种语言均能输出Json串. ...

  7. Java 网络编程(三) 创建和使用URL访问网络上的资源

    链接地址:http://www.cnblogs.com/mengdd/archive/2013/03/09/2951877.html 创建和使用URL访问网络上的资源 URL(Uniform Reso ...

  8. 使用python访问网络上的数据

    这两天看完了Course上面的: 使用 Python 访问网络数据 https://www.coursera.org/learn/python-network-data/ 写了一些作业,完成了一些作业 ...

  9. android post 方式 访问网络 实例

    android post 方式 访问网络 实例 因为Android4.0之后对使用网络有特殊要求,已经无法再在主线程中访问网络了,必须使用多线程访问的模式 该实例需要在android配置文件中添加 网 ...

随机推荐

  1. Python项目--Scrapy框架(一)

    环境 win8, python3.7, pycharm 正文 1.Scrapy框架的安装 在cmd命令行窗口执行: pip install Scrapy 即可完成Scrapy框架的安装 2. 创建Sc ...

  2. 【bug小记】应用跳转白屏

    tv端项目 测试那边反馈我们的应用跳转到别的应用,再跳转回来会出现白屏的情况. 其实这个原因很简单,就是系统内存不足了把我们的app进程销毁了 所以再回到我们的应用的时候需要重新绘制,而这个" ...

  3. IoGetRelatedDeviceObject学习

    PDEVICE_OBJECT IoGetRelatedDeviceObject( IN PFILE_OBJECT FileObject ) /*++ Routine Description: This ...

  4. linux_vim编辑文件无法高亮显示解决方法

    打开/etc/vimrc(/etc/vim/vimrc不同版本,可能不一样) 在文档最后添加下面内容 syntax on 如图所示:我添加了高亮显示和显示行数 syntax on set nu 修改完 ...

  5. GitHub--创建新的分支(转)

    如何在 GitHub 的项目中创建一个分支呢? 其实很简单啦,直接点击 Branch,然后在弹出的文本框中添加自己的 Branch Name 然后点击蓝色的Create branch就可以了,这样一来 ...

  6. 利用UML语言建模--以图书馆管理系统为例

    一.基本信息 标题:利用UML语言建模--以图书馆管理系统为例 时间:2016 出版源:内蒙古科技与经济 领域分类:UML:RFID:图书馆:模型: 二.研究背景 问题定义:建立图书馆管理系统 难点: ...

  7. 使用Jupyter Notebook编写技术文档

    1.jupyter Notebook的组成 这里它的组件及其工程构成,帮助大家更好的用好jupyter Notebook 组件 Jupyter Notebook结合了三个组件: 笔记本Web应用程序: ...

  8. WITH RECOMPILE和OPTION(RECOMPILE)区别仅仅是存储过程级重编译和SQL语句级重编译吗

    在考虑重编译T-SQL(或者存储过程)的时候,有两种方式可以实现强制重编译(前提是忽略导致重编译的其他因素的情况下,比如重建索引,更新统计信息等等), 一是基于WITH RECOMPILE的存储过程级 ...

  9. 利用ADO打开Access数据(64位系统)

    64位的access一定要用64的程序才能正确打开,仍然用"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Test.accdb;Persist ...

  10. 如果你在it院校学习累了,你能干什么?

    文章来源i春秋,未经允许不得转载    工具链接https://bbs.ichunqiu.com/portal.php 如果你在国内的it院校累了,有些厌倦了,你该怎么办?    分享一些joke以前 ...