【Docker】(11)---Docker的網路概念

雨點的名字發表於2021-10-21

一、實現原理

1、實現原理

Docker使用Linux橋接,在宿主機虛擬一個Docker容器網橋(docker0),Docker啟動一個容器時會根據Docker網橋的網段分配給容器一個IP地址,稱為Container-IP,

同時Docker網橋是每個容器的預設閘道器。因為在同一宿主機內的容器都接入同一個網橋,這樣容器之間就能夠通過容器的Container-IP直接通訊。

Docker網橋是宿主機虛擬出來的,並不是真實存在的網路裝置,外部網路是無法定址到的,這也意味著外部網路無法通過直接Container-IP訪問到容器。如果容器希望外部訪問能夠

訪問到,可以通過對映容器埠到宿主主機(埠對映),即docker run建立容器時候通過 -p 或 -P 引數來啟用,訪問容器的時候就通過[宿主機IP]:[容器埠]訪問容器。


二、四種網路模式

安裝Docker時,它會自動建立三個網路,bridge(建立容器預設連線到此網路)、 nonehost

【Docker】(11)---Docker的網路概念

安裝好docker,我們可以通過命令來檢視當前的網路模式

[root@izbp13196 ~]# docker network ls
NETWORK ID          NAME                         DRIVER              SCOPE
a6fb564d8107        bridge                       bridge              local
8f63ceca4d5a        host                         host                local
de62f8161011        none                         null                local

我們在使用docker run建立Docker容器時,可以用 --net 選項指定容器的網路模式,Docker可以有以下4種網路模式:

host模式:使用 --net=host 指定。
none模式:使用 --net=none 指定。
bridge模式:使用 --net=bridge 指定,預設設定。
container模式:使用 --net=container:NAME_or_ID 指定。

下面分別介紹一下Docker的各個網路模式。

1、Host模式

如果啟動容器時候使用host模式,那麼這個容器將不會獲得一個獨立的Network Namespace,而是和宿主機共用一個NetworkNamespace。容器將不會虛擬出自己的網路卡,

配置自己的IP等,而是使用宿主機的IP和埠。但是,容器的其他方面,如檔案系統、程式列表等還是和宿主機隔離的。

使用host模式的容器可以直接使用宿主機的IP地址與外界通訊,容器內部的服務埠也可以使用宿主機的埠,host最大的優勢就是網路效能比較好,但是docker host上已經

使用的埠就不能再用了,網路的隔離性不好。

【Docker】(11)---Docker的網路概念

2、Container模式

這個模式指定新建立的容器和已經存在的一個容器共享一個Network Namespace,而不是和宿主機共享。新建立的容器不會建立自己的網路卡,配置自己的IP,而是和一個指定的

容器共享IP、埠範圍等。同樣,兩個容器除了網路方面,其他的如檔案系統、程式列表等還是隔離的。兩個容器的程式可以通過lo網路卡裝置通訊。

【Docker】(11)---Docker的網路概念

3、none模式

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

自己為Docker容器新增網路卡、配置IP等。

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

的安全性。

4、bridge模式

當Docker程式啟動時,會在主機上建立一個名為docker0的虛擬網橋,此主機上啟動的Docker容器會連線到這個虛擬網橋上。容器啟動時,Docker會建立一對veth pair

(虛擬網路介面)裝置,veth裝置的特點是成對存在,從一端進入的資料會同時出現在另一端。Docker會將一端掛載到docker0網橋上,另一端放入容器的Network Namespace

內,從而實現容器與主機通訊的目的。

bridge模式是docker的預設網路模式,不寫--net引數,就是bridge模式。使用docker run -p時,docker實際是在iptables做了DNAT規則,實現埠轉發功能。

【Docker】(11)---Docker的網路概念

三、 學容器必須懂bridge網路

前面有說過 Docker啟動的時候會在主機上自動建立一個docker0網橋,實際上是一個Linux網橋,所有容器的啟動如果在docker run的時候如果不指定--network,都會掛載

到docker0網橋上。這樣容器就可以和主機甚至是其他容器之間通訊了。

具體看下圖片

【Docker】(11)---Docker的網路概念

1、新建立容器

如果只是安裝了docker,但並沒有啟動任何docker專案,我們可以看到當前 docker0 上沒有任何其他網路裝置

[root@izbp1319 ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242b79eef68       no                                                                   

這時我們建立一個容器看看有什麼變化。

#啟動容器
[root@izbp13196 ~]#  docker run -d httpd
#檢視容器
[root@izbp13196 ~]# docker ps
 CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS              PORTS                                            NAMES
 ae4959077e70        httpd                      "httpd-foreground"       17 minutes ago      Up 17 minutes       80/tcp                                           loving_ptolemy

再來檢視下網路裝置

[root@izbp13196wp34obmnd4avdz ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.0242b79eef68       no              vethb37e106                                                    

一個新的網路介面 vethb37e106 被掛到了 docker0 上,vethb37e106就是新建立容器的虛擬網路卡。

2、檢視新建容器網路配置

我們進入剛建立的容器內部,檢視網路配置。

# ae4959077e70為該容器id
[root@izbp13196 ~]# docker exec -it ae4959077e70 bash
root@ae4959077e70:/usr/local/apache2# 

先安裝ip命令,因為預設是沒有ip命令的,所以我們要先安裝這個命令,才能檢視當前容器網路地址

#先更新
root@ae4959077e70:/usr/local/apache2# apt-get update 
#在安裝iproute,如果安裝失敗那就安裝iproute2
root@ae4959077e70:/usr/local/apache2# apt-get install iproute

檢視網路

【Docker】(11)---Docker的網路概念

容器有一個網路卡 eth0@if1004。大家可能會問了,為什麼不是vethb37e106 呢?

實際上 eth0@if1004 和 vethb37e106 是一對 veth pair。veth pair 是一種成對出現的特殊網路裝置,可以把它們想象成由一根虛擬網線連線起來的一對網路卡,網路卡的一頭

(eth0@if1004)在容器中,另一頭(vethb37e106)掛在網橋 docker0 上,其效果就是將 eth0@if1004 也掛在了 docker0 上。

3、檢視宿主機

[root@izbp13196wp34obmnd4avdz ~]# ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
    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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:16:3e:14:50:2d brd ff:ff:ff:ff:ff:ff
    inet 172.16.255.238/20 brd 172.16.255.255 scope global eth0
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:b7:9e:ef:68 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
1004: vethb37e106@if1003: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP 
    link/ether d6:b4:d1:b6:ee:f0 brd ff:ff:ff:ff:ff:ff link-netnsid 11

把上面整理成一份圖大致就是下面這樣的

【Docker】(11)---Docker的網路概念

四、容器之間的通訊

1、容器內部能否ping通外部?

# 測試  執行一個tomcat
$ docker run -d --name tomcat01 tomcat
# 檢視主機網路地址
$ 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
551: vethbfc37e3@if550: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 1a:81:06:13:ec:a1 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::1881:6ff:fe13:eca1/64 scope link 
       valid_lft forever preferred_lft forever
# 進入容器內部,檢視網路地址    
$ docker exec -it 容器id 
$ ip addr
# 檢視容器內部網路地址 發現容器啟動的時候會得到一個 eth0@if551 ip地址,docker分配!
550: eth0@if551: <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
       
# 思考? linux能不能ping通容器內部! 可以 容器內部可以ping通外界嗎? 可以!
$ ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.074 ms

原因:我們每啟動一個docker容器,docker就會給docker容器分配一個ip,我們只要按照了docker,就會有一個docker0橋接模式,使用的技術是veth-pair技術!

2、容器之間能否ping通

【Docker】(11)---Docker的網路概念
# 啟動tomcat01 檢視ip地址為172.17.0.2
$ docker-tomcat docker exec -it tomcat01 ip addr  #獲取tomcat01的ip 172.17.0.2   
550: eth0@if551: <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
#啟動tomcat02 看能否ping通172.17.0.2
$ docker-tomcat docker exec -it tomcat02 ping 172.17.0.2 
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.098 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.071 ms
# 可以ping通

思考

雖然所我們通過tomcat02,能夠ping通tomcat1,但這裡不是直接ping通過的,而是通過路由器,也就是docker0,來進行橋接的。

【Docker】(11)---Docker的網路概念

參考

1、《每天5分鐘玩轉 Docker 容器技術》書籍

2、docker 進階

3、Docker網路詳解——原理篇

3、Docker的網路概念與網路模式



相關文章