前言
这篇我会从头开始来过,要把原本前几篇的 VM destroy 主要是要与上一篇环境做区隔,为的是要让按照教学做,但是做烂不知道该怎么处理的朋友另一个可以参考的方向。
Halt&Destroy VM
首先按下 Ctrl D 登出 root 跟 Ubuntu 回到 Host 之后用 vagrant 指令关掉并且杀掉 VM
代码语言:javascript复制$ [host] vagrant halt==> default: Attempting graceful shutdown of VM...$ [host] vagrant destroydefault: Are you sure you want to destroy the 'default' VM? [y/N] y==> default: Destroying VM and associated drives...
在这之后我们要先对 Vagrantfile 做一个调整,因为 Vagrant 登入预设是 Headless mode 靠 SSH 登入进去控制,但是我们将 Network Interface 加入 OVS bridge 会造成网路中断 SSH 因此会不能用,因此这次不要使用 Headless mode,将 GUI 设为 True 即可。
代码语言:javascript复制# -*- mode: ruby -*-# vi: set ft=ruby :Vagrant.configure("2") do |config| config.vm.box = "ubuntu/xenial64" config.vm.provider "virtualbox" do |vb| vb.gui = true vb.customize ['modifyvm', :id, '--nictype1', 'Am79C973'] vb.customize ['modifyvm', :id, '--nicpromisc1', 'allow-all'] end config.vm.provision :shell, path: "bootstrap.sh"end
重启并登入全新的VM
这时候会有一个 Virtualbox 所开启的 VM 视窗和原本的 Console ,先不需要去管 Virtualbox 所开启的视窗,我们先透过原本的 Console 做一些设定。更改 root 密码,原因是等一下会透过 Virtualbox 的视窗登入,又 Ubuntu 16.04之后已经没有预设 Ubunut 的 root 密码,所以我们先自己设定。
代码语言:javascript复制$ [host] vagrant up$ [host] vagrant ssh$ [guest] sudo passwd rootEnter new UNIX password:Retype new UNIX password:passwd: password updated successfully
操作概要(六步骤)
跟前一篇一样,在详细进入每个操作步骤之前,会先把全面性的概要操作方法列出来,才不会有种见树不见林的感觉。
1.建立 OVS Bridge 名称 ovsbr0 2.将 enp0s3 network interface 加入 OVS 的 port (此时 SSH 会中断使用,切勿直接在 Vagrant ssh 操作,这边会有一个 workaround) 3.移除 enp0s3 的网路设定,并设定 OVS Bridge ovsbr0 用 DHCP 来拿到 IP address 4.产生两个 Containers 来当 Hosts 5.透过 ovs-docker/pipework 工具将 Containers attach 上 OVS Bridges 6.最后很重要 attach 进去 Containers 设定 Routing table 的 Default Gateway
Fig1. Original Network Stack
SSH 进去 VM 之后 Network Stack 如图一所示,第一步我们要透过 ovs-vsctl 指令来建立 OVS Bridge (记得要在 root 的身份)
代码语言:javascript复制$ sudo -s$ ovs-vsctl add-br ovsbr0 #Create OVS bridge$ ovs-vsctl show #Show bridge information1054844d-7b25-4ec1-be12-2069fac0c03b Bridge "ovsbr0" Port "ovsbr0" Interface "ovsbr0" type: internal ovs_version: "2.5.2"
在这个时候,我们的 Network Stack 如图二所示,在这个时候我们还保持跟前一篇一样的架构跟步骤。
Fig2. Network Stack with OVS Bridge
第二步,因为将 enp0s3 network interface 加入 OVS 的 port 会造成网路中断SSH 因此而不能用,这里要透过刚刚启动的 Virtualbox 视窗来控制 VM ,还记得刚刚有设定 Ubuntu 的 root password ,这里务必要使用 root 及方才设定的 root password 在 Virtualbox的视窗登入之后再将 enp0s3 加入 OVS 的 port ! 可以透过 ovs-vsctl show 来看 enp0s3 有没有被加入。
代码语言:javascript复制$ ovs-vsctl add-port ovsbr0 enp0s3$ ovs-vsctl show #Show bridge information1054844d-7b25-4ec1-be12-2069fac0c03b Bridge "ovsbr0" Port "ovsbr0" Interface "ovsbr0" type: internal Port "enp0s3" Interface "enp0s3"ovs_version: "2.5.2"
此时没有意外的话,网路会中断可以试著 ping 外部网路,会发现不通。这时候 Network Stack 变成像图三所示。很明显的 IP Stack 现在那条线路已经接到 OVS bridge上所以网路暂时不通,我们现在尝试著将封包从 OVS bridge forward 给 IP Stack。
Fig3. Network Stack with OVS Bridge without Internet Connection
第三步,来设定 OVS bridge ovsbr0 的 IP address,这样一来封包会进去 ovsbr0 并透过 Bridge 的机制(L2 Switching 也就是 OpenFlow 的 NORMAL action)转发到 IP Stack。首先清掉 enp0s3 上的网路设定,其次透过 dhclient获取 OVS bridge ovsbr0 的 IP address 并另用 ifconfig 看看是否被分配到 IP,最后我们来确认一下 routing table 请记得 Gateway IP 等一下会用到,我们的Gateway IP 是 10.0.2.2。
代码语言:javascript复制$ ifconfig enp0s3 0 #remove enp0s3 configuration$ dhclient ovsbr0$ ifconfig ovsbr0ubuntu@ubuntu-xenial:~$ ifconfig ovsbr0ovsbr0 Link encap:Ethernet HWaddr fe:30:97:7b:d9:42 inet addr:10.0.2.16 Bcast:10.0.2.255 Mask:255.255.255.0 inet6 addr: fe80::fc30:97ff:fe7b:d942/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:57 errors:0 dropped:11 overruns:0 frame:0 TX packets:44 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1 RX bytes:6741 (6.7 KB) TX bytes:6709 (6.7 KB)$ route -nKernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Iface0.0.0.0 10.0.2.2 0.0.0.0 UG 0 0 0 ovsbr010.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 ovsbr0172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
到这边我们可以暂别 Virtualbox 的难用视窗,透过 Terminal 直接在使用 Vagrant ssh 连线回去,并用 root 登入。视窗就先摆着不需要把他关掉。此时我们的 Network Stack会变成如图四所示。红色的箭头线是逻辑的表示网路可以连通。
代码语言:javascript复制$ vagrant ssh #Back to VM through SSH$ sudo -i #Login as root
Fig4. Network Stack with OVS Bridge with Internet Connection
第四步,产生两个 Containers 来当作 Hosts,跟上一篇一样透过 docker 指令,加入两个 containers
代码语言:javascript复制$ docker pull busybox$ docker run --name=container1 --cap-add=NET_ADMIN --net='none' -itd busybox /bin/sh$ docker run --name=container2 --cap-add=NET_ADMIN --net='none' -itd busybox /bin/sh
几个 options 可以看上一篇或是不了解可以去查 docker 官方指南。
第五步,透过 ovs-docker 工具将 Containers attach 上 OVS Bridges,这边选用的工具是 ovs-docker,特别注意我们这边 IP 选的范围刻意挑在跟 Gateway 10.0.2.2 同一个网段。
代码语言:javascript复制$ ovs-docker add-port ovsbr0 eth0 container1 --ipaddress=10.0.2.10/24$ ovs-docker add-port ovsbr0 eth0 container2 --ipaddress=10.0.2.20/24
第六步,attach 进去 containers 设定,每一个container 的 routing table 的 default gateway 还记得前面在 ubuntu 里面查到的 gateway IP 是 10.0.2.2 透过 tmux 开起一个 session 进去 container
代码语言:javascript复制$ docker attach d5475514cada$ / ifconfig eth0eth0 Link encap:Ethernet HWaddr 7A:73:01:04:26:5C inet addr:10.0.2.10 Bcast:0.0.0.0 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:8 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:648 (648.0 B) TX bytes:0 (0.0 B)$ / route -nKernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Iface10.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
这时候我们用 route -n 会看到少了 default gateway,透过 route add 将default gateway 加回去。然后 ping 看看外部就会发现可以通了。
代码语言:javascript复制/ $ route add default gw 10.0.2.2/ $ route -nKernel IP routing tableDestination Gateway Genmask Flags Metric Ref Use Iface0.0.0.0 10.0.2.2 0.0.0.0 UG 0 0 0 eth010.0.2.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0/ $ ping www.google.comPING www.google.com (108.177.97.106): 56 data bytes64 bytes from 108.177.97.106: seq=0 ttl=43 time=127.659 ms64 bytes from 108.177.97.106: seq=1 ttl=43 time=6.647 ms64 bytes from 108.177.97.106: seq=2 ttl=43 time=6.512 ms64 bytes from 108.177.97.106: seq=3 ttl=43 time=6.653 ms
此时 Network Stack 会变成如图五所示,这个时候就成功的打造出一个 vSwitch 在内部每个 containers 都会透过这个 vSwitch 去做封包转发,在加上 SDN Controller 就是一套完整 虚拟的「真实 SDN 网路」。
Fig5. Network Stack with OVS Bridge and Containers
结语
最后我想认真看完这几篇的朋友们,不知道有没有什么问题?目前大家看到的都是只有一个 VM ,未来我会用 Multiple VMs 来做 GRE Tunneling 和 VXLAN 的环境,对 GRE 或 VXLAN 有兴趣也可以一起讨论。
此外有收到一些朋友在询问,是不是可以把 OVS 底层抽换 DPDK ?
事实上官方就有教学指引,重编译加入 OVS 绝对没问题,OVS 会需要重新编译,再带入 DPDK 的参数重编一次就可以,但其实讲虽然简单,做没那麽容易有机会在另外发几篇重编译 OVS 的文章让大家参考。
认真地说这个环境可以尝试运用到商业部署上,透过 Docker 的特性和 SDN 的弹性绝对可以创造出无限的可能,欢迎业界朋友对于部署有任何客制化的问题不方便公开说,可以留言交流。
· END ·