iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0
DevOps

那些關於 docker 你知道與不知道的事系列 第 23

Day 23: container 怎麼跟別人溝通呢?

  • 分享至 

  • xImage
  •  

我們終於「擺脫」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

先讓我們從 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

https://ithelp.ithome.com.tw/upload/images/20221008/20151857TNiMMWGDI7.png

這裡也可以看到這個 container 沒有被分配到 ip。這時候也可以去觀察一下 host 的 ip addr,是不會有什麼變化的。

host

再來是 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 上一模一樣。

https://ithelp.ithome.com.tw/upload/images/20221008/20151857xJGbyw8weN.png

一樣沒有分配 ip,這也很好理解,都直接用 host 這個網路了。

bridge

會使用預設 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 一下:
https://ithelp.ithome.com.tw/upload/images/20221008/20151857FWvJJRsHf7.png

這次 GatewayIPAddress 都有被設置了。既然這邊有了不同的變化,那讓我們去看一下 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 有關,來把他們放近一點看:
https://ithelp.ithome.com.tw/upload/images/20221008/20151857Zz38lWdKXQ.png

container

既然已經啟動了一個 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 觀察一下:
https://ithelp.ithome.com.tw/upload/images/20221008/20151857LGYcejJKKS.png

嗯,什麼都沒有,比 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 的網路之間又有什麼交互作用呢?這些問題就會是我們接下來幾天想要探討的,再讓我們一起來研究吧!


上一篇
Day 22: Ubuntu 的 /bin/sh 怎麼了?
下一篇
Day 24: 什麼是 veth pair?
系列文
那些關於 docker 你知道與不知道的事32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
highwall
iT邦新手 5 級 ‧ 2022-10-19 12:01:29

花了快三天把全部看完了,收穫很多,非常謝謝 Ashley
關於 docker networking 的部分,覺得這個講得蠻清楚的,提供參考~

from 大狗的朋友

小賴 iT邦新手 4 級 ‧ 2022-10-19 12:04:30 檢舉

哇,太棒了,謝謝你的分享!

我要留言

立即登入留言