在上一篇文章中 《“深入淺出”來解讀Docker網絡核心原理》 大家了解了Docker中libnetwrok提供的4種驅動,它們各有千秋,但實際上每一種方式都有一定的局限性。假設需要營運一個資料中心的網絡,我們有許多的主控端,每台主控端上運作了成千上萬個Docker容器,如果使用4種網絡驅動的話會是怎麼樣的呢,我們來分析一下:
使用host驅動可以讓容器與主控端共用同一個網絡棧,這麼做看似解決了網絡問題,可實際上并未使用network namespace的隔離,缺乏安全性。
使用Docker預設的bridge驅動,容器沒有對外IP,隻能通過NAT來實作對外通信。這種方式不能解決跨主機容器間直接通信的問題,難以滿足複雜場景下的業務需求。
使用overlay驅動,可以用于支援跨主機的網絡通信,但必須配合swarm進行配置和使用才能實作跨主機的網絡通信。
使用null驅動實際上不進行任何網絡配置。
可見,為了實作資料中心大量容器間的跨主機網絡通信,為了更靈活地實作容器間網絡的共享與隔離,也為了在管理成千上萬個容器時可以更加自動化地進行網絡配置,我們需要來了解更進階的網絡方案。
本文及後期的文章将通過一些工具和額外的操作來突破Docker網絡原有的限制,實作一些更進階的功能來滿足實際運用中的複雜需求。
在上一篇文章中已經介紹過了linux network namespace,在本文中我們将從實踐的角度來了解如何在linux系統下操作linux network namespace。
ip是linux系統下一個強大的網絡配置工具,它不僅可以替代一些傳統的網絡管理工具,如ifconfig、route等,還可以實作更豐富的功能。下面将介紹如何使用ip指令來管理network namespace。
ip netns指令是用來操作network namespace的指令,具體使用方法如下。
建立一個network namespace:
列出系統中已存在的network namespace:
删除一個network namespace:
在network namespace中執行一條指令:
#指令格式
ip netns exec <network nameapce name> <command>
#比如顯示net-test namespace的網卡資訊,路由資訊
其實,你如果覺得ip netns exec 來執行指令比較麻煩,還可以使用啟動一個shell來配合:
ip netns exec <network nameapce name> bash
這樣,就可以在上面執行指令,就好像使用者進入了這個network namespace中;如果要退出這個bash,則輸入exit即可。
當使用ip netns add指令建立了一個network namespace後,就擁有了一個獨立的網絡空間,可以根據需求來配置該網絡空間,如添加網卡,配置IP,設定路由等。下面以之前建立的名為net-test的network namespace為例來示範如何進行這些操作。
當使用ip指令建立一個network namespace時,會預設建立一個回環裝置(loopback interface:lo)。該裝置預設不啟動,最好将其啟動。
在主機上建立兩張虛拟網卡veth-1 和 veth-2:
将veth-2裝置添加到net-test這個network namespace中,veth-1留在主控端中:
現在net-test這個network namespace就有兩塊網卡了(lo和veth-2),驗證看一下:
接下來可以為網卡配置設定IP并啟動網卡:
給兩張網卡配置了IP後,會在各自的network namespace中生成一條路由,用ip route 或者 route -n檢視:
上面這兩條路由表明的意義是目的位址 10.0.0.0/24網絡的IP包分别從veth-1和veth-2發出。
現在net-test這個network namespace有了自己的網卡、IP位址、路由表等資訊,就相當于成了一台小型的“虛拟機”了。測試一下它的連通性,來檢查配置是否正确。
從主機的veth-1網卡ping net-test的veth-2網卡:
從net-test的veth-2網卡ping主機的veth-1網卡:
很多時候,想搭建一個複雜的網絡環境來測試資料,往往受困于沒有足夠的資源來建立虛拟機。我們掌握了配置network namespace後,便可以解決這個問題。可以在一台普通的機器上,以簡單的方式建立多個互相隔離的network namespace,然後通過網卡、網橋等虛拟裝置将它們連接配接起來,組成想要的網絡拓撲。
下面我們來示範一個簡單的例子,将兩個network namespace通過veth pair裝置連起來。過程如下:
1、建立兩個network namespace ns1、ns2,名稱可自行定義:
2、建立veth pair裝置veth-a,veth-b:
3、将網卡分别放到兩個network namespace中:
4、啟動這兩個網張:
5、配置設定IP:
6、驗證連通
通過veth pair裝置連接配接起來的兩個network namespace就好像直接通過網線連接配接起來的兩台機器,它的拓撲圖如下所示:
大家想一下,如果有更多的network namespace需要連接配接怎麼辦?是不是就需要引入虛拟網橋了,就如同Docker網絡一樣。
在上一篇文章 <“深入淺出”來解讀Docker網絡核心原理> 介紹過,Docker是使用Linux namespace技術進行資源隔離的,網絡也是如此。當用預設網絡模式(bridge模式)啟動一個Docker容器時,一定是在主機上建立了一個Linux network namespace。我們可以按照在network namespace中配置網絡的方法來配置Docker 容器的網絡。
首先,啟動一個名為test1的Docker容器:
然後,使用ip netns list指令檢視是否可以看到建立的network namespace。執行指令後發現并沒有看到建立的network namespace。這并不代表Docker容器沒有建立network namespace,隻是ip netns 指令無法檢視而以,這個與ip netns指令工作方式有關。
當使用ip netns指令建立了兩個network namespace(ns1、ns2)後,會在/var/run/netns目錄下看到ns1和ns2:
ip netns list指令在/var/run/netns目錄下查找network namespace。由于Docker建立的network namespace并不在此目錄下建立任何選項,是以,需要一些額外的操作來使ip指令可以操縱Docker建立的network namespace。
Linux下的每一個程序都會屬于一個特定的network namespace,來看一下不同network namespace環境中/pro/$PID/ns目錄下有何差別。
從上面可以發現,不同network namespace中的程序有不同的net:[]号碼發配。這些号碼代表着不同的network namespace,擁有相同net:[]号碼的程序屬于同一個network namesapce。隻要将代表Docker建立的network namesapce的檔案連結到/var/run/netns目錄下,就可以使用ip netns指令操作了,步驟方法如下:
1、用docker inspect檢視test1容器的PID
2、如果/var/run/netns目錄不存在,就要手工建立(一般都有),然後在/var/run/netns目錄下建立軟連結,指向test1容器的network namespace
3、測試是否成功
完成上面的配置後,就可以自行配置Docker的網絡環境了。除了ip netns指令外,還有一些工具可以進入linux network namespace,比如nsenter。但需要額外的安裝這個工具。
Docker現有的網絡比較簡單,擴充性和靈活性都不能滿足很多複雜的應用場景。很多時候都需要自定義Docker容器的網絡。比如,為了使容器各節點之間通信、各節點和本地主機之間的通信,比較簡單的做法就是将Docker容器網絡配置到本地主機網絡的網段中。我們來看一下怎麼實作。
如果想要使Docker容器和容器主機處于同一網絡,那麼容器和主機應該處在一個二層網絡中。就是把兩台機器連在同一個交換機上,或者連在不同的級聯交換機上。在虛拟場影 下,虛拟網橋可以将容器連在一個二層網絡中,隻要将主機的網卡橋接到虛拟網橋中,就能将容器和主機的網絡連起來,再給Docker容器配置設定一個本地區域網路IP就OK了。
我們來通個一個例子分析一下這個過程 :本地網絡為 172.18.18.0/24,網關為 172.18.18.1,主控端IP為172.18.18.34(網卡ens160),要在這台主控端上啟動一個名為test的Docker容器,并給它配置IP為 172.18.18.36。由于并不需要Docker提供的網絡,是以用--net=none參數來啟動容器。操作如下:
1、啟動一個test容器
2、建立一個供容器連接配接的網橋br0
3、将主機ens160網卡橋接到br0上,并把ens160的IP配置在br0上。由于筆者是遠端操作伺服器,是以執行這一步的時候會導緻網絡斷開,是以這裡放在一條指令執行
4、找到test01的PID
5、将容器的network namespace添加到/var/run/netns/目錄下
6、建立用于連接配接網橋和Docker容器的網卡裝置
7、檢視一下test01的網卡情況,并測試
完成配置扣,Docker容器和主控端連接配接的網絡圖如下所示:
現在test01容器可以與本地主機互相通路,并且test01容器可以通過本地網絡的網關172.18.18.1通路外部網絡。
從上面的過程可以發現,配置Docker容器的網絡是相當繁瑣的。如果需要經常自定義Docker網絡,可以把上面的步驟編寫成shell腳本,這樣友善操作。事實上,目前已有了一個這樣的工具解脫我們繁瑣的步驟,就是由Docker公司工程師Jerome Petazzoni在Githu上釋出的pipework的工具。pipwork号稱是容器的SDN解決方案,可以在複場景下将容器連接配接起來。其實随着Docker網絡的不斷改進,piipwork工具的很多功能會被Docker原生支援,是以pipework當初隻是過渡方案之一而以,大家隻要知道了解就行了。下面來看一下pipework的功能。
* 支援linux網橋連接配接到容器并配置容器IP
1、下載下傳pipework
2、将pipework腳本放處指定的目錄,/usr/local/bin
3、對test01容器進行配置
上面配置指令操作如下:
檢視主機是否存在br0網橋,不存在就建立;
向test01中加入一塊名為eth1的網卡,并配置IP172.18.18.36/24;
若test01中已有預設路由,就删除,把172.18.18.1設為預設路由l
将test01容器連接配接到之前建立的網橋上br0;
這個過程和之前采用ip指令配置的過程類似,pipework其實就是用shell寫的代碼。
pipework其實還有其它的很多功能,比如還支援open vswitch、支援dhcp擷取容器的IP等等,本文隻要是和大家了解一下它的作用和功能,其它詳細的功能就不作介紹了。
看到這裡的朋友應該對network namespace和pipework有了更好的了解