1. 程式人生 > 其它 >20221202 Docker 3. 網路

20221202 Docker 3. 網路

Docker 網路

docker同樣有著很多不完善的地方,網路方面就是Docker比較薄弱的部分。

docker安裝後會自動建立3種網路:

  • bridge

  • host

  • none

docker network ls

理論部分

docker使用Linux橋接網絡卡,在宿主機虛擬一個docker容器網橋(docker0),docker啟動一個容器時會根據docker網橋的網段分配給容器一個IP地址,稱為Container-IP,同時docker網橋是每個容器的預設閘道器。因為在同一宿主機內的容器都接入同一個網橋,這樣容器之間就能夠通過容器的Container-IP直接通訊。

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

建立容器時候通過 -p-P 引數來啟用,訪問容器的時候就通過 [宿主機IP]:[容器埠] 訪問容器。

# 使用命令檢視docker網路部分
docker info

網路介面的命名

eth0: ethernet的簡寫,一般用於乙太網介面。

wifi0:wifi是無線區域網,因此wifi0一般指無線網路介面。

ath0: Atheros的簡寫,一般指Atheros晶片所包含的無線網路介面。

lo: local的簡寫,一般指本地環回介面。

網路模式

Docker網路模式 配置 說明
host --net=host 容器和宿主機共享Network namespace。 容器將不會虛擬出自己的網絡卡,配置自己的IP 等, 而是使用宿主機的IP和埠。
container --net=container:NAME_or_ID 容器和另外一個容器共享Network namespace。
kubernetes中的pod就是多個容器共享一個 Network namespace。
建立的容器不會建立自己的網絡卡,配置自己的 IP, 而是和一個指定的容器共享IP、埠範圍。
none --net=none 容器有獨立的Network namespace,並沒有對其進行任何網路設定, 如分配 veth pair 和網橋連線,配置IP等。
該模式關閉了容器的網路功能。
bridge --net=bridge 預設為該模式
此模式會為每一個容器分配、設定IP等, 並將容器連線到一個 docker0 虛擬網橋,通過 docker0 網橋 以及 Iptables nat 表配置與宿主機通訊。
Macvlan  network 容器具備Mac地址,使其顯示為網路上的物理裝置
Overlay (覆蓋網路): 利用 VXLAN 實現的bridge模式

bridge 模式(預設)

預設的網路模式。bridge模式下容器沒有一個公有 ip ,只有宿主機可以直接訪問,外部主機是不可見的,但容器通過宿主機的 NAT 規則後可以訪問外網。

Bridge 橋接模式的實現步驟主要如下:

  • Docker Daemon 利用 veth pair 技術,在宿主機上建立兩個虛擬網路介面裝置,假設為veth0veth1 。而veth pair 技術的特性可以保證無論哪一個 veth 接收到網路報文,都會將報文傳輸給另一方

  • Docker Daemon 將 veth0 附加到 Docker Daemon 建立的 docker0 網橋上。保證宿主機的網路報文可以發往 veth0

  • Docker Daemon 將 veth1 新增到 Docker Container 所屬的 namespace 下,並被改名為 eth0

如此一來,保證宿主機的網路報文若發往 veth0,則立即會被 eth0 接收,實現宿主機到DockerContainer網路的聯通性;同時,也保證 Docker Container 單獨使用 eth0,實現容器網路環境的隔離性。

注意:veth裝置是成雙成對出現的,一端是容器內部命名為eth0,一端是加入到網橋並命名的veth(通常命名為veth),它們組成了一個數據傳輸通道,一端進一端出,veth裝置連線了兩個網路裝置並實現了資料通訊

bridge 橋接模式的 缺陷

  1. 最明顯的是,該模式下 Docker Container 不具有一個公有 IP,即和宿主機的 eth0 不處於同一個網段。導致的結果是宿主機以外的世界不能直接和容器進行通訊。

  2. 雖然 NAT 模式經過中間處理實現了這一點,但是 NAT 模式仍然存在問題與不便,如:容器均需要在宿主機上競爭埠,容器內部服務的訪問者需要使用服務發現獲知服務的外部埠等。

  3. 另外 NAT 模式由於是在三層網路上的實現手段,故肯定會影響網路的傳輸效率。

host 模式

相當於Vmware中的NAT模式,與宿主機在同一個網路中,但沒有獨立IP地址。

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

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

host網路模式需要在容器建立時指定 --network=host

host 模式是 bridge 橋接模式很好的補充。採用 host 模式的 Docker Container,可以直接使用宿主機的 IP地址與外界進行通訊,若宿主機的 eth0 是一個公有 IP,那麼容器也擁有這個公有IP。同時容器內服務的埠也可以使用宿主機的埠,無需額外進行 NAT 轉換。

