Website logo

Robert Chang

技術部落格

Docker - 虛擬網路中的 DNS 有什麼不同?

這篇文章要來介紹的是 DNS 這個名詞。

這邊先介紹一下 DNS 本身代表什麼,本名:網域名稱系統( 英語:Domain Name System,縮寫:DNS ),簡單的說就是網際網路世界的電話簿,那為什麼我們會需要這樣的電話簿呢?

相信大家應該都知道網際網路的互動是透過 IP 位置來找到對方並進行訊息的傳送,但舉個簡單的例子好了,你在網址中輸入 https://142.251.42.238 會前往 google.com,但你平常真的會輸入一大段 IP 位置嗎?也太難記了吧!

而 DNS 就是當你輸入 google.com 時會幫你去找到 https://142.251.42.238 的系統,可以想像 IP 位置就是真實的地址,而 DNS 則是一個別名的概念,就像大家常常會提到北車 ( 台北車站 ),但你真的知道台北車站的地址嗎?你需要知道地址才可以到達台北車站嗎?

Docker 中的 DNS

好的,現在我們了解了 Docker 虛擬網路的基本概念以及 DNS 了。

在 Docker 的世界,我們可以忘掉 IP 位置這件事情,就像前面有提過的,IP 位置會由 Docker 分配,每次容器啟動的時機不同,快一秒或慢一秒就會導致每個容器的 IP 位置不相同。

所以若是要透過 IP 位置來讓容器們彼此溝通顯然是不切實際的事情。

這時候剛剛提到的 DNS 就是 Docker 提出的解決方案,要如何可以一直連線到某一個服務而不論其啟動順序、重新開啟之後呢?

答案就是在一開始我們就學到的 --name 這個選項,當我們替容器命名後,在 Docker 的虛擬網路中,我們為他的命名就會是這個服務的 DNS,我們可以透過容器的名字輕易的訪問到容器本身。

下面我們用 IP 位置來連接到另外一個容器做一次比較不好的示範,來看看如果容器啟動的順序不同會導致什麼樣的問題!

如果使用 IP 位置來溝通…

首先清空所有的容器吧!

$ docker container rm -f $(docker container ls -aq)

把接下來的容器都放到剛剛建立的 app 虛擬網路裡面執行

$ docker container run --publish 3000:3000 --detach --name whoami --network app robeeerto/whoami # 不換行

接著打開瀏覽器輸入 http://127.0.0.1:3000 應該會看到畫面顯示著:

容器名稱:eb356e256481 # 這邊不會和我一樣
容器的 IP 位置:172.26.0.2 # 這邊不會和我一樣
環境變數 AUTHOR 是:robertchang # 這邊會一樣

這邊的容器名稱就是剛剛啟動容器的 ID,而 IP 位置則是前面介紹過 Docker 分配的 IP 位置,至於第三個環境變數,則等到介紹映像檔時才會進行解說,所以這邊可以暫時不理,接著我們在啟動第二個相同的容器吧!

$ docker container run --publish 3001:3000 --detach --name whoami-2 --network app robeeerto/whoami # 不換行

接著打開瀏覽器輸入 http://127.0.0.1:3001 應該會看到畫面顯示著:

容器名稱:c531f601ebf8 # 這邊不會和我一樣
容器的 IP 位置:172.26.0.3 # 這邊不會和我一樣
環境變數 AUTHOR 是:robertchang # 這邊會一樣

所以現在在 app 的虛擬網路中有著 whoami 以及 whoami-2 兩個容器,接著我們試著用 IP 位置的方式來進行溝通吧!

$ docker container exec -it whoami sh # 進入第一個容器
/ # curl 172.26.0.3:3000
容器名稱:c531f601ebf8<br>容器的 IP 位置:172.26.0.3<br>環境變數 AUTHOR 是:robertchang
# 這邊確實利用了 IP 位置和第二個容器進行了互動

這裡或許會有人疑惑,為什麼是 curl 172.26.0.3:3000 而不是 172.26.0.3:3001

明明 whoami-2 這個容器是 --publish 3001:3000 呀!

會有這個疑問是非常正常的,首先可以回想一下左邊的 port 代表的是什麼意思?

是在這台機器上對應的 port 而不是容器本身打開的 port,所以在相同的虛擬網路中,whoami 這個容器要找到 whoami-2 這個容器並不需要從外部的連線進入。

而是直接透過容器本身在虛擬網路的 IP 位置或是容器名稱 ( DNS ) 加上打開的 port 進行連線即可,透過下方圖片可以更清楚的了解。

how docker network works

若是容器啟動的順序不同

上一個範例乍看之下沒有什麼問題,但如果把剛剛的流程走過一次但在中間穿插一個不一樣的服務會發生什麼事呢?

$ docker container rm -f $(docker container ls -aq)
# 清空所有容器

$ docker container run --publish 3000:3000 --detach --name whoami --network app robeeerto/whoami # 不換行

$ docker container run --detach --name pg -e POSTGRES_PASSWORD=mysecretpassword --network app postgres # 不換行

$ docker container run --publish 3001:3000 --detach --name whoami-2 --network app robeeerto/whoami # 不換行

現在我們的 app 虛擬網路中有了 whoami & pg & whoami-2 三個容器,且啟動的順序是在兩個 whoami 的容器中間穿插了 pg,讓我們繼續用 IP 位置來嘗試連線 whoami-2 這個容器吧!

$ docker container exec -it whoami sh # 進入第一個容器
/ # curl 172.26.0.3:3000
curl: (7) Failed to connect to 172.26.0.3 port 3000 after 1 ms: Connection refused

依照相同的 IP 位置去做連線就會發生這種狀況,因為啟動順序的調整,目前 172.26.0.3 這個 IP 位置被 pg 這個容器給拿走了。

這在之後的 Docker Compose 章節更是大忌,畢竟容器啟動的順序在少量的情況下還可以手動控制,但若是幾百個容器時,根本沒辦法靠 IP 位置溝通。

所以依照上一小節的作法,我們能夠利用替容器取的名字來替代 IP 位置進行連線。

/ # curl whoami-2:3000
容器名稱:6c95c42a6ece<br>容器的 IP 位置:172.26.0.4<br>環境變數 AUTHOR 是:robertchang

耶!又成功的和 whoami-2 這個容器進行連線了。

結語

今天介紹了 Docker 虛擬網路中的 DNS 系統,透過容器的名字,可以讓容器們彼此溝通。

明天開始,就會進入映像檔的章節。

上一篇文章Docker - Network 的基礎指令

下一篇文章Docker - 什麼是映像檔( Image )?