在一篇隨筆中,我們已經嘗試了在不依賴工具的情況下設置docker的ip,連我都想吐槽,MD單機都這么麻煩,在多機的環境中豈不是要了我的小命!
本文就是為了多機環境中各個節點的容器通信而做的,網絡拓朴如下,這里用到了openvswitch工具。
openvswitch為我們建立一個擴展到三層網絡的網橋,我們知道vlan是不能跨子網的,openvswitch利用了隧道技術,將二層的報文用三層的協議(udp/sdn)重新封裝,從而實現二層網絡在三層中進行擴展:如下圖:
openvswitch是一個比較直觀的解決方案,它暴露了足夠多的細節給我們,生產環境中定位問題也是比較方便的。
openvswitch的安裝
首先在centos7上安裝openvswitch(很可惜yum源中並沒有編譯好的rpm,但debian是有的),我們編譯的時候生成rpm而不是利用make install的方式,因為openvswitch的啟動是比較麻煩的(可以讀一下INSTALL.md),生成rpm然后安裝rpm的方式在系統中添加了啟動和停止服務,使用起來很方便。
下面是安裝過程,基本是INSTALL.md的翻譯,但INSTALL.md寫得有點冗長,有細節問題會對我們的編譯過程造成一些干擾。
1、下載openvswitch的源碼,下載release版本的openvswitch源碼可以減少很多麻煩。
wget http://openvswitch.org/releases/openvswitch-2.5.0.tar.gz
2、建立rpmbuild結構(這里其實只需要建立$HOME/rpmbuild/SOURCES目錄即可,其它的目錄可以在rpmbuild執行過程生成的)
cp openvswitch-2.5.0.tar.gz $HOME/rpmbuild/SOURCES
3、安裝編譯所需要的依賴包:
yum install gcc make python-devel openssl-devel kernel-devel graphviz \ kernel-debug-devel autoconf automake rpm-build redhat-rpm-config \ libtool
4、檢查內核開發kernel-devel源碼的位置是否正確:
ls /lib/modules/$(uname -r) -ln
從上圖可以看出,build是一個無效的稱號鏈接,刪除這個鏈接,重新鏈接到正確目錄:
rm /lib/modules/$(uname -r)/build
ln -s /usr/src/kernels/3.10.0-327.13.1.el7.x86_64 /lib/modules/$(uname -r)/build
5、在任意目錄下解壓開源碼,進入源碼目錄:
tar -zxvf openvswitch-2.5.0.tar.gz
cd openvswitch-2.3.2
6、執行rpmbuild生成rpm安裝包:
rpmbuild -bb --without check rhel/openvswitch.spec
--without check表明不運行測試。
另外我們可以不需要編譯內核模塊,這樣子,報文會發到用戶空間由程序去處理,這樣子效率會有所下降,但對內核動手畢竟是一件比較危險又麻煩的事。SO。。。
7、最后安裝我生成的rpm包:
yum localinstall $HOME/rpmbuild/RPMS/openvswitch-2.5.0-1.x86_64.rpm
建立vxlan拓朴
下面利用openvswitch建立我們所需要的vxlan網絡拓朴:
1、在192.168.1.102執行:
# 有錯誤則停止執行 set -e # 創建一個openvswitch bridge ovs-vsctl add-br ovs-br0 # 添加一個到192.168.1.108的接口 ovs-vsctl add-port ovs-br0 vxlan-port-to-192.168.1.108 -- set interface vxlan-port-to-192.168.1.108 type=vxlan option:remote_ip="192.168.1.108" # 創建一對虛擬網卡veth ip link add vethx type veth peer name vethContainer # sleep 3 seconds to wait for the completion of previous work. sleep 3 # 將vethx接入到ovs-br0中 ovs-vsctl add-port ovs-br0 vethx ifconfig vethx up # 啟動docker容器,使用--net=none策略 export containerID=$(docker run -tid --net=none ubuntu:latest /bin/bash) export pid=$(docker inspect -f "{{.State.Pid}}" ${containerID}) echo containerID=${containerID} echo pid=${pid} # 如果net namespace目錄沒有創建則新建一個 if [ ! -d "/var/run/netns" ]; then mkdir -p /var/run/netns fi # 將docker容器使用的net namespace 打回原形 ln -s /proc/${pid}/ns/net /var/run/netns/${pid} ip netns list # 將vethContainer加入到容器的net namespace中 ip link set vethContainer netns ${pid} # 配置vethContainer接口 ip netns exec ${pid} ifconfig vethContainer 192.168.100.100/24 up ip netns exec ${pid} ifconfig -a
2、同樣在192.168.1.108上執行:
# 有錯誤則停止執行 set -e # 創建一個openvswitch bridge ovs-vsctl add-br ovs-br0 # 添加一個到192.168.1.102的接口 ovs-vsctl add-port ovs-br0 vxlan-port-to-192.168.1.102 -- set interface vxlan-port-to-192.168.1.102 type=vxlan option:remote_ip="192.168.1.102" # 創建一對虛擬網卡veth ip link add vethx type veth peer name vethContainer # sleep 3 seconds to wait for the completion of previous work. sleep 3 # 將vethx接入到ovs-br0中 ovs-vsctl add-port ovs-br0 vethx ifconfig vethx up # 啟動docker容器,使用--net=none策略 export containerID=$(docker run -tid --net=none ubuntu:latest /bin/bash) export pid=$(docker inspect -f "{{.State.Pid}}" ${containerID}) echo containerID=${containerID} echo pid=${pid} # 如果net namespace目錄沒有創建則新建一個 if [ ! -d "/var/run/netns" ]; then mkdir -p /var/run/netns fi # 將docker容器使用的net namespace 打回原形 ln -s /proc/${pid}/ns/net /var/run/netns/${pid} ip netns list # 將vethContainer加入到容器的net namespace中 ip link set vethContainer netns ${pid} # 配置vethContainer接口 ip netns exec ${pid} ifconfig vethContainer 192.168.100.101/24 up ip netns exec ${pid} ifconfig -a
測試:
192.168.1.102上的容器:
192.168.1.108上的容器: