我們終於「擺脫」process 的討論啦,接下來就讓我們進入網路的世界,我們在用 docker run
啟動 container 時,可以透過 --network
參數來進行不同的網路設定,這些不同的網路設定將會決定這個 container 要怎麼跟外部網路連接。根據官方文件,我們有以下幾種選擇:
bridge
: 會在預設的 bridge
上建立網路,至於這個 bridge
是什麼呢,容我們稍後討論,這邊要先知道的是,如果在啟動 container 時沒有指定 network,這會是預設的選項。none
: 顧名思義,就是沒有網路的意思,會完全禁止所有傳入跟傳出。container:<name|id>
: 如果這邊是設定一個 container 的 id 或是名稱,那就會重用這個 container 的網路。host
: 使用 host 上的網路。<network-name>|<network-id>
: 使用我們自定義的網路,這個也容我們後面再討論。不知道大家來記不記得,我們之前花了幾天時間討論 namespace,如果還記得的話,應該可以推測,這裡也會跟 namespace 脫離不了關係,就讓我們針對以上幾個選項分別做一點觀察。這次我們繼續用 ubuntu:20.04 來當作我們的實驗 image,不過這個 image 裡沒有 ip
指令,所以我先以 ubuntu:20.04 作為 base image,build 一個有安裝 ip
指令的 image 出來:
這個 Dockerfile 非常簡單,就是多安裝一個 iproute2
而已,我們將這個 Dockerfile build 成 ubuntu:net
image:
FROM ubuntu:20.04
RUN apt-get update \
&& apt-get install -y iproute2
然後我們先記錄一下目前 host 上的 net namespace:
ubuntu@ip-xxx:~/net$ sudo lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531840 net 116 1 root unassigned /run/docker/netns/default /sbin/init
目前 host 上的網路:
ubuntu@ip-xxx:~/net$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
link/ether 0e:24:0e:79:cc:2d brd ff:ff:ff:ff:ff:ff
inet 172.31.58.247/20 brd 172.31.63.255 scope global dynamic ens5
valid_lft 1825sec preferred_lft 1825sec
inet6 fe80::c24:eff:fe79:cc2d/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:ea:22:dd:97 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:eaff:fe22:dd97/64 scope link
valid_lft forever preferred_lft forever
ip addr
是用來顯示指派給所有網路介面的網址的指令(文件),這邊可以看到 host 上總共有 lo, ens5 及 docker0
,這個 docker0
看來就跟 docker 有關,我們可以先留意一下。
先讓我們從 none
開始,這會讓這個 container 沒有網路。
# 啟動一個 network 為 none 的 container
ubuntu@ip-xxx:~/net$ docker run -it --rm --network=none ubuntu:net /bin/bash
root@e80e1a88b34b:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
root@e80e1a88b34b:/# lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026532210 net 2 1 root unassigned /bin/bash
root@e80e1a88b34b:/#
這邊可以觀察到,當 network 設定為 none
時,在 container 裡只有一個 lo,而他的 net namespace 跟 host 上是不一樣的。這邊也算是證明的網路上的隔離性,明明 host 中是有 lo, ens5 跟 docker0 的,但 container 裡只有 lo。
到另外一個 terminal 去用 inspect 一下這個 container:
$ docker container inspect --format='{{ json .NetworkSettings }}' e80e1a88b34b | jq
這裡也可以看到這個 container 沒有被分配到 ip。這時候也可以去觀察一下 host 的 ip addr
,是不會有什麼變化的。
再來是 host,這會讓這個 container 直接使用 host 上的網路。
ubuntu@ip-xxx:~/net$ docker run -it --rm --network=host ubuntu:net /bin/bash
root@ip-xxx:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
link/ether 0e:24:0e:79:cc:2d brd ff:ff:ff:ff:ff:ff
inet 172.31.58.247/20 brd 172.31.63.255 scope global dynamic ens5
valid_lft 2357sec preferred_lft 2357sec
inet6 fe80::c24:eff:fe79:cc2d/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:ea:22:dd:97 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:eaff:fe22:dd97/64 scope link
valid_lft forever preferred_lft forever
root@ip-xxx:/# lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531840 net 2 1 root unassigned /bin/bash
這邊可以看到,ip addr
的結果跟在 host 上一樣,列出來的 net namespace 是 4026531840
,也跟 host 上的一樣,除了網路介面外,其實還有一個很直接的,就是這個 container 中的 hostname 也跟 host 上一模一樣。
一樣沒有分配 ip,這也很好理解,都直接用 host 這個網路了。
會使用預設 bridge 來設定網路,我們今天先著重在觀察,至於這是什麼,就留給明後天去討論嚕。
ubuntu@ip-xxx:~/net$ docker run -it --rm --network=bridge ubuntu:net /bin/bash
root@3b4b8107d717:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
268: eth0@if269: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
root@3b4b8107d717:/# lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026532212 net 2 1 root unassigned /bin/bash
這邊可以看到 net namespace 跟 host 是不一樣的,而且他會有一個 eth0@if269
的網路介面,其 ip 為 172.17.0.2,還記得 host 上的 docker0
嗎?這邊可以發現在 ip 上是有關連的。
inspect container 一下:
這次 Gateway
跟 IPAddress
都有被設置了。既然這邊有了不同的變化,那讓我們去看一下 host 的情況,透過在 host 執行 ip addr
,可以看到多了以下一組網路介面:
269: vethd124db5@if268: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 1a:e6:b9:ef:25:32 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::18e6:b9ff:feef:2532/64 scope link
valid_lft forever preferred_lft forever
這是在啟動了這個 container 之後才多出來的,且在 container 裡的那個網路介面叫做 eth0@if269
,這個 269 顯然跟 host 的這個 269 有關,來把他們放近一點看:
既然已經啟動了一個 container 3b4b8107d717
,那就讓我們來啟動另外一個 container,且這個新的 container 的網路設定指定使用 3b4b8107d717
這個 container 的。
ubuntu@ip-xxx:~/net$ docker run --rm -it --network=container:3b4b8107d717 ubuntu:net /bin/bash
root@3b4b8107d717:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
268: eth0@if269: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
root@3b4b8107d717:/# lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026532212 net 2 1 root unassigned /bin/bash
這邊可以看到,這個新的 container 的 net namespace 跟網路介面 eth0@if269 都跟上一個 container 一模一樣,hostname 也是,雖然新的這個 container 的 container id 是 717eb6b582ab
,但其 hostname 仍為上一個 container 的 container id 3b4b8107d717
。(container 裡的 hostname 預設為 container id 的前 12 碼。)
可以推想,這時候用 ip addr
去觀察 host 中的網路介面時,是不會多出什麼東西的。
用 inspect 觀察一下:
嗯,什麼都沒有,比 none
還空,也蠻合理的,這個方式就是讓這個新的 container 複用了 3b4b8107d717
這個 container 的網路。
這邊也可以再多做一個觀察,在用 lsns
列出 namespace 時,不要加上 -t
去篩選類別,這邊可以觀察到這兩個 container 的 mnt, uts, ipc, pid namespace id 都是不同的,只有 net, user 及 cgroup namespace 是一樣的。
這邊留個小實驗給大家動手試試看:既然 container 717eb6b582ab
是用了 container 3b4b8107d717
的網路,那如果 3b4b8107d717
先關閉,那會發生什麼事呢?
今天我們對幾種不同的網路設定做了一點觀察,大概知道了 net namespace 在不同的網路設定下會有什麼作用,但到底什麼是 docker0
?用了 bridge 後在 host 跑出來的 veth 又是什麼?docker 的網路跟 host 的網路之間又有什麼交互作用呢?這些問題就會是我們接下來幾天想要探討的,再讓我們一起來研究吧!
花了快三天把全部看完了,收穫很多,非常謝謝 Ashley
關於 docker networking 的部分,覺得這個講得蠻清楚的,提供參考~
from 大狗的朋友
哇,太棒了,謝謝你的分享!