Host 網路模式的 缺陷

  • 最明顯的是 Docker Container 網路環境隔離性的弱化。即容器不再擁有隔離、獨立的網路環境。另外,使用 host 模式的 Docker Container 雖然可以讓容器內部的服務和傳統情況無差別、無改造的使用,但是由於網路隔離性的弱化,該容器會與宿主機共享競爭網路棧的使用;

  • 另外,容器內部將不再擁有所有的埠資源,原因是部分埠資源已經被宿主機本身的服務佔用,還有部分埠已經用以 bridge 網路模式容器的埠對映。

container 模式

一種特殊 host 網路模式

Container 網路模式是 Docker 中一種較為特別的網路的模式。在容器建立時使用 --network=container:vm1 指定( vm1指定的是執行的容器名)

這個模式指定新建立的容器和已經存在的一個容器共享一個 Network Namespace,而不是和宿主機共享。

新建立的容器不會建立自己的網絡卡,配置自己的 IP,而是和一個指定的容器共享 IP、埠範圍等。同樣,兩個容器除了網路方面,其他的如檔案系統、程序列表等還是隔離的。兩個容器的程序可以通過 lo 網絡卡裝置通訊。

優勢:處於這個模式下的 Docker 容器會共享一個網路環境,這樣兩個容器之間可以使用 localhost 高效快速通訊。

缺陷:它並沒有改善容器與宿主機以外世界通訊的情況(和橋接模式一樣,不能連線宿主機以外的其他裝置)。

none 模式

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

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

overlay 模式

Overlay 網路,也稱為覆蓋網路。主要用於 Docker 叢集部署

Overlay 網路的實現方式和方案有多種。Docker 自身集成了一種,基於 VXLAN 隧道技術實現。

Overlay 網路主要用於實現跨主機容器之間的通訊。

應用場景:需要管理成百上千個跨主機的容器叢集的網路時

macvlan 模式

macvlan網路模式,最主要的特徵就是他們的通訊會直接基於mac地址進行轉發。

這時宿主機其實充當一個二層交換機。Docker會維護著一個MAC地址表,當宿主機網路收到一個數據包後,直接根據mac地址找到對應的容器,再把資料交給對應的容器。

容器之間可以直接通過IP互通,通過宿主機上內建的虛擬網路裝置(建立macvlan網路時自動建立),但與主機無法直接利用IP互通。

應用場景:由於每個外來的資料包的目的mac地址就是容器的mac地址,這時每個容器對於外面網路來說就相當於一個真實的物理網路裝置。因此當需要讓容器來的網路看起來是一個真實的物理機時,使用macvlan模式

Macvlan是一個新的嘗試,是真正的網路虛擬化技術的轉折點。Linux實現非常輕量級,因為與傳統的Linux Bridge隔離相比,它們只是簡單地與一個Linux乙太網介面或子介面相關聯,以實現網路之間的分離和與物理網路的連線。

Macvlan提供了許多獨特的功能,並有充足的空間進一步創新與各種模式。這些方法的兩個高階優點是繞過Linux網橋的正面效能以及移動部件少的簡單性。刪除傳統上駐留在Docker主機NIC和容器介面之間的網橋留下了一個非常簡單的設定,包括容器介面,直接連線到Docker主機介面。由於在這些情況下沒有埠對映,因此可以輕鬆訪問外部服務。

Macvlan Bridge模式每個容器都有唯一的MAC地址,用於跟蹤Docker主機的MAC到埠對映。Macvlan驅動程式網路連線到父Docker主機介面。示例是物理介面,例如eth0,用於802.1q VLAN標記的子介面eth0.10(.10代表VLAN 10)或甚至繫結的主機介面卡,將兩個乙太網介面捆綁為單個邏輯介面。 指定的閘道器由網路基礎設施提供的主機外部。 每個Macvlan Bridge模式的Docker網路彼此隔離,一次只能有一個網路連線到父節點。

每個主機介面卡有一個理論限制,每個主機介面卡可以連線一個Docker網路。 同一子網內的任何容器都

可以與沒有閘道器的同一網路中的任何其他容器進行通訊macvlan bridge。 相同的docker network命令

適用於vlan驅動程式。 在Macvlan模式下,在兩個網路/子網之間沒有外部程序路由的情況下,單獨網路

上的容器無法互相訪問。這也適用於同一碼頭網路內的多個子網

操作例項

基礎映象

# 拉取映象
docker pull nginx:1.19.3-alpine

# 備份映象
docker save nginx:1.19.3-alpine -o nginx.1.19.3.alpine.tar

# 匯入映象
docker load -i nginx.1.19.3.alpine.tar

bridge 網路

bridge網路表現形式就是 docker0 這個網路介面。容器預設都是通過 docker0 這個介面進行通訊。也可以通過 docker0 去和本機的乙太網介面連線,這樣容器內部才能訪問網際網路。

