天天看點

5 年工作經驗,Docker 的幾種網絡模式都說不清,你敢信?

docker 容器網絡

Docker 在安裝後自動提供 3 種網絡,可以使用 docker network ls 指令檢視

[root@localhost ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
cd97bb997b84        bridge              bridge              local
0a04824fc9b6        host                host                local
4dcb8fbdb599        none                null                local      

Docker 使用 ​

​Linux 橋接​

​​,在主控端虛拟一個 Docker ​

​容器網橋(docker0)​

​,Docker 啟動一個容器時會根據 Docker 網橋的網段配置設定給容器一個 IP 位址,稱為 Container-IP,同時 Docker 網橋是每個容器的預設網關。因為在同一主控端内的容器都接入同一個網橋,這樣容器之間就能夠通過容器的 Container-IP 直接通信。

docker 的 4 種網絡模式

5 年工作經驗,Docker 的幾種網絡模式都說不清,你敢信?
5 年工作經驗,Docker 的幾種網絡模式都說不清,你敢信?

bridge 模式

當 Docker 程序啟動時,會在主機上建立一個名為 docker0 的虛拟網橋,此主機上啟動的 Docker 容器會連接配接到這個虛拟網橋上。虛拟網橋的工作方式和實體交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網絡中。

從 docker0 子網中配置設定一個 IP 給容器使用,并設定 docker0 的 IP 位址為容器的預設網關。在主機上建立一對虛拟網卡 veth pair 裝置,Docker 将 veth pair 裝置的一端放在新建立的容器中,并命名為 eth0(容器的網卡),另一端放在主機中,以 vethxxx 這樣類似的名字命名,并将這個網絡裝置加入到 docker0 網橋中。可以通過 ​

​brctl show​

​ 指令檢視。

bridge 模式是 docker 的​

​預設網絡模式​

​,不寫--network 參數,就是 bridge 模式。使用 docker run -p 時,docker 實際是在 iptables 做了 DNAT 規則,實作端口轉發功能。可以使用 iptables -t nat -vnL 檢視。

bridge 模式如下圖所示:

5 年工作經驗,Docker 的幾種網絡模式都說不清,你敢信?

假設上圖的 docker2 中運作了一個 nginx,大家來想幾個問題:

  • 同主機間兩個容器間是否可以直接通信?比如在 docker1 上能不能直接通路到 docker2 的 nginx 站點?
  • 在主控端上能否直接通路到 docker2 的 nginx 站點?
  • 在另一台主機上如何通路 node1 上的這個 nginx 站點呢?DNAT 釋出?

Docker 網橋是主控端虛拟出來的,并不是真實存在的網絡裝置,外部網絡是無法尋址到的,這也意味着外部網絡無法通過直接 Container-IP 通路到容器。如果容器希望外部通路能夠通路到,可以通過映射容器端口到宿主主機(端口映射),即 docker run 建立容器時候通過 -p 或 -P 參數來啟用,通路容器的時候就通過​

​[主控端 IP]:[容器端口]​

​通路容器。

container 模式

這個模式指定新建立的容器和已經存在的一個容器共享一個 Network Namespace,而不是和主控端共享。新建立的容器不會建立自己的網卡,配置自己的 IP,而是和一個指定的容器共享 IP、端口範圍等。同樣,兩個容器除了網絡方面,其他的如檔案系統、程序清單等還是隔離的。兩個容器的程序可以通過 lo 網卡裝置通信。

container 模式如下圖所示:

5 年工作經驗,Docker 的幾種網絡模式都說不清,你敢信?

host 模式

如果啟動容器的時候使用 host 模式,那麼這個容器将不會獲得一個獨立的 Network Namespace,而是和主控端共用一個 Network Namespace。容器将不會虛拟出自己的網卡,配置自己的 IP 等,而是使用主控端的 IP 和端口。但是,容器的其他方面,如檔案系統、程序清單等還是和主控端隔離的。

使用 host 模式的容器可以直接使用主控端的 IP 位址與外界通信,容器内部的服務端口也可以使用主控端的端口,不需要進行 NAT,host 最大的優勢就是網絡性能比較好,但是 docker host 上已經使用的端口就不能再用了,網絡的隔離性不好。

Host 模式如下圖所示:

5 年工作經驗,Docker 的幾種網絡模式都說不清,你敢信?

none 模式

使用 none 模式,Docker 容器擁有自己的 Network Namespace,但是,并不為 Docker 容器進行任何網絡配置。也就是說,這個 Docker 容器沒有網卡、IP、路由等資訊。需要我們自己為 Docker 容器添加網卡、配置 IP 等。

這種網絡模式下​

​容器隻有 lo 回環網絡​

​,沒有其他網卡。none 模式可以在容器建立時通過--network none 來指定。這種類型的網絡沒有辦法聯網,封閉的網絡能很好的保證容器的安全性。

應用場景

  • 啟動一個容器處理資料,比如轉換資料格式
  • 一些背景的計算和處理任務

none 模式如下圖所示:

5 年工作經驗,Docker 的幾種網絡模式都說不清,你敢信?
docker network inspect bridge   #檢視bridge網絡的詳細配置      

docker 容器網絡配置

Linux 核心實作名稱空間的建立

ip netns 指令

可以借助 ip netns 指令來完成對 Network Namespace 的各種操作。ip netns 指令來自于 iproute 安裝包,一般系統會預設安裝,如果沒有的話,請自行安裝。

注意:ip netns 指令修改網絡配置時需要 sudo 權限。

可以通過 ip netns 指令完成對 Network Namespace 的相關操作,可以通過 ip netns help 檢視指令幫助資訊:

[root@localhost ~]# ip netns help
Usage: ip netns list
       ip netns add NAME
       ip netns set NAME NETNSID
       ip [-all] netns delete [NAME]
       ip netns identify [PID]
       ip netns pids NAME
       ip [-all] netns exec [NAME] cmd ...
       ip netns monitor
       ip netns list-id      

預設情況下,Linux 系統中是沒有任何 Network Namespace 的,是以 ip netns list 指令不會傳回任何資訊。

建立 Network Namespace

通過指令建立一個名為 ns0 的命名空間:

[root@localhost ~]# ip netns list
[root@localhost ~]# ip netns add ns0
[root@localhost ~]# ip netns list
ns0      

新建立的 Network Namespace 會出現在/var/run/netns/目錄下。如果相同名字的 namespace 已經存在,指令會報 Cannot create namespace file "/var/run/netns/ns0": File exists 的錯誤。

[root@localhost ~]# ls /var/run/netns/
ns0
[root@localhost ~]# ip netns add ns0
Cannot create namespace file "/var/run/netns/ns0": File exists      

對于每個 Network Namespace 來說,它會有自己獨立的網卡、路由表、ARP 表、iptables 等和網絡相關的資源。

操作 Network Namespace

ip 指令提供了 ip netns exec 子指令可以在對應的 Network Namespace 中執行指令。

檢視新建立 Network Namespace 的網卡資訊

[root@localhost ~]# ip netns exec ns0 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00      

可以看到,新建立的 Network Namespace 中會預設建立一個 lo 回環網卡,此時網卡處于關閉狀态。此時,嘗試去 ping 該 lo 回環網卡,會提示 Network is unreachable

[root@localhost ~]# ip netns exec ns0 ping 127.0.0.1
connect: Network is unreachable

127.0.0.1是預設回環網卡      

通過下面的指令啟用 lo 回環網卡:

[root@localhost ~]# ip netns exec ns0 ip link set lo up
[root@localhost ~]# ip netns exec ns0 ping 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.029 ms
^C
--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1036ms
rtt min/avg/max/mdev = 0.029/0.029/0.029/0.000 ms      

轉移裝置

我們可以在不同的 Network Namespace 之間轉移裝置(如 veth)。由于一個裝置隻能屬于一個 Network Namespace ,是以轉移後在這個 Network Namespace 内就看不到這個裝置了。

其中,veth 裝置屬于可轉移裝置,而很多其它裝置(如 lo、vxlan、ppp、bridge 等)是不可以轉移的。

veth pair

veth pair 全稱是 Virtual Ethernet Pair,是一個成對的端口,所有從這對端口一 端進入的資料包都将從另一端出來,反之也是一樣。

引入 veth pair 是為了在不同的 Network Namespace 直接進行通信,利用它可以直接将兩個 Network Namespace 連接配接起來。

5 年工作經驗,Docker 的幾種網絡模式都說不清,你敢信?

建立 veth pair

[root@localhost ~]# ip link add type veth
[root@localhost ~]# ip a

4: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 0a:f4:e2:2d:37:fb brd ff:ff:ff:ff:ff:ff
5: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 5e:7e:f6:59:f0:4f brd ff:ff:ff:ff:ff:ff      

可以看到,此時系統中新增了一對 veth pair,将 veth0 和 veth1 兩個虛拟網卡連接配接了起來,此時這對 veth pair 處于”未啟用“狀态。

實作 Network Namespace 間通信

下面我們利用 veth pair 實作兩個不同的 Network Namespace 之間的通信。剛才我們已經建立了一個名為 ns0 的 Network Namespace,下面再建立一個資訊 Network Namespace,命名為 ns1

[root@localhost ~]# ip netns add ns1
[root@localhost ~]# ip netns list
ns1
ns0      

然後我們将 veth0 加入到 ns0,将 veth1 加入到 ns1

[root@localhost ~]# ip link set veth0 netns ns0
[root@localhost ~]# ip link set veth1 netns ns1      

然後我們分别為這對 veth pair 配置上 ip 位址,并啟用它們

[root@localhost ~]# ip netns exec ns0 ip link set veth0 up
[root@localhost ~]# ip netns exec ns0 ip addr add 192.0.0.1/24 dev veth0
[root@localhost ~]# ip netns exec ns1 ip link set veth1 up
[root@localhost ~]# ip netns exec ns1 ip addr add 192.0.0.2/24 dev veth1      

檢視這對 veth pair 的狀态

[root@localhost ~]# ip netns exec ns0 ip a
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
4: veth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 0a:f4:e2:2d:37:fb brd ff:ff:ff:ff:ff:ff link-netns ns1
    inet 192.0.0.1/24 scope global veth0
       valid_lft forever preferred_lft forever
    inet6 fe80::8f4:e2ff:fe2d:37fb/64 scope link
       valid_lft forever preferred_lft forever      
[root@localhost ~]# ip netns exec ns1 ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: veth1@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 5e:7e:f6:59:f0:4f brd ff:ff:ff:ff:ff:ff link-netns ns0
    inet 192.0.0.2/24 scope global veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::5c7e:f6ff:fe59:f04f/64 scope link
       valid_lft forever preferred_lft forever      

從上面可以看出,我們已經成功啟用了這個 veth pair,并為每個 veth 裝置配置設定了對應的 ip 位址。我們嘗試在 ns1 中通路 ns0 中的 ip 位址

[root@localhost ~]# ip netns exec ns1 ping 192.0.0.1
PING 192.0.0.1 (192.0.0.1) 56(84) bytes of data.
64 bytes from 192.0.0.1: icmp_seq=1 ttl=64 time=0.033 ms
64 bytes from 192.0.0.1: icmp_seq=2 ttl=64 time=0.041 ms
^C
--- 192.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.033/0.037/0.041/0.004 ms
[root@localhost ~]# ip netns exec ns0 ping 192.0.0.2
PING 192.0.0.2 (192.0.0.2) 56(84) bytes of data.
64 bytes from 192.0.0.2: icmp_seq=1 ttl=64 time=0.025 ms
64 bytes from 192.0.0.2: icmp_seq=2 ttl=64 time=0.025 ms
^C
--- 192.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1038ms
rtt min/avg/max/mdev = 0.025/0.025/0.025/0.000 ms      

可以看到,veth pair 成功實作了兩個不同 Network Namespace 之間的網絡互動。

四種網絡模式配置

bridge 模式配置

[root@localhost ~]# docker run -it --name ti --rm busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:12 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1032 (1.0 KiB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)      

在建立容器時添加--network bridge 與不加--network 選項效果是一緻的

[root@localhost ~]# docker run -it --name t1 --network bridge --rm busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
         inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
         UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
         RX packets:8 errors:0 dropped:0 overruns:0 frame:0
         TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:0
         RX bytes:696 (696.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
         inet addr:127.0.0.1  Mask:255.0.0.0
         UP LOOPBACK RUNNING  MTU:65536  Metric:1
         RX packets:0 errors:0 dropped:0 overruns:0 frame:0
         TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:1000
         RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)      

none 模式配置

[root@localhost ~]# docker run -it --name t1 --network none --rm busybox
/ # ifconfig -a
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)      

