動手玩Windows 10 Docker(3) - 有關Docker的網絡連接

Windows 10 Docker 是2016年度更新後很大的一個進步但(好像)被很多人忽略沒有話題性

這個系列是我的學習筆記也順便推廣這好用的東西

大家好, 新的2017年祝大家器運行暢順, 年中無休

上一篇我們看到怎樣可以把Docker運行先container而且知道怎樣把他們的服務發佈到到host的port上

讓我們在host機器上存取到container提供的服務

這一篇我們再深入一點看看Docker的網絡部份是如何運作的, 

我們可以繼續想像container是一個個運行中的VM, 如果大家有玩過現今的虛擬機器系統, 例如VMware ESX和Hyper-V

就可以用虛擬交換機(Virtual Switch)的概念來思考,

這些交換機可以連接實體NIC與外面的世界, 也可以只為虛擬機之間連接之用

Docker也有這種網絡概念, 如果你鍵入

docker network ls

可以見到預設的3種網絡

我們在之前的container之中沒有說明過要把它連接到那一個網絡

Docker預設把docker run建立的container放到"bridge" 這個網絡上, 而他的驅動程式(DRIVER)是接橋(Bridge)

固名思義bridge是把一些東西連接起來, 也是最常用的一種驅動程式, 我們先暫時不理會host和none是甚麼,

如果我們鍵入docker network inspect bridge (注意小寫字母), 可以得到如以下的結果

可以見到bridge就有設定subnet和default gateway (172.17.0.1)

而下面能見到我們在運行中的mysql579和mysql800擁有IP地址172.17.0.2和172.17.0.3

如果你只想查看一個container它拿到那一個IP地址, 你可以用以下的docker inspect指令

docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name

例如要查詢mysql800的ip地址你可以這樣

這樣說mysql579和mysql800是在同一個網段了, 那他們應該能溝通是不是? 我們試試看

記得上一篇我們用過docker exec來運行mysql800裡的mysql指令, 

我們也可以用來運行linux上的bash

docker exec -it mysql579 bash

可以見到, 進入Bash後我們可以ping 到mysql800的IP地址, 那就是說他們的網絡是接通的.

知道了這個後我們可以理解. 每一個docker run都會把container放到預設172.17.0.0這個網絡上

而且他們是能夠互相溝通的, 就如之前所說, 如果我們有一個PHP站台, 背後有一個mysql的資料庫

就只需要把站台的80或443埠發佈出來, 而整個架構背後就以bridge來互相連接.

 

這樣我們會想, 如果現在要建立一套擁有幾個container 的系統,

他們應該是處於一個獨立運作的網絡裡, 和其他的container 分別開來, 

這樣無論是架構上或是設計理念上也是比較好的.

現在就看看如何新增一個新的網絡, 和把container指派到這些指定的網絡上吧

舉例我現在要建立一個新的網絡叫JustinNetwork, Driver使用bridge (不選擇的話預設也是bridge), 指令如下

docker network create -d bridge JustinNetwork

這樣我們就有一個新的網絡接橋可以使用了, 查看他的屬性

會見到JustinNetwork自動地擁有172.18.0.0/16這個網段. 再建立下去就會是172.19.0.0/16 , 172.20.0.0/16

如果你要自定一個subnet, 你可以用 --subnet 參數來設定, 例如建立一個叫FionaNetwork 192.168.0.0/16的網絡

docket network create -d bridge --subnet=192.168.0.0/16 FionaNetwork

如果我們要新建一個container, 而不想它被自己發配到bridge這個預設網絡想, 我們可以加想 --net 參數

例如在建立mysql579時就把它放到JustinNetwork的方式是

docker run --name mysql579 --net JustinNetwork -e MYSQL_ROOT_PASSWORD=Nosecret -d mysql:5.7.9

現在我們有2個新的網絡JustinNetwork和FionaNetwork了,

如果mysql579如預設先接到bridge, 現在我們想把他接駁上JustinNetwork

指令是 docker network connect JustinNetwork mysql579

再查看mysql579的IP地址

可以看到mysql579連接到JustinNetwork並不代表他沒有從bridge網絡斷線

要把它抽離bridge network我們要用docker network disconnect指令

再試試在mysql579的bash來ping mysql800的172.17.0.3

他們現在不能接通了. 這樣我們可以實現把不同項目的container 分隔開來的方法.

那我們可以ping 其他東西嗎? 例如www.yahoo.com

可以哦, 而且它可以解釋到116.214.12.74這個IP地址

但這個mysql579我們沒有讓它接上網際網絡, 它的DNS結果是從那裡來的?

如果我們查看這個container的dns nameserver設定  (cat /etc/resolv.conf)

會發現他是向127.0.0.11查詢DNS要求的, 這是Docker的內嵌DNS服務

借助host的dns連接能力來查詢DNS名稱, 而且search network也是抄過來的

如果你的Host沒有設定DNS Server的IP或填上127.0.0.1

Docker會把nameserver設定成Google 的DNS服務地址 8.8.8.8和 8.8.4.4來達成對外的DNS解釋

如果Host有啟動IPv6的話側會再加入2001:4860:4860::8888 和 2001:4860:4860::8844.

現在我們可以來解釋一起始我們見到預設的3個網絡, 第一個是bridge, 我們已經知道用途了

還有兩個叫host和none, 我們試試把mysql 分別接想host和none的網絡

可以看到host網絡不容許container連接, 因為它是host專屬的

而none,顧名思義就是沒有網絡連接能力, 如果我們把mysql579接到none上

可以看到他再次ping www.yahoo.com就得不到任何回應了.

如果你會看docker network ls, 你會發現none網絡是沒有給予DRIVER的.

這篇把Docker Network基本上試了一遍, 下一篇我們再加進一點元素, 看看不同的container如何互動.