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 技術,在宿主機上建立兩個虛擬網路介面裝置,假設為veth0 和 veth1 。而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 橋接模式的 缺陷 :
-
最明顯的是,該模式下 Docker Container 不具有一個公有 IP,即和宿主機的 eth0 不處於同一個網段。導致的結果是宿主機以外的世界不能直接和容器進行通訊。
-
雖然 NAT 模式經過中間處理實現了這一點,但是 NAT 模式仍然存在問題與不便,如:容器均需要在宿主機上競爭埠,容器內部服務的訪問者需要使用服務發現獲知服務的外部埠等。
-
另外 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