container 模式配置

啟動第一個容器

[root@localhost ~]# docker run -dit --name b3 busybox
af5ba32f990ebf5a46d7ecaf1eec67f1712bbef6ad7df37d52b7a8a498a592a0

[root@localhost ~]# docker exec -it b3 /bin/sh
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:906 (906.0 B)  TX bytes:0 (0.0 B)      

啟動第二個容器

[root@localhost ~]# docker run -it --name b2 --rm busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03
          inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:516 (516.0 B)  TX bytes:0 (0.0 B)      

可以看到名為 b2 的容器 IP 位址是 10.0.0.3,與第一個容器的 IP 位址不是一樣的,也就是說并沒有共享網絡,此時如果我們将第二個容器的啟動方式改變一下,就可以使名為 b2 的容器 IP 與 B3 容器 IP 一緻,也即共享 IP,但不共享檔案系統。

[root@localhost ~]# docker run -it --name b2 --rm --network container:b3 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02
          inet addr:172.17.0.2  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:14 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1116 (1.0 KiB)  TX bytes:0 (0.0 B)      

此時我們在b1容器上建立一個目錄

/ # mkdir /tmp/data
/ # ls /tmp
data      

到 b2 容器上檢查/tmp 目錄會發現并沒有這個目錄,因為檔案系統是處于隔離狀态,僅僅是共享了網絡而已。

