前言
前面總結了Docker基礎以及Docker存儲相關知識,今天來總結一下Docker單主機網絡的相關知識。毋庸置疑,網絡絕對是任何系統的核心,他在Docker中也占有重要的作用。同樣本文基於CloudMan的系列教程。感謝ColudMan無私分享。
一、Docker默認網絡
在新安裝docker的主機上執行
docker network ls
便能看到docker默認安裝的所有網絡,分別是none網絡、host網絡和bridge網絡。
1.1 none 網絡
none網絡就是什么都沒有的網絡。掛在這個網絡下的容器除了lo,沒有其他任何網卡。容器run時,可以通過添加--network=none參數來指定該容器使用none網絡。那么這樣一個只有lo的網絡有什么用呢?此處CloudMan指出:
none網絡應用與隔離場景,一些對安全性要求高並且不需要聯網的應用可以使用none網絡。
比如某個容器的唯一用途是生成隨機密碼,就可以放到none網絡中避免密碼被竊取。
我可以理解none網絡肯定是用於隔離的,然而我好奇的是生成的隨機密碼如何發送到外部呢?如何被外部調用呢?這是我沒有想明白的問題。有知道的希望不吝賜教!謝謝!
1.2 host 網絡
連接到host網絡的容器共享Docker宿主機的網絡棧,即容器的網絡配置與host宿主機完全一樣。可以通過添加--network=host參數來指定該容器使用host網絡。
在容器中可以看到host的所有網卡,並且連hostname也是host的。host網絡的使用場景又是什么呢?
直接使用Docker host的網絡最大的好處就是性能,如果容器對網絡傳輸效率有較高要求,則可以選擇host網絡。當然不便之處就是犧牲一些靈活性,比如要考慮端口沖突問題,Docker host上已經使用的端口就不能再用了。
Docker host的另一個用途是讓容器可以直接配置 host 網路。比如某些跨host的網絡解決方案,其本身也是以容器方式運行的,這些方案需要對網絡進行配置。
相當於該容器擁有了host主機的網絡,那么其ip等配置也相同,相當於主機中套了一個與外部一模一樣的容器,可以直接通過host的ip地址來訪問該容器。
1.3 bridge 網絡
在不指定--network參數或者--network=bridge的情況下創建的容器其網絡類型都是bridge。
Docker在安裝時會在宿主機上創建名為docker0的網橋,所謂網橋相當於一個虛擬交換機,如果使用上述兩種方式run的容器都會掛到docker0上。
容器和docker0之間通過veth進行連接,veth相當於一根虛擬網線,連接容器和虛擬交換機,這樣就使得docker0與容器連通了。
二、自定義容器網絡
理論上有了上述三種網絡已經足夠滿足普通用戶的需求,但是有時候可能用戶需要指定自己的網絡,以此來適應某些配置,如ip地址規划等等。
2.1 創建自定義網絡
Docker提供三種user-defined網絡驅動:bridge,overlay和macvlan。overlay和macvlan用於創建跨主機的網絡,會在下一篇文章介紹。所以本文介紹創建bridge自定義網絡。命令如下:
docker network create -d bridge --subnet 172.10.0.0/24 --gateway 172.10.0.1 my_net
-d bridge表示自定義網絡的驅動為bridge,--subnet 172.10.0.0/24 --gateway 172.10.0.1分別指定網段和網關。
這樣就創建好了一個自動一網絡,可以通過以下命令查看此網絡的信息:
docker network inspect my_net
會得到此網絡的配置信息,my_net是剛剛創建的網絡名稱,如果為bridge就是查看docker創建的默認bridge網絡信息。
每創建一個自定義網絡便會在宿主機中創建一個網橋(docker0是創建的默認網橋,其實原理是一致的,而且也是對等的。)。名字為br-<網絡短ID>,可以通過brctl show
命令查看全部網橋信息。
docker的自定義網絡與OpenStack中的網絡信息倒是基本一致。所以一通百通,只要docker的明白了,所有虛擬化甚至實體的網絡也就基本都搞清楚了。
2.2 使用自定義網絡
通過以下命令為容器指定自定義網絡:
docker run -it --network my_net --ip 172.10.0.3 busybox
其實這與使用docker默認網絡是一致的,都是添加--network參數參數,此處也添加了--ip參數來指定容器的ip地址。
三、不同容器之間的連通性
同一個網絡(默認網絡或者自定義網絡)下的容器之間是能ping通的,但是不同網絡之間的容器由於網絡獨立性的要求是無法ping通的。原因是iptables-save DROP掉了docker之間的網絡,大概如下:
-A DOCKER-ISOLATION -i docker0 -o br-ac4fe2d72b18 -j DROP
-A DOCKER-ISOLATION -i br-ac4fe2d72b18 -o docker0 -j DROP
-A DOCKER-ISOLATION -i br-62f17c363f02 -o br-ac4fe2d72b18 -j DROP
-A DOCKER-ISOLATION -i br-ac4fe2d72b18 -o br-62f17c363f02 -j DROP
-A DOCKER-ISOLATION -i br-62f17c363f02 -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-62f17c363f02 -j DROP
那么如何讓不同網絡之間的docker通信呢?接下來介紹容器間通信的三種方式。
3.1 IP 通信
IP通信就是直接用IP地址來進行通信,根據上面的分析需要保證兩個容器處於同一個網絡,那么如果不在同一個網絡如何處理呢?
如果是實體機我們很容易理解,只需要為其中一台服務器添加一塊網卡連接到另一個網絡就可以了。容器同理,只需要為其中一個容器添加另外一個容器的網絡就可以了。使用如下命令:
docker network connect my_net httpd
connect命令能夠為httpd容器再添加一個my_net網絡(假設httpd原來只有默認的bridge網絡)。這樣上面創建的busybox容器就能與此次connect的httpd容器進行通信。
3.2 Docker DNS Server
通過 IP 訪問容器雖然滿足了通信的需求,但還是不夠靈活。因為我們在部署應用之前可能無法確定IP,部署之后再指定要訪問的IP會比較麻煩。對於這個問題,可以通過docker自帶的DNS服務解決。
從Docker 1.10 版本開始,docker daemon 實現了一個內嵌的DNS server,使容器可以直接通過“容器名”通信。
方法很簡單,只要在啟動時用--name為容器命名就可以了。
下面的命令啟動兩個容器bbox1和bbox2:
docker run -it --network=my_net --name=bbox1 busybox
docker run -it --network=my_net --name=bbox2 busybox
然后,bbox2就可以直接ping到bbox1了,但是使用docker DNS有個限制,只能在user-defined網絡中使用。默認的bridge網絡是無法使用的。
3.3 joined 容器
joined 容器是另一種實現容器間通信的方式。joined 容器非常特別,它可以使兩個或多個容器共享一個網絡棧,共享網卡和配置信息,joined容器之間可以通過127.0.0.1直接通信。host網絡使得容器與宿主機共用同一個網絡,而jointed是使得兩個容器共用同一個網絡。
請看下面的例子:
先創建一個httpd容器,名字為web1。
docker run -d -it --name=web1 httpd
然后創建busybox容器並通過--network=container:web1指定jointed容器為web1:
docker run -it --network=container:web1 busybox
這樣busybox和web1的網卡mac地址與IP完全一樣,它們共享了相同的網絡棧。busybox 可以直接用127.0.0.1訪問web1的http服務。
其實也很容易理解,之前的--network參數指定了默認網絡或者自定義網絡,而此處是指定了一個容器,那么當然意思就是使用這個容器的網絡。這也有點類似上一篇文章講到的共享存儲。
joined 容器非常適合以下場景:
- 不同容器中的程序希望通過loopback高效快速地通信,比如web server與app server。
- 希望監控其他容器的網絡流量,比如運行在獨立容器中的網絡監控程序。
其實就是應用於即需要獨立而又需要兩個容器網絡高度一致的場景。
3.4 容器與外部網絡的連通性
3.4.1 容器訪問外部網絡
容器默認是能訪問外部網絡的。通過NAT,docker實現了容器對外網(此處外網不一定是互聯網)的訪問。
3.4.2 外部網絡訪問容器
通過端口映射的方式實現外部網絡訪問容器,即通過-p參數實現將容器的端口映射到外部端口。
四、總結
本文簡單總結了單主機情況下容器網絡的相關知識和使用方案,重點是使用方案,如果需要理解原理可以直接查閱CloudMan的相關教程。下一章總結跨主機容器網絡。