本文中,咱们首先将Rancher部署到EC2实例上,而且添加新的主机,以后用Rancher的Catalog启动了RocketChat应用,紧接着对运行中的容器的网络接口和其余属性的进行了分析。git
同时,咱们简要介绍了Rancher的Overlay网络和运行在Network Agent中的辅助服务进程,并经过上面实践中收集的信息构建了Rancher集群中网络通讯的概览图。github
与此同时,还特别介绍了使用IPSec实现主机间的安全通讯。docker
Rancher 是一个容器管理的完整解决方案,而且即将成为一个完整的容器管理平台。咱们对在本身平台上如何处理容器间的网络进行了审慎的思考,并打算用一个简单的例子和你们分享一下Rancher中的网络。Rancher既能够被部署在单机,也能被扩展到数千个节点,在这篇文章中咱们只用少许的主机和容器进行讨论。ubuntu
首先咱们要配置咱们的基础设施,本文使用的是AWS。咱们先在EC2上用下面的命令安装Docker而且启动Rancher部署Master节点:安全
curl -sSL https://get.docker.com | sh - && sudo docker run -d --restart=always -p 8080:8080 rancher/server
Rancher的server在52.40.47.157:8080上被建立好了(须要注意的是:文中涉及的IP地址指向的AWS实例已经在发文的时候被销毁了,文中所列IP仅做示例使用)。经过EC2的console,咱们再新增两个主机——H1和H2,用来跑咱们的应用程序容器。下图展现了咱们主机的逻辑拓扑关系:一个节点用来跑Rancher的Server,另外两个跑Rancher agent:bash
为了方便描述容器间的网络,咱们须要先启动一个容器化的应用服务。用Rancher的Catalog建立应用很是方便,这里咱们选择Rocket Chat。Rocket Chat的应用模板有三个容器镜像组成,分别是:mongo、rocketchat和hubot。启动以后Rocket Chat被分配到:52.11.188.233:3000(关于更详细的关于Rancher Catalog的攻略能够阅读这里:http://docs.rancher.com/ranch...)。微信
Rocket Chat跑起来后,咱们用Rancher UI来对H1和H2的状况一探究竟。点击Infrastructure标签页看看有哪些容器跑在宿主机上:网络
图中能够看出,rocketchat容器被调度到H1上了,剩下的两个容器:mongo和hubot被调度到H2上。截图中咱们还能看到每一个节点都运行着一个network agent(注意:只有当有容器被调度到当前宿主机后,network agent才会被建立)。各个容器的IP地址如截图中所示——这些IP对于咱们后面讨论很重要。app
咱们能够下载machine config文件以得到主机更详细的信息:ssh
解压下载下来的machine configs以后,咱们能够找到主机的私钥和公钥以及一些其余相关的配置文件。用私钥咱们ssh到主机。在每台主机上咱们执行ifconfig列出主机IP和网络接口。下面是在H1上的结果(精简后的),能够看到docker0网桥的IP(172.17.0.1)和eth0接口地址(172.31.38.255):
`ubuntu@leo-alpha-h1:~$ ifconfig docker0 Link encap:Ethernet HWaddr 02:42:64:4e:c0:c6 inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::42:64ff:fe4e:c0c6/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1114933 errors:0 dropped:0 overruns:0 frame:0 TX packets:1437072 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:198587596 (198.5 MB) TX bytes:1813282482 (1.8 GB) eth0 Link encap:Ethernet HWaddr 02:b8:4d:31:40:f3 inet addr:172.31.39.255 Bcast:172.31.47.255 Mask:255.255.240.0 inet6 addr: fe80::b8:4dff:fe31:40f3/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:9001 Metric:1 RX packets:2187296 errors:0 dropped:0 overruns:0 frame:0 TX packets:1382626 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:2627031496 (2.6 GB) TX bytes:277190533 (277.1 MB)`
在H2上重复上面的过程,得到类似的结果:docker0的IP是172.17.0.1,物理网卡eth0的地址是172.31.38.133。
接下来,咱们深挖每台主机上运行的容器的状态并查看每一个网络接口上的IP地址。在H1上咱们用sudo docker ps 和 sudo docker exec:
ubuntu@leo-alpha-h1:~$ sudo docker ps | awk '{print $1"\t"$2}' CONTAINER ID b6a27f5fd2fe rocketchat/rocket.chat:latest f0cd5839d719 rancher/agent-instance:v0.8.1 132d6ad0c6b9 rancher/agent:v1.0.1 ubuntu@leo-alpha-h1:~$ sudo docker exec -it b6a27f5fd2fe /bin/bash rocketchat@b6a27f5fd2fe:/app/bundle$ ip addr 17: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:14:82:66:7d:fd brd ff:ff:ff:ff:ff:ff inet 172.17.0.5/16 scope global eth0 valid_lft forever preferred_lft forever inet 10.42.64.98/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::14:82ff:fe66:7dfd/64 scope link valid_lft forever preferred_lft forever ubuntu@leo-alpha-h1:~$ sudo docker exec -it f0cd5839d719 /bin/bash root@f0cd5839d719:/# ip addr 11: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:14:82:82:b0:68 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 scope global eth0 valid_lft forever preferred_lft forever inet 10.42.162.246/16 scope global eth0 valid_lft forever preferred_lft forever inet 169.254.169.250/32 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::14:82ff:fe82:b068/64 scope link valid_lft forever preferred_lft forever
在H2上重复上述过程,咱们获得了在H1和H2上运行着的容器的信息:
HOST | Container Name | MAC Address | IP addresses |
---|---|---|---|
H1 | rocket.chat | 02:14:82:66:7d:fd |
172.17.0.5/16 10.42.64.98/16 |
H1 | agent-instance | 02:14:82:82:b0:68 |
172.17.0.2/16 10.42.162.246/16 169.254.169.250/32 |
H2 | hubot | 02:14:82:36:a4:6c |
172.17.0.5/16 10.42.42.48/16 |
H2 | mongo | 02:14:82:2d:a0:55 |
172.17.0.4/16 10.42.148.239/16 |
H2 | agent-instance | 02:14:82:ab:9d:5d |
172.17.0.2/16 10.42.69.59/16 169.254.169.250/32 |
从上表中咱们发现每一个容器都有一个网络接口eth0。除此以外,Rancher的network agent容器(上表中的agent-instance)用三个IP地址:一个属于Docker的子网(172.17.X.X),一个属于Rancher的子网(10.42.X.X),以及第三个属于链路本地地址子网(169.254.X.X)。其它的应用服务容器(hubot、mongo、rocketchat)每一个容器有两个IP地址,一个属于Docker子网,另外一个属于Rancher的子网。
让咱们继续了解下Rancher中容器间的数据通讯。从mongo 容器 ping hubot 容器(这俩是在同一台宿主机上):
root@ad4e749d2658:/# ping -c4 hubot PING hubot.rocket-chat.rancher.internal (10.42.42.48): 48 data bytes 56 bytes from 10.42.42.48: icmp_seq=0 ttl=64 time=0.041 ms 56 bytes from 10.42.42.48: icmp_seq=1 ttl=64 time=0.046 ms 56 bytes from 10.42.42.48: icmp_seq=2 ttl=64 time=0.075 ms 56 bytes from 10.42.42.48: icmp_seq=3 ttl=64 time=0.060 ms --- hubot.rocket-chat.rancher.internal ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.041/0.055/0.075/0.000 ms root@ad4e749d2658:/#
网络从mongo容器可达hubot容器,从traceroute的结果也能够确认二者直接只有一跳:
root@ad4e749d2658:/# traceroute hubot traceroute to hubot (10.42.42.48), 30 hops max, 60 byte packets 1 ip-10-42-42-48.us-west-2.compute.internal (10.42.42.48) 0.029 ms 0.012 ms 0.015 ms root@ad4e749d2658:/#
咱们再看下从mongo容器到rocketchat容器的traceroute结果(二者在不一样的主机上):
root@ad4e749d2658:/# traceroute rocketchat traceroute to rocketchat (10.42.64.98), 30 hops max, 60 byte packets 1 * * * 2 ip-10-42-162-246.us-west-2.compute.internal (10.42.162.246) 1.391 ms 1.229 ms 1.168 ms 3 ip-10-42-64-98.us-west-2.compute.internal (10.42.64.98) 1.137 ms 1.108 ms 1.086 ms root@ad4e749d2658:/#
上面的结果中能够看出从mongo到rocketchat容器有三跳,而且中间通过了IP地址为10.42.162.246的网络,这个正是在H1上运行着的network agent的地址。
咱们从mongo容器中看下此时的ARP table:
root@ad4e749d2658:/# cat /proc/net/arp IP address HW type Flags HW address Mask Device 169.254.169.250 0x1 0x2 02:14:82:ab:9d:5d * eth0 10.42.64.98 0x1 0x2 02:14:82:ab:9d:5d * eth0 10.42.69.59 0x1 0x2 02:14:82:ab:9d:5d * eth0 10.42.42.48 0x1 0x2 02:14:82:36:a4:6c * eth0 172.17.0.1 0x1 0x2 02:42:6c:a6:5e:b8 * eth0 root@ad4e749d2658:/#
在ARP table中rocketchar容器的IP地址10.42.64.98的MAC地址是02:14:82:ab:9d:5d
,这和在H2上运行着的network agent eth0的MAC地址是同样的。
让咱们看下IPSec的信息:
root@9cdde771152c:/# swanctl --list-conns conn-52.11.188.233: local: %any remote: 52.11.188.233 local pre-shared key authentication: remote pre-shared key authentication: child-52.11.188.233: TUNNEL local: 0.0.0.0/0 remote: 0.0.0.0/0 root@9cdde771152c:/#
从结果中咱们能够看出H2和H1之间有一条加密的通讯通道52.11.188.233。上述结果的逻辑关系可由下图所示:
咱们经过查看H1和H2上容器的IP地址能够看出,Docker分配的IP地址在不一样的主机上并非惟一的。例如,相同的IP地址172.17.0.5在H1上分配给了rocketchat容器,而在H2上则被分配给了hubot容器,因此单独使用Docker分配的IP不能得到惟一的地址。为了解决这个问题,Rancher给集群中运行着的每一容器分配了一个惟一的IP地址,本文例子中的地址是从从ranher的默认子网10.42.0.0/16分配而来。
在Rancher看来,安全性是头等重要的事情!根据Rancher的设计,Rancher的集群的环境既能够公有云也能够是私有云,因此就不能对主机间的通信信道作任何假设。咱们但愿从主机流出的数据是安全的,所以咱们选择用IPSec去构建主机间的完整网络拓扑。虽然这会带来一些性能上的影响,可是能够确保Rancher的网络默认是安全的。将来的版本里咱们可能会提供选项关闭IPsec。
Rancher用strongSwan来配置IPSec。其中strongSwan的组件Charon daemon用来实现IKEv2协议。若是想要看完整的拓扑细节,咱们能够用命令swanctl:
root@f0cd5839d719:/# swanctl --list-sas conn-52.11.198.155: #71, ESTABLISHED, IKEv2, 2146471635b90a25:1dc18102c0c48357 local '172.17.0.2' @ 172.17.0.2 remote '172.17.0.2' @ 52.11.198.155 AES_CBC-128/AES_XCBC_96/PRF_AES128_XCBC/MODP_2048 established 524s ago, rekeying in 12694s child-52.11.198.155: #1, reqid 1234, INSTALLED, TUNNEL-in-UDP, ESP:AES_CBC-128/HMAC_SHA1_96 installed 459878s ago in cb2952a7, 0 bytes, 0 packets out c0992075, 0 bytes, 0 packets local 0.0.0.0/0 remote 0.0.0.0/0 conn-52.11.198.155: #70, ESTABLISHED, IKEv2, ff2a5d9495f14efe:dda2d2a6df6a1cf3 local '172.17.0.2' @ 172.17.0.2 remote '172.17.0.2' @ 52.11.198.155 AES_CBC-128/AES_XCBC_96/PRF_AES128_XCBC/MODP_2048 established 8076s ago, rekeying in 5913s child-52.11.198.155: #2, reqid 1234, INSTALLED, TUNNEL-in-UDP, ESP:AES_CBC-128/HMAC_SHA1_96 installed 459859s ago in cf604805, 13790077094 bytes, 11532487 packets out cb46151e, 776570467 bytes, 9019180 packets local 0.0.0.0/0 remote 0.0.0.0/0
若是在Network Agent容器中列举全部在跑的进程,咱们能够看到几个关键的服务在运行:rancher-dns,rancher=net等。rancher-net进程是Rancher网络服务的核心,它的做用是用strongSwan 和 charon建立IPSec网络。rancher-net的源代码能够在https://github.com/rancher/ra...查看。相似的,rancher-dns服务的职责是解析容器的名字和IP地址,其代码能够在https://github.com/rancher/ra...查看。
经过应用容器内的/etc/resolv.conf文件咱们能够看到容器的nameserver指向NetworkAgent的地址169.254.169.250。
rocketchat@b6a27f5fd2fe:/app/bundle$ cat /etc/resolv.conf search us-west-2.compute.internal rocket-chat.rancher.internal rocketchat.rocket-chat.rancher.internal rancher.internal nameserver 169.254.169.250
本文中,咱们首先将Rancher部署到EC2实例上,而且添加新的主机,以后用Rancher的Catalog启动了RocketChat应用,紧接着对运行中的容器的网络接口和其余属性的进行了分析。
同时,咱们简要介绍了Rancher的Overlay网络和运行在Network Agent中的辅助服务进程,咱们经过上面实践中收集的信息构建了Rancher集群中网络通讯的概览图。
与此同时,还特别介绍了使用IPSec实现主机间的安全通讯。
Rancher中即将到来的几点对于网络的改进:
目前网路中因为给每一个容器引入了第二个IP地址,对于一些只能使用网卡第一个IP地址的应用带来了一些问题。咱们打算改用CNI/libnetwork的方案,这样能够保证容器只有的默认网络接口只有一个IP地址。于此同时,用户也能够方便的使用社区中不少其余的网络技术。
对于Rancher原生网络,咱们打算除了IPSec外添加对VXLAN的支持。
在接下来的发行版中,咱们打算为每个Rancher支持的环境提供多个相互之间隔离的网络。
但愿这篇文章能够对您深刻了解Rancher的网络提供有价值的信息。一如既往,您的任何问题和困惑均可以经过论坛 https://forums.rancher.com 或者微信公众号(@RancherLabs )联系咱们,咱们的社区有里一群优秀和充满激情的小伙伴期待与您的沟通!