在 b2 容器上部署一個站點

/ # echo 'hello world' > /tmp/index.html
/ # ls /tmp
index.html
/ # httpd -h /tmp
/ # netstat -antl
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 :::80                   :::*                    LISTEN      

在 b1 容器上用本地位址去通路此站點

/ # wget -O - -q 172.17.0.2:80
hello world      

host 模式配置

啟動容器時直接指明模式為 host

[root@localhost ~]# docker run -it --name b2 --rm --network host busybox
/ # ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:B8:7F:8E:2C
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          inet6 addr: fe80::42:b8ff:fe7f:8e2c/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3 errors:0 dropped:0 overruns:0 frame:0
          TX packets:20 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:116 (116.0 B)  TX bytes:1664 (1.6 KiB)

ens33     Link encap:Ethernet  HWaddr 00:0C:29:95:19:47
          inet addr:192.168.203.138  Bcast:192.168.203.255  Mask:255.255.255.0
          inet6 addr: fe80::2e61:1ea3:c05a:3d9b/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:9626 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3950 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:3779562 (3.6 MiB)  TX bytes:362386 (353.8 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

veth09ee47e Link encap:Ethernet  HWaddr B2:10:53:7B:66:AE
          inet6 addr: fe80::b010:53ff:fe7b:66ae/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3 errors:0 dropped:0 overruns:0 frame:0
          TX packets:19 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:158 (158.0 B)  TX bytes:1394 (1.3 KiB)      

此時如果我們在這個容器中啟動一個 http 站點,我們就可以直接用主控端的 IP 直接在浏覽器中通路這個容器中的站點了。

容器的常用操作

檢視容器的主機名

[root@localhost ~]# docker run -it --name t1 --network bridge --rm busybox
/ # hostname
48cb45a0b2e7      

在容器啟動時注入主機名

[root@localhost ~]# docker run -it --name t1 --network bridge --hostname ljl --rm busybox
/ # hostname
ljl
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3 ljl
/ # cat /etc/resolv.conf
# Generated by NetworkManager
search localdomain
nameserver 192.168.203.2
/ # ping www.baidu.com
PING www.baidu.com (182.61.200.7): 56 data bytes
64 bytes from 182.61.200.7: seq=0 ttl=127 time=31.929 ms
64 bytes from 182.61.200.7: seq=1 ttl=127 time=41.062 ms
64 bytes from 182.61.200.7: seq=2 ttl=127 time=31.540 ms
^C
--- www.baidu.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 31.540/34.843/41.062 ms      

手動指定容器要使用的 DNS

[root@localhost ~]# docker run -it --name t1 --network bridge --hostname ljl --dns 114.114.114.114 --rm busybox
/ # cat /etc/resolv.conf
search localdomain
nameserver 114.114.114.114
/ # nslookup -type=a www.baidu.com
Server:  114.114.114.114
Address: 114.114.114.114:53

Non-authoritative answer:
www.baidu.com canonical name = www.a.shifen.com
Name: www.a.shifen.com
Address: 182.61.200.6
Name: www.a.shifen.com
Address: 182.61.200.7      

手動往/etc/hosts 檔案中注入主機名到 IP 位址的映射

[root@localhost ~]# docker run -it --name t1 --network bridge --hostname ljl --add-host www.a.com:1.1.1.1 --rm busybox
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
1.1.1.1 www.a.com
172.17.0.3 ljl      

開放容器端口

執行 docker run 的時候有個-p 選項,可以将容器中的應用端口映射到主控端中,進而實作讓外部主機可以通過通路主控端的某端口來通路容器内應用的目的。

-p 選項能夠使用多次,其所能夠暴露的端口必須是容器确實在監聽的端口。

  • -p 選項的使用格式:
  • -p containerPort
  • 将指定的容器端口映射至主機所有位址的一個動态端口
  • -p hostPort : containerPort
  • 将容器端口 containerPort 映射至指定的主機端口 hostPort
  • -p ip :: containerPort
  • 将指定的容器端口 containerPort 映射至主機指定 ip 的動态端口
  • -p ip : hostPort : containerPort
  • 将指定的容器端口 containerPort 映射至主機指定 ip 的端口 hostPort

動态端口指的是随機端口,具體的映射結果可使用 docker port 指令檢視。

[root@localhost ~]# docker run -dit --name web1 -p 192.168.203.138::80 httpd
e97bc1774e40132659990090f0e98a308a7f83986610ca89037713e9af8a6b9f
[root@localhost ~]# docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED          STATUS          PORTS                           NAMES
e97bc1774e40   httpd     "httpd-foreground"   6 seconds ago    Up 5 seconds    192.168.203.138:49153->80/tcp   web1
af5ba32f990e   busybox   "sh"                 48 minutes ago   Up 48 minutes                                   b3
[root@localhost ~]# ss -antl
State    Recv-Q   Send-Q        Local Address:Port        Peer Address:Port   Process
LISTEN   0        128         192.168.203.138:49153            0.0.0.0:*
LISTEN   0        128                 0.0.0.0:22               0.0.0.0:*
LISTEN   0        128                    [::]:22                  [::]:*      

以上指令執行後會一直占用着前端,我們新開一個終端連接配接來看一下容器的 80 端口被映射到了主控端的什麼端口上

[root@localhost ~]# docker port web1
80/tcp -> 192.168.203.138:49153      

由此可見,容器的 80 端口被暴露到了主控端的 49153 端口上,此時我們在主控端上通路一下這個端口看是否能通路到容器内的站點

[root@localhost ~]# curl http://192.168.203.138:49153
<html><body><h1>It works!</h1></body></html>      

iptables 防火牆規則将随容器的建立自動生成,随容器的删除自動删除規則。

[root@localhost ~]# iptables -t nat -nvL
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    3   164 DOCKER     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    4   261 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0
    0     0 MASQUERADE  tcp  --  *      *       172.17.0.3           172.17.0.3           tcp dpt:80

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    2   120 DOCKER     all  --  *      *       0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain DOCKER (2 references)
 pkts bytes target     prot opt in     out     source               destination
    1    60 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0
    1    60 DNAT       tcp  --  !docker0 *       0.0.0.0/0            192.168.203.138      tcp dpt:49153 to:172.17.0.3:80      

将容器端口映射到指定 IP 的随機端口

[root@localhost ~]# docker run -dit --name web1 -p 192.168.203.138::80 httpd      

在另一個終端上檢視端口映射情況

[root@localhost ~]# docker port web1
80/tcp -> 192.168.203.138:49153      

自定義 docker0 橋的網絡屬性資訊

自定義 docker0 橋的網絡屬性資訊需要修改/etc/docker/daemon.json 配置檔案

[root@localhost ~]# cd /etc/docker/
[root@localhost docker]# vim daemon.json
[root@localhost docker]# systemctl daemon-reload
[root@localhost docker]# systemctl restart docker

{
    "registry-mirrors": ["https://4hygggbu.mirror.aliyuncs.com/"],
    "bip": "192.168.1.5/24"
}
EOF

``` ```ruby
[root@localhost ~]# vim /lib/systemd/system/docker.service

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375  -H unix:///var/run/docker.sock
[root@localhost ~]# systemctl daemon-reload
[root@localhost ~]# systemctl restart docker      

在用戶端上向 dockerd 直接傳遞“-H|--host”選項指定要控制哪台主機上的 docker 容器

[root@localhost ~]# docker -H 192.168.203.138:2375 ps
CONTAINER ID   IMAGE     COMMAND              CREATED             STATUS          PORTS                           NAMES
e97bc1774e40   httpd     "httpd-foreground"   30 minutes ago      Up 11 seconds   192.168.203.138:49153->80/tcp   web1
af5ba32f990e   busybox   "sh"                 About an hour ago   Up 14 seconds                                   b3      

建立新網絡

[root@localhost ~]# docker network create ljl -d bridge
883eda50812bb214c04986ca110dbbcb7600eba8b033f2084cd4d750b0436e12
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
0c5f4f114c27   bridge    bridge    local
8c2d14f1fb82   host      host      local
883eda50812b   ljl       bridge    local
85ed12d38815   none      null      local      
[root@localhost ~]# docker network create -d bridge --subnet "192.168.2.0/24" --gateway "192.168.2.1" br0
af9ba80deb619de3167939ec5b6d6136a45dce90907695a5bc5ed4608d188b99
[root@localhost ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
af9ba80deb61   br0       bridge    local
0c5f4f114c27   bridge    bridge    local
8c2d14f1fb82   host      host      local
883eda50812b   ljl       bridge    local
85ed12d38815   none      null      local      

使用新建立的自定義橋來建立容器:

[root@localhost ~]# docker run -it --name b1 --network br0 busybox
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:C0:A8:02:02
          inet addr:192.168.2.2  Bcast:192.168.2.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:962 (962.0 B)  TX bytes:0 (0.0 B)      
[root@localhost ~]# docker run --name b2 -it busybox
/ # ls
bin   dev   etc   home  proc  root  sys   tmp   usr   var
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:C0:A8:01:03
          inet addr:192.168.1.3  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:516 (516.0 B)  TX bytes:0 (0.0 B)