這幾天在研究Kubernetes, 遇到一個有意思的nodejs鏡像:luksa/kubianode
# 不帶端口映射啓動容器
docker run -it -d luksa/kubia
# 鏈接到默認的Bridge網橋,容器IP是 172.17.0.2
以後,在宿主機使用容器IP和8080 端口可訪問該容器nodejs服務 linux
對此我有幾個疑問,這幾個疑問在我看來有點與我以前對docker 網絡的認知相沖突。
Q1. 不是說若是容器沒有端口映射,容器內外隔離嗎,怎麼在宿主機使用容器IP還能夠訪問?
Q2. 容器IP:80 訪問不到容器內nodejs服務,容器IP:8080能夠訪問,這個8080從哪裏來?git
host
網絡模型連到宿主機,因此能夠在宿主機經過容器IP訪問
- All containers without a --network specified, are attached to the default bridge network.
- In terms of Docker, a bridge network uses a software bridge which allows containers connected to the same bridge network to communicate, while providing isolation from containers which are not connected to that bridge network.
對於問題1,我有個誤區:沒有端口映射,容器內外網絡隔離,宿主機是沒法訪問容器的。
實際上,對於加入同一bridge網橋上的容器,網橋內外網絡確實是隔離的,網橋上的容器均可以相互鏈接。
而咱們的宿主機也在這個默認的bridge網橋設備上,其IP地址是網橋設備的網關(172.17.0.1)。github
Q3.那端口映射到底起什麼做用呢?
網橋模型確保了網橋內容器可相互訪問,但除此以外的宿主機網絡(127.0.0.1/宿主機物理IP)均不能訪問容器, 這也正是bridge網絡隔離的效果。
端口映射-p表示容器綁定宿主機的網卡端口來實現轉發訪問,綁定的網卡決定了你對外暴露的程度。web
docker run -it -d -p 127.0.0.1:8080:8080 luksa/kubia
那麼在宿主機內只能使用127.0.0.1:8080
可訪問容器 docker
docker run -it -d -p 10.201.80.126:8080:8080 luksa/kubia
那麼在宿主機內可以使用物理IP10.201.80.126:8080
訪問容器,這樣局域網機器就能訪問到容器了 3. 不寫IP,這樣會綁定到0.0.0.0,也就是宿主機全部的網卡。api
docker run -it -d -p 8080:8080 luksa/kubia
很顯然,宿主機內迴環地址和物理地址
都可以訪問該容器了。bash
容器IP:8080
訪問容器,8080是哪裏來的?8080是容器內nodejs進程的監聽端口,咱們在構建鏡像時本就無所謂使用expose指令
網絡
The EXPOSE instruction does not actually publish the port. It functions as a type of documentation between the person who builds the image and the person who runs the container, about which ports are intended to be published.app
因此在docekr ps時候,並不會在PORTS列顯示任何內容,可是經過容器IP可直接連通容器內進程監聽端口。
這是由於容器鏡像在構建的時候,通常在0.0.0.0
地址上監聽請求,這意味着程序在全部地址的8080端口上監聽請求。
這樣就延伸出一個有趣的現象,讓咱們進入容器內部:
docker exec -it 3cc9f428fc25 bash
curl 127.0.0.1:8080
curl 127.0.0.2:8080
curl 127.0.1:8080
curl 172.17.0.2:8080
curl 172.17.2:8080
幾個看起來錯誤的IP居然也能夠訪問nodejs服務, 這正是nodejs在http://0.0.0.0:8080
地址監聽請求的結果。
# 截取自該鏡像構建源碼: https://github.com/luksa/kubia-qps/blob/master/kubia-qps/app.js
var www = http.createServer(handler);
www.listen(8080);
# nodejs: server.listen([port[, host[, backlog]]][, callback]) api
If host is omitted, the server will accept connections on the unspecified IPv6 address (::) when IPv6 is available, or the unspecified IPv4 address (0.0.0.0) otherwise.
猜測,驗證,源碼支持,解答了我一開始的幾個疑問,對容器Bridge的網絡認知進一步加深。