跳至主要内容

3.1 Docker 的虛擬網路概念

在上一個章節中我們了解了容器的生命週期、如何進入容器內部以及最後提到關於容器的 IP 位置,也算是對容器有了一些基本的瞭解。

但是這樣子似乎和串連成為一個服務還有很大的距離,想像中最基本的 Web 應用程式應該會有一個 Web Server ( Nginx, Apache, Traefik... ),App Server ( Ruby on Rails, Laravel, Django ... ) 再搭配資料庫 ( PostgreSQL, MySQL, SQLite... )

能夠將這些服務串連在一起也是 Docker 如此強大的原因,可以透過 Docker 虛擬網路使得容器們相互溝通,或者將它們連接到非 Docker 的服務上,而 Docker 的容器或是服務本身不需要知道自己是不是被部署在 Docker 上,也不需要確認對方是不是也在 Docker 上。

無論你的主機是運行在 Linux、Windows 或是兩者混合,都可以用一個超脫作業系統框架的方式來管理它們。

接下來的內容講述了一些基本的 Docker 網路概念,為了後面 Docker Compose 章節以及部署 Web 應用程式做足準備。

電腦的防火牆

2-4 容器的 IP 位置以及 Port 的結尾,我們發現 Docker 容器的 IP 位置和本機電腦的 IP 位置不相同,至於是為什麼呢?這就需要更仔細地了解外部網路請求是如何進入到容器內部,那肯定不能錯過關於電腦的防火牆。

相信這個名字大家一定不陌生,尤其從小玩 Windows 桌機長大的小孩,一定常常看到關於防火牆設定的通知跳出來,那這到底是什麼,跟 Docker 的虛擬網路又有什麼關係呢?

防火牆最一開始的意思,是古人使用木頭建造房屋時,為了避免火災發生及蔓延,將堅固石塊堆砌在房屋周圍做為屏障,這種防護結構建築就被稱為防火牆。

現代網路也參照這個寓意,指隔離本機網路與外界網路的一道防禦系統,藉由控制過濾限制訊息來保護內部網路資料的安全。

超簡易的防火牆示意圖

防火牆本身預設阻止所有從網際網路中進來的流量;提到防火牆就是希望透過這個方式更理解 Docker 是如何向網際網路打開大門,並讓外部的請求進入到容器內部。

打開防火牆

正常情況下,Docker 預設會用一個叫做 bridge 的虛擬網路,我們可以透過 docker network list 指令查看:

$ docker network list
NETWORK ID NAME DRIVER SCOPE
8089a4c2e32...... bridge bridge local
....

而就是這個虛擬網路幫助我們橋接了本機的網路介面,讓我們可以透過簡單的 --publish 參數,快速的啟動容器並對應到防火牆該開啟哪個 port。

而若是沒有指定虛擬網路的情況下,Docker 都會默認使用這個 bridge 的虛擬網路,以一開始的 nginx 容器為例,搭配下方的圖片:

容器預設接上 bridge 虛擬網路

這和一開始介紹容器生命週期時所繪製的圖很相似,多加上了防火牆以及虛擬網路。

這也牽扯到 2-4 容器的 IP 位置以及 Port 最後提到關於容器以及本機不同 IP 位置的問題,為什麼 nginx 的容器預設不會被分配到和本機相同的 IP 位置呢?

是因為沒有指定網路的話,容器都會以 Docker 的 bridge 虛擬網路為優先並連接上去,所以不同的網路環境當然會顯示不相同的 IP 位置。

我們也可以透過 inspect 的指令來查看 bridge 這個虛擬網路本身的 IP 位置:

$ docker network inspect bridge
[
...
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
...
]

可以觀察到在 Config 裡面的 Gateway 寫著 172.17.0.1,而我們啟動的 nginx 服務則是在 172.17.0.2,若是我們在開一個 nginx 服務呢?

$ docker container run --detach --publish 8080:80 --name nginx2 nginx # 不換行
b76c49631846d8b2249f7c4c...

$ docker container inspect --format '{{ .NetworkSettings.IPAddress }}' nginx2 # 不換行
172.17.0.3

如同上文所說,在沒有指定虛擬網路的情況下,Docker 預設使用 bridge 這個虛擬網路,而 Docker 則替我們在 bridge 這個網路內分配了 IP 位置。

但即使容器被分配到了不同的 IP 位置,但這又和網際網路的請求能夠進入容器內部有什麼關係呢?是因為使用了 NAT 的技術!

NAT ( 網路位址轉換 )

Docker 透過了 NAT ( 網路位址轉換 ) 這項技術,讓外部的請求進入 Docker 並順著虛擬網路找到容器,而 NAT 這項技術被廣泛地使用在許多公司的內部網路,或是私人企業的內網。

主要原因是 IPv4 位置稀少,而很多企業或網路公司在只擁有少數 IP 位置情況下,但公司內部確有太多電腦要連接網路,故採取共用 IP 的解決方法,就是讓一個 IP 位置給多臺電腦使用。

使用者上網後,拿到一個 IP 位置,而 IP 分享器或無線基地台則將一組專門給內部使用的私有IP ,分配給所有內部電腦,內部每台電腦擁有一個192.168.0.x 的 IP 位置, 但無線基地台對外卻只有一個由網路公司賦予的 IP 位置。

通常 NAT 將每一部電腦所用的 IP,對應到共用 IP,且 NAT 負責將進出封包的 Header 進行轉換使得內部電腦可以輕鬆地與外部網路連線溝通。

用上述的例子,我們可以想像 Docker 本身就是負責分配 IP 的機器,而在 Docker 上運作的容器都是公司內部的電腦,被分配了一個 IP 位置,但主要外面的入口還是要通過 Docker 來處理底層的網路技術。