6 張圖詳解 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 種網絡模式

ByjhRO

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 模式如下圖所示:

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

Docker 網橋是宿主機虛擬出來的,並不是真實存在的網絡設備,外部網絡是無法尋址到的,這也意味着外部網絡無法通過直接 Container-IP 訪問到容器。如果容器希望外部訪問能夠訪問到,可以通過映射容器端口到宿主主機(端口映射),即 docker run 創建容器時候通過 -p 或 -P 參數來啓用,訪問容器的時候就通過 [宿主機 IP]:[容器端口] 訪問容器。

container 模式

這個模式指定新創建的容器和已經存在的一個容器共享一個 Network Namespace,而不是和宿主機共享。新創建的容器不會創建自己的網卡,配置自己的 IP,而是和一個指定的容器共享 IP、端口範圍等。同樣,兩個容器除了網絡方面,其他的如文件系統、進程列表等還是隔離的。兩個容器的進程可以通過 lo 網卡設備通信。

container 模式如下圖所示:

host 模式

如果啓動容器的時候使用 host 模式,那麼這個容器將不會獲得一個獨立的 Network Namespace,而是和宿主機共用一個 Network Namespace。容器將不會虛擬出自己的網卡,配置自己的 IP 等,而是使用宿主機的 IP 和端口。但是,容器的其他方面,如文件系統、進程列表等還是和宿主機隔離的。

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

Host 模式如下圖所示:

none 模式

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

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

應用場景:

none 模式如下圖所示:

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=ttl=64 time=0.029 ms
64 bytes from 127.0.0.1: icmp_seq=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 連接起來。

創建 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

 ``` ```sql
[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=ttl=64 time=0.033 ms
64 bytes from 192.0.0.1: icmp_seq=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=ttl=64 time=0.025 ms
64 bytes from 192.0.0.2: icmp_seq=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=ttl=127 time=31.929 ms
64 bytes from 182.61.200.7: seq=ttl=127 time=41.062 ms
64 bytes from 182.61.200.7: seq=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 選項的使用格式:

動態端口指的是隨機端口,具體的映射結果可使用 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

創建一個額外的自定義橋,區別於 docker0

[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)

再創建一個容器,使用默認的 bridge 橋:

[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)

轉自:馬哥 Linux 運維

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/RCG7TlkBaYIx5s55zMhmgA