檢視docker0網路,在預設環境中,一個名為docker0的linux bridge自動被建立好了,其上有一個docker0 內部介面

# 檢視docker0網路
ip a
# 檢視 docker 網路
docker network ls

# 檢視 bridge 網路詳情。主要關注 Containers 節點資訊。
docker network inspect bridge
docker0 詳解
# 執行映象
docker run -itd --name nginx1 nginx:1.19.3-alpine

# 檢視bridge網路詳情。
# 主要關注Containers節點資訊。發現nginx1容器預設使用bridge網路
docker network inspect bridge
# 檢視主機網路,發現多出一塊網絡卡 veth4748026@if108086
ip a

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:08:df:1e:cd brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.1/24 brd 192.168.10.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:8ff:fedf:1ecd/64 scope link 
       valid_lft forever preferred_lft forever
108087: veth4748026@if108086: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 86:9d:51:2b:c7:4c brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::849d:51ff:fe2b:c74c/64 scope link 
       valid_lft forever preferred_lft forever

Docker 建立一個容器的時候,會執行如下操作:

  • 建立一對虛擬介面/網絡卡,也就是 veth pair ,分別放到本地主機和新容器中

  • 本地主機一端橋接到預設的 docker0 或指定網橋上,並具有一個唯一的名字,如 vetha596da4

  • 容器一端放到新容器中,並修改名字作為 eth0 ,這個網絡卡/介面只在容器的名字空間可見

  • 從網橋可用地址段中(也就是與該 bridge 對應的 network )獲取一個空閒地址分配給容器的 eth0 ,並配置預設路由到橋接網絡卡 vetha596da4

完成這些之後,容器就可以使用 eth0 虛擬網絡卡來連線其他容器和其他網路。

如果不指定 --network ,建立的容器預設都會掛到 docker0 上,使用本地主機上 docker0 介面的 IP 作為所有容器的預設閘道器。

# 第一種方式:
docker exec -it nginx1 sh
ip a

# 第二種方式:
docker exec -it nginx1 ip a
# 安裝brctl
yum install -y bridge-utils

