天天看點

Docker進階網絡實踐之 玩轉Linux network namespace & pipework

 在上一篇文章中 《“深入淺出”來解讀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網卡:

Docker進階網絡實踐之 玩轉Linux network namespace & pipework

 從net-test的veth-2網卡ping主機的veth-1網卡:

Docker進階網絡實踐之 玩轉Linux network namespace & pipework

 很多時候,想搭建一個複雜的網絡環境來測試資料,往往受困于沒有足夠的資源來建立虛拟機。我們掌握了配置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、驗證連通

Docker進階網絡實踐之 玩轉Linux network namespace & pipework

 通過veth pair裝置連接配接起來的兩個network namespace就好像直接通過網線連接配接起來的兩台機器,它的拓撲圖如下所示:

Docker進階網絡實踐之 玩轉Linux network namespace & pipework

 大家想一下,如果有更多的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容器和主控端連接配接的網絡圖如下所示:

Docker進階網絡實踐之 玩轉Linux network namespace & pipework

 現在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有了更好的了解
Docker進階網絡實踐之 玩轉Linux network namespace & pipework