[root@VM-72-146-centos ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.024208df1ecd       no              veth4748026
多容器之間通訊
# 啟動兩個容器
docker run -itd --name nginx1 nginx:1.19.3-alpine
docker run -itd --name nginx2 nginx:1.19.3-alpine

# 網路檢視,可知到容器的 IP 地址
docker network inspect bridge

# 容器間 ping
docker exec -it nginx1 ping 192.168.10.3
容器IP地址會發生變化
# 停止容器
docker stop nginx1 nginx2

# 先啟動nginx2,再啟動nginx1
docker start nginx2
docker start nginx1

# 網路檢視
docker network inspect bridge
link容器

docker run命令的link引數

  • --link=[]:新增連結到另一個容器;不推薦使用該引數

使用link的場景:在企業開發環境中,我們有一個mysql的服務的容器mysql_1,還有一個web應用程式 web_1,肯定web_1這臺容器肯定要連線mysql_1這個資料庫。前面網路名稱空間的知識告訴我們,兩個容器需要能通訊,需要知道對方的具體的IP地址。生產環境還比較好,IP地址很少變化,但是在我們內部測試環境,容器部署的IP地址是可能不斷變化的,所以,開發人員不能在程式碼中寫死資料庫的IP地址。這個時候,我們就可以利用容器之間link來解決這個問題。

下面,我們來介紹如何通過容器名稱來進行ping,而不是通過IP地址。

docker run -itd --name nginx1 nginx:1.19.3-alpine
docker run -itd --name nginx2 --link nginx1 nginx:1.19.3-alpine

docker exec -it nginx2 ping nginx1
# 可以 ping 通
  • 上面link命令,是在nginx2容器啟動時link到nginx1容器,因此,在nginx2容器裡面可以ping通nginx1容器名,link的作用相當於添加了DNS解析。這裡提醒下,在nginx1容器裡去ping nginx2容器是不通的,因為link關係是單向的,不可逆。

  • 實際工作中,docker官網已經不推薦我們使用link引數。

  • docker用其他方式替換掉link引數,如下

新建 bridge 網路
docker network create -d bridge lagou-bridge

引數 -d 是指 DRIVER 的型別,後面的 lagou-bridge 是network的自定義名稱,這個和docker0 是類似的。

把容器連線到lagou-bridge這個網路:

啟動一個nginx的容器nginx3,並通過引數network connect來連線lagou-bridge網路。在啟動容器nginx3之前,我們檢視目前還沒有容器連線到了lagou-bridge這個網路上。

ip a    # 多了一個 br-e008eb1ee544
brctl show        # 多了一個 br-e008eb1ee544
docker network ls    # 多了一個 lagou-bridge
docker network inspect lagou-bridge

docker run -itd --name nginx3 --network lagou-bridge nginx:1.19.3-alpine
brctl show
docker network inspect lagou-bridge

把一個執行中容器連線到lagou-bridge網路:

docker network connect lagou-bridge nginx2
docker network inspect lagou-bridge
docker exec -it nginx2 ping nginx3    # 可以ping通
docker exec -it nginx3 ping nginx2    # 可以ping通

host 網路

# 清理所有容器
docker rm $(docker stop $(docker ps -aq))

# 執行容器
docker run -itd --name nginx2 --network host nginx:1.19.3-alpine

# 網路檢視
docker network inspect host    # 多了nginx2,不顯示IP地址
docker exec -it nginx2 ip a    # 和在主機執行 ip a 結果相同

容器使用了host模式,說明容器和外層linux主機共享一套網路介面。

VMware公司的虛擬機器管理軟體,其中網路設定,也有host這個模式,作用也是一樣,虛擬機器裡面使用網路和你自己外層機器是一模一樣的。

這種容器和本機使用共享一套網路介面,缺點還是很明顯的,例如我們知道web伺服器一般埠是80,共享了一套網路介面,那麼你這臺機器上只能啟動一個nginx埠為80的伺服器了。否則,出現埠被佔用的情況。

none 網路

使用none模式,這個容器是不能被其他容器訪問。這種使用場景很少,只有專案安全性很高的功能才能使用到。例如:密碼加密演算法容器

# 清理所有容器
docker rm $(docker stop $(docker ps -aq))

# 刪除網路
docker network rm lagou-bridge
docker network inspect none    # Containers 為空
docker run -itd --name nginx1 --network none nginx:1.19.3-alpine
docker network inspect none    # Containers 多了一個 nginx1,不顯示IP地址
docker exec -it nginx1 ip a    # 只有一個lo介面

網路命令彙總

docker network --help

# 網路常用命令彙總
connect:Connect a container to a network
create:Create a network
disconnect:Disconnect a container from a network
inspect:Display detailed information on one or more networks
ls:List networks
prune:Remove all unused networks
rm:Remove one or more networks

ls

檢視網路

預設情況下,docker安裝完成後,會自動建立bridge、host、none三種網路驅動

docker network ls [OPTIONS]
  • -f, --filter filter :過濾條件(如 'driver=bridge’)

  • --format string :格式化列印結果

  • --no-trunc :不縮略顯示

  • -q, --quiet :只顯示網路物件的ID

docker network ls
docker network ls --no-trunc
docker network ls -f 'driver=host'

create

建立網路

host和none模式網路只能存在一個

docker自帶的overlay 網路建立依賴於docker swarm(叢集負載均衡)服務

docker network create [OPTIONS] NETWORK
  • -d, --driver string: 指定網路的驅動(預設 "bridge")

  • --subnet strings: 指定子網網段(如192.168.0.0/16、172.88.0.0/24)

  • --ip-range strings: 執行容器的IP範圍,格式同subnet引數

  • --gateway strings: 子網的IPv4 or IPv6閘道器,如(192.168.0.1)

172.88.0.0/24 表示前24位是網路字首,後8位是主機號,子碼掩碼是255.255.255.0,包含 IP:172.88.0.0 ~ 172.88.0.255

192.168.0.0/16 包含 IP:192.168.0.0 ~ 192.168.255.255

docker network ls
docker network create -d bridge my-bridge
docker network ls

rm

網路刪除

docker network rm NETWORK [NETWORK...]

inspect

檢視網路詳細資訊

docker network inspect [OPTIONS] NETWORK [NETWORK...]
或
docker inspect [OPTIONS] NETWORK [NETWORK...]
  • -f, --format string :根據format輸出結果

run

使用網路,為啟動的容器指定網路模式

預設情況下,docker建立或啟動容器時,會預設使用名為bridge的網路

docker run/create --network NETWORK

connect、disconnect

網路連線與斷開

docker network connect [OPTIONS] NETWORK CONTAINER
docker network disconnect [OPTIONS] NETWORK CONTAINER
  • -f, --force :強制斷開連線(用於 disconnect)

練習示例

# 建立網路
docker network create -d bridge --subnet=172.172.0.0/24 --gateway 172.172.0.1 lagou-network
# 172.172.0.0/24: 24代表網路字首,子碼掩碼是255.255.255.0

docker network ls
docker run -itd --name nginx3 -p 80:80 --net lagou-network --ip 172.172.0.10 nginx:1.19.3-alpine
# --net mynetwork: 選擇存在的網路
# --ip 172.172.0.10: 給nginx分配固定的IP地址

# 檢視ip是否變化
docker network inspect lagou-network
docker restart nginx3
docker network inspect lagou-network