1. 程式人生 > 實用技巧 >Docker實驗Docker的網路配置

Docker實驗Docker的網路配置

一.基本網路配置–docker網路模式 https://blog.csdn.net/qq_39376481/article/details/95054890

  • docker的映象是令人稱道的地方,但網路功能還是相對薄弱的部分。
  • docker安裝後會自動建立3種網路:bridge、host、none

Docker在啟動時會開啟一個虛擬網橋裝置docker0,預設的地址為172.17.0.1/16,容器啟動後都會被橋接到docker0上,並自動分配到一個ip地址
實驗:
1.檢視docker的網路有哪些(發現有三種, bridge,host,none)

[root@server1 ~]# docker network ls


2.檢視server1上的ip,發現docker0

[root@server1 ~]# ip addr
  • 1

二.基本網路配置–容器的四種網路模式

(一)docker網路中的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 接收,實現宿主機到Docker Container 網路的聯通性;同時,也保證 Docker Container 單獨使用 eth0,實現容器網路環境的隔離性

Bridge橋接模式的缺陷:

  • 1.最明顯的是,該模式下 Docker Container 不具有一個公有 IP,即和宿主機的 eth0 不處於同一個網段。導致的結果是宿主機以外的世界不能直接和容器進行通訊。
  • 2.雖然 NAT 模式經過中間處理實現了這一點,但是 NAT 模式仍然存在問題與不便,如:容器均需要在宿主機上競爭埠,容器內部服務的訪問者需要使用服務發現獲知服務的外部埠等。
  • 3.另外 NAT 模式由於是在三層網路上的實現手段,故肯定會影響網路的傳輸效率。

實驗:
1.建立一個別名為vm1的容器並檢視其ip,發現其ip為 172.17.0.3/16(這是因為當容器橋接docker0後,會自動分配ip地址,然後逐漸遞增)

[root@server1 ~]# docker run -it --name vm1 ubuntu
root@6269c5f20354:/# ip addr


2.裝置vethed03df5連線在了docker0上
#docker安裝時會建立一個名為 docker0 的Linux bridge,新建的容器會自動橋接到這個介面。

[root@server1 ~]# brctl show


3.檢視真實物理機上的ip,發現多了一個虛擬網絡卡,且注意vethed03df5@if4與容器間的是成對的

[root@server1 ~]# ip addr show


4.檢視vm1的情況中的Pid(每個容器都會有一個獨立的Pid)

[root@server1 ~]# docker inspect vm1 | grep Pid


5.檢視關於此Pid容器網路的檔案(每一個獨立的Pid都會在/proc目錄下有一個相應的以Pid為名的目錄,這個目錄裡面的ns目錄有著關於這個Pid容器網路的檔案):

[root@server1 ~]# cd /proc/1872/
[root@server1 1872]# ls
[root@server1 1872]# cd ns/
[root@server1 ns]# ll

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

(二)docker網路中的host網路模式

  • host網路模式需要在容器建立時指定–network=host
  • host 模式是 bridge 橋接模式很好的補充。採用 host 模式的 Docker Container,可以直接使用宿主機的 IP 地址與外界進行通訊,若宿主機的 eth0 是一個公有 IP,那麼容器也擁有這個公有 IP。同時容器內服務的埠也可以使用宿主機的埠,無需額外進行 NAT 轉換。
  • host模式可以讓容器共享宿主機網路棧,這樣的好處是外部主機與容器直接通訊,但是容器的網路缺少隔離性。

    Host 網路模式的缺陷:
  • 最明顯的是 Docker Container 網路環境隔離性的弱化。即容器不再擁有隔離、獨立的網路棧。
  • 另外,使用 host 模式的 Docker Container 雖然可以讓容器內部的服務和傳統情況無差別、無改造的使用,但是由於網路隔離性的弱化,該容器會與宿主機共享競爭網路棧的使用;
  • 另外,容器內部將不再擁有所有的埠資源,原因是部分埠資源已經被宿主機本身的服務佔用,還有部分埠已經用以 bridge 網路模式容器的埠對映。

實驗:
1.重新建立host網路模式的一個容器vm2並檢視ip,會發現此時的ip與宿主機(docker0)中的ip一樣

[root@server1 ~]# docker run -it --name vm2 --network=host ubuntu
root@server1:/# ip addr
root@server1:/# [root@server1 ~]#


2.證明(容器vm2中的ip和宿主機(docker0)中的ip一樣):

[root@server1 ~]# ip a

(三)docker網路中的none網路模式

  • none模式是指禁用網路功能,只有lo介面,在容器建立時使用–network=none指定。
  • 網路環境為 none,即不為 Docker Container 任何的網路環境。一旦 Docker Container 採用了none 網路模式,那麼容器內部就只能使用 loopback 網路裝置,不會再有其他的網路資源。可以說 none 模式為 Docker Container 做了極少的網路設定,但是俗話說得好“少即是多”,在沒有網路配置的情況下,作為 Docker 開發者,才能在這基礎做其他無限多可能的網路定製開發。這也恰巧體現了 Docker 設計理念的開放。

實驗:
建立一個none網路模式的容器vm3並檢視ip,會發現此時只有lo介面

[root@server1 ~]# docker run -it --name vm3 --network=none ubuntu
root@5a2991d10db2:/# ip addr

(四)docker網路中的Container網路模式

  • Container 網路模式是 Docker 中一種較為特別的網路的模式。在容器建立時使用–network=container:vm1指定。(vm1指定的是執行的容器名)
  • 處於這個模式下的 Docker 容器會共享一個網路棧,這樣兩個容器之間可以使用localhost高效快速通訊。
  • 缺陷:它並沒有改善容器與宿主機以外世界通訊的情況(和橋接模式一樣,不能連線宿主機以外的其他裝置)。

實驗:
建立一個container網路模式的容器vm4並檢視ip,由於vm4使用的是vm1的網路,所以其檢視的網路結果和vm1的相同

[root@server1 ~]# docker run -it --name vm4 --network=container:vm1 ubuntu
root@6269c5f20354:/# ip addr

(五)使用link方式使容器間可以相互通訊
docker run --link可以用來連結2個容器,使得源容器(被連結的容器)和接收容器(主動去連結的容器)之間可以互相通訊,並且接收容器可以獲取源容器的一些資料,如源容器的環境變數。
實驗:
1.建立一個容器vm5,並使用link方式連線vm1

#此時的vm1的是容器名,db1是容器的別名
[root@server1 ~]# docker run -it --name vm5 --link vm1:db1 ubuntu
#檢視當前環境的環境變數
root@b814d53a605c:/# env


2.嘗試去連線vm1以及其別名,發現可以成功連線

root@b814d53a605c:/# ping vm1
root@b814d53a605c:/# ping db1


3.檢視其ip,發現是172.17.0.4/16,說明ip是遞增的(之前只有容器vm1時才為其自動分配了ip

root@b814d53a605c:/# ip a 


4.檢視容器中的域名解析,可以發現每一個ip對應的主機名

root@b814d53a605c:/# cat /etc/hosts

三.高階網路配置–網橋

  • 自定義網路模式中,docker提供了三種自定義網路驅動:brdge,overlay,macvlan,bridge驅動類似預設的bridge網路模式,但增加了一些新的功能,overlay和macvlan是用於建立跨主機網路
  • 建議使用自定義的網路來控制哪些容器可以相互通訊,還可以自動DNS解析容器名稱到IP地址

實驗:
(一)bridge自定義網路

  • 自定義網橋中會自己分配ip地址和閘道器地址)
    1.建立自定義網橋並檢視

    #以下命令也可以寫成以下格式:[root@server1 ~]# docker network create --driver bridge my_net1
    [root@server1 ~]# docker network create my_net1
    [root@server1 ~]# docker network ls


2.為了不影響之後的實驗,將所有的容器都進行關閉
#檢視正在執行的容器

[root@server1 ~]# docker ps


#將正在執行的容器強制刪除

[root@server1 ~]# docker rm -f vm1
[root@server1 ~]# docker rm -f vm3
[root@server1 ~]# docker rm -f vm4
[root@server1 ~]# docker rm -f vm5


#檢視沒有執行的容器

[root@server1 ~]# docker ps -a


#將其也依次刪除,使其環境純淨

[root@server1 ~]# docker rm -f vm2
[root@server1 ~]# docker rm -f registry



3.檢視自定義網路的ip地址和閘道器地址

[root@server1 ~]# ip a
[root@server1 ~]# docker network inspect my_net1


4.建立容器vm1並使用自定義網橋,並嘗試與vm1通訊,發現可以通訊

[root@server1 ~]# docker run -it --name vm1 --network=my_net1 ubuntu
#在通訊時
root@ea41dabc161f:/# ping vm1


5.建立容器vm2並使用自定義網橋,並嘗試與vm1通訊,發現可以通訊

[root@server1 ~]# docker run -it --name vm2 --network=my_net1 ubuntu
#在通訊時可以發現vm1自動進行了域名解析
root@010fe2d13a0b:/# ping vm1


總結:
在建立容器時,如果使用的網路模式時自定義的網橋,那麼在此網橋中建立的容器都可以互相進行通訊。

(二)bridge自定義網路–網段

  • 還可以自己定義網段:在建立時指定引數:–subnet 、–gateway
  • 建立兩個容器,並橋接到不同的網橋上(vm1連線的網橋是my_net1),彼此是不通訊的。
  • 使用–ip引數可以指定容器ip地址,但必須是在自定義網橋上,預設的bridge模式不支援,同一網橋上的容器是可以互通的。

實驗:
1.新增一個docker的自定義網段並檢視

[root@server1 ~]# docker network create --subnet=172.21.0.0/24 --gateway=172.21.0.1 my_net2
[root@server1 ~]# docker network ls


2.建立一個容器vm3,並設定其ip(ip必須在自定義橋內)

[root@server1 ~]# docker run -it --name vm3 --network=my_net2 --ip=172.21.0.100  ubuntu
root@0f6d07ab74f1:/# ip a


3.嘗試通訊vm1,發現無法通訊;嘗試通訊vmm3,發現可以通訊。說明如果使用不同網橋間的容器時不可以通訊的

root@0f6d07ab74f1:/# ping vm1
root@0f6d07ab74f1:/# ping vm3
  • 1
  • 2


(三)不同網橋間的容器進行通訊

  • docker在設計上就是要隔離不同的network的
  • dokcer作為一個超級厲害的容器,怎麼能容忍不同網橋間無法進行通訊,它當然有其自己的方法。

前提:
現在使用的容器vm1使用的網橋時my_net1,容器vm3使用的網橋是my_net2,預設是無法進行通訊的

實驗:
1.使用 docker network connect命令為vm1新增一塊my_net2 的網絡卡。

#給容器新增網絡卡後可以連線不同網路
[root@server1 ~]# docker network connect my_net2 vm1


2.進入容器vm1(因為vm1此時正在執行,所以可以使用attach直接進入vm1容器),並檢視ip,發現此時多了一塊網絡卡,且自動分配了ip,然後嘗試與vm3進行通訊,發現可以成功通訊

[root@server1 ~]# docker attach vm1
root@ea41dabc161f:/# 
root@ea41dabc161f:/# ip a
root@ea41dabc161f:/# ping vm3


3.容器之間除了使用ip通訊外,還可以使用容器名稱通訊

#docker 1.10開始,內嵌了一個DNS server,但是dns解析功能必須在自定義網路中使用
root@ea41dabc161f:/# ping -c1 vm1
root@ea41dabc161f:/# ping -c1 vm3

總結:
1.docker的bridge自定義網路(自定義網路中的網橋)間可以隨便新增對方的網絡卡
2.docker的bridge自定義網路與系統自帶的網橋自己間:只能是系統自帶的網橋對應的容器新增給自定義的網橋間,而反過來會報錯
3.docker的系統自帶的網橋之間時可以互相通訊的,因為在同一個網路橋接上

四.容器訪問外網以及外網訪問容器

  • 容器如何訪問外網?其是通過iptables的SNAT實現的

  • 外網如何訪問容器?通過埠對映以及選項指定對映埠

  • 外網訪問容器用到了docker-proxy和iptables DNAT
    宿主機訪問本機容器使用的是iptables DNAT
    外部主機訪問容器或容器之間的訪問是docker-proxy實現

    實驗:
    1.首先檢視原來的防火牆策略

    [root@server1 ~]# iptables -t nat -nL


2.執行映象nginx並設定對映的埠

[root@server1 ~]# docker run -d --name nginx -p 80:80 nginx


3.檢視容器的埠

[root@server1 ~]# docker port nginx
[root@server1 ~]# netstat -antlp | grep 80


4.再次檢視防火牆的策略

[root@server1 ~]# iptables -t nat -nL


5.訪問172.17.0.2,172.17.0.1和localhost,發現都可以成功訪問,說明防火牆策略設定成功並實現了容器和外網之間相互通訊

[root@server1 ~]# curl 172.17.0.2
[root@server1 ~]# curl localhost
[root@server1 ~]# curl 172.17.0.1



五.網路解決方案(跨主機)

  • 跨主機網路解決方案:docker原生的overlay和macvlan,第三方的flannel,weave,calico
  • 眾多網路方案是如何與docker整合在一起的:libnetwork docker容器網路庫;CNM(Container Network Model)這個模型對容器網路進行了抽象
  • CNM分三類元件
    1.Sandbox:容器網路棧,包含容器介面、dns、路由表。(namespace)
    2.Endpoint:作用是將sandbox接入network (veth pair)
    3.Network:包含一組endpoint,同一network的endpoint可以通訊。

macvlan網路方案實現:

  • Linux kernel提供的一種網絡卡虛擬化技術。
  • 無需Linux bridge,直接使用物理介面,效能極好。
  • macvlan本身是linxu kernel的模組,本質上是一種網絡卡虛擬化技術。其功能是允許在同一個物理網絡卡上虛擬出多個網絡卡,通過不同的MAC地址在資料鏈路層進行網路資料的轉發,一塊網絡卡上配置多個 MAC 地址(即多個 interface),每個interface可以配置自己的IP,Docker的macvlan網路實際上就是使用了Linux提供的macvlan驅動。
  • macvlan網路間的隔離和連通
    (1)macvlan網路在二層上是隔離的,所以不同macvlan網路的容器是不能通訊的。
    (2)可以在三層上通過閘道器將macvlan網路連通起來。
    (3)docker本身不做任何限制,像傳統vlan網路那樣管理即可。

實驗:
(一)開啟混雜模式

1.首先在server1中新增一塊網絡卡


2.在server1中檢視,發現多了一個新的網絡卡eth1

[root@server1 ~]# ip addr show



3.在server1中新增網絡卡配置檔案並啟動網絡卡

[root@server1 ~]# cd /etc/sysconfig/network-scripts/
[root@server1 network-scripts]# ls
[root@server1 network-scripts]# cp ifcfg-eth0 ifcfg-eth1
[root@server1 network-scripts]# vim ifcfg-eth1
[root@server1 network-scripts]# cat ifcfg-eth1
[root@server1 network-scripts]# ifup eth1
[root@server1 network-scripts]# ip addr

檔案ifcfg-eth1中的內容如下:

BOOTPROTO=static
ONBOOT=yes
DEVICE=eth1



4.在server2中要新增網絡卡並進行相應的配置,然後啟動



5.開啟server1和srver2的eth1網絡卡的混雜模式並檢視其是否是混雜模式(PROMISC)

[root@server1 ~]# ip link set eth1 promisc on
[root@server1 ~]# ip addr show | grep eth1
[root@server2 ~]# ip link set eth1 promisc on
[root@server2 ~]# ip addr show | grep eth1



注意:
1.因為多個MAC地址的網路資料包都是從同一塊網絡卡上傳輸,所以需要開啟網絡卡的混雜模式
2.如果不開啟混雜模式,會導致macvlan網路無法訪問外界,具體在不使用vlan時,表現為無法ping通路由以及同一網路內他其他主機

6.刪除容器,避免影響接下來的實驗

[root@server1 ~]# docker ps -a
# 檢視所有容器的container id
[root@server1 ~]# docker ps -qa
# 一次性關閉
[root@server1 ~]# docker rm -f `docker ps -qa`
[root@server1 ~]# docker ps -a

(二)在兩臺主機上各建立macvlan網路並使用建立的網路執行容器
server1:
1.在server1上建立macvlan網路:

# -o指父介面
[root@server1 ~]# docker network create -d macvlan --subnet=172.22.0.0/24 --gateway=172.22.0.1 -o parent=eth1 macvlan1
[root@server1 ~]# docker network ls
[root@server1 ~]# brctl show


2.將server1中不需要的自定義網路刪除(我知道很唐突,但是看著實在難受)

[root@server1 ~]# docker network rm my_net1 
[root@server1 ~]# docker network rm my_net2
[root@server1 ~]# docker network ls


3.在server1中建立一個容器並使用macvlan網路,並設定ip為172.25.0.10

[root@server1 ~]# docker run -it --name vm1 --network=macvlan1 --ip=172.22.0.10 ubuntu
root@cb1d34c71d79:/# ip addr

補充:
macvlan模式不依賴網橋,所以如果使用brctl show檢視時會發現並沒有建立新的bridge,但是檢視容器的網路時,會看到虛擬網絡卡對應了一個interface是26,而此時檢視宿主機的網路時會發現26正是虛擬機器的eth1網絡卡

總結:
由上可見,容器的eth0就是宿主機的eth0通過macvlan虛擬出來的介面,容器的介面直接與主機的網絡卡連線,這種方法使得容器無需通過NAT和埠對映就能與外網直接通訊(只要有網絡卡),在網路上看起來與其他獨立主機沒有區別

4.在server1中再次建立一個容器並使用macvlan網路,並設定ip為172.23.0.11

[root@server1 ~]# docker run -it --name vm2 --network=macvlan1 --ip=172.22.0.11 ubuntu
root@b5c839190bbe:/# ip addr
#發現可以ping通vm1
root@b5c839190bbe:/# ping vm1


server2:
5.在server2中建立macvlan網路並檢視

[root@server2 ~]# docker network create -d macvlan --subnet=172.22.0.0/24 --gateway=172.22.0.1 -o parent=eth1 macvlan1
[root@server2 ~]# docker network ls


6.在server2中匯入ubuntu映象

[root@server2 ~]# docker load -i ubuntu.tar 
  • 1


7.在server2中建立一個容器並使用macvlan網路,設定ip為172.25.0.12,嘗試與172.25.0.10和172.25.0.11通訊,發現可以成功通訊

[root@server2 ~]# docker run -it --name vm3 --network=macvlan1 --ip=172.22.0.12 ubuntu
root@7cf65030033d:/# ping 172.22.0.10
root@7cf65030033d:/# ping 172.22.0.11


(三)macvlan會獨佔主機的網絡卡的解決方案

  • macvlan會獨佔主機網絡卡,但可以使用vlan子介面實現多macvlan網路
  • vlan可以將物理二層網路劃分為4094個邏輯網路,彼此隔離,vlan id取值為1~4094
  • 網路模型對比
    (1)Docker overlay 建立主機間 VxLAN 隧道,原始資料包在傳送端被封裝成 VxLAN 資料包,到達目的後在接收端解包。
    (2)Macvlan 網路在二層上通過 VLAN 連線容器,在三層上依賴外部閘道器連線不同macvlan。資料包直接傳送,不需要封裝,屬於 underlay 網路。
    (3)Flannel 的兩種 backend:vxlan 和 host-gw。vxlan 與 Docker overlay 類似,屬於overlay 網路。host-gw 將主機作為閘道器,依賴三層 IP 轉發,不需要vxlan 那樣對包進行封裝,屬於 underlay 網路。
    (4)Weave 是 VxLAN 實現,屬於 overlay 網路。
  • 分散式儲存
    (1)Docker Overlay、Flannel 和 Calico 都需要 etcd 或 consul。
    (2)Macvlan 是簡單的 local 網路,不需要儲存和共享網路資訊。
    (3)Weave 自己負責在主機間交換網路配置資訊,也不需要Distributed Store。
  • IP地址管理
    (1)Docker Overlay 所有主機共享同一個子網,容器啟動時會順序分配 IP。
    (2)Macvlan 需要使用者自己管理子網,不同子網通訊依賴外部閘道器。
    (3)Flannel 為每個主機自動分配獨立的子網,使用者只需要指定一個大的 IP 池。不同子網之間的路由資訊也由 Flannel 自動生成和配置。
    (4)Weave 預設所有容器使用 10.32.0.0/12子網。
    (5)Calico 從定製IP池中為每個主機分配自己的子網。
  • 連通與隔離
    (1)同一 Docker Overlay 網路中的容器可以通訊,但不同網路之間無法通訊,要實現跨網路訪問,只有將容器加入多個網路。與外網通訊可以通過 docker_gwbridge網路。
    (2)Macvlan 網路的連通或隔離完全取決於二層 VLAN 和三層路由。
    (3)不同 Flannel 網路中的容器直接就可以通訊,沒有提供隔離。與外網通訊可以通過 bridge 網路。
    (4)Weave 網路預設配置下所有容器在一個大的子網中,可以自由通訊,如果要實現隔離,需要為容器指定不同的 subnet 或 IP。與外網通訊的方案是將主機加入到weave 網路,並把主機當作閘道器。
    (5)Calico 預設配置下只允許位於同一網路中的容器之間通訊,但通過其強大的Policy 能夠實現幾乎任意場景的訪問控制。
  • 效能
    (1)最樸素的判斷是:Underlay 網路效能優於 Overlay 網路。
    (2)Overlay 網路利用隧道技術,將資料包封裝到 UDP 中進行傳輸。因為涉及資料包的封裝和解封,存在額外的 CPU 和網路開銷。雖然幾乎所有 Overlay 網路方案底層都採用Linux kernel 的 vxlan 模組,這樣可以儘量減少開銷,但這個開銷與Underlay 網路相比還是存在的。所以 Macvlan、Flannel host-gw、Calico 的效能會優於 Docker overlay、Flannel vxlan 和 Weave。
    (3)Overlay 較 Underlay 可以支援更多的二層網段,能更好地利用已有網路,以及有避免物理交換機 MAC 表耗盡等優勢,所以在方案選型的時候需要綜合考慮
  • macvlan的效能非常好
    overlay偏向應用層(更豐富,但是效能上有點損耗)
    ct主要指網路

1.建立vlan子介面並檢視

[root@server1 ~]# docker network create -d macvlan --subnet=172.23.0.0/24 --gateway=172.23.0.1 -o parent=eth1.1 macvlan2
[root@server1 ~]# docker network ls
  • 1
  • 2


2.再次建立一個容器且ip為172.23.0.11,此時嘗試與172.22.0.10通訊,發現無法通訊

[root@server1 ~]# docker run -it --name vm3 --network=macvlan2 --ip=172.23.0.11 ubuntu
root@5d9460b74f05:/# ip addr
root@5d9460b74f05:/# ping 172.22.0.10


3.因為各個vlan子介面建立的容器之間是可以相互通訊的,所以給容器vm3新增vlan子介面並連線vm3

[root@server1 ~]# docker network connect macvlan1 vm3
[root@server1 ~]# docker attach vm3
root@5d9460b74f05:/# 
root@5d9460b74f05:/# ip addr


4.連線vm3後,發現可以成功與172.25.0.10/172.25.0.11/172.22.0.12進行通訊

root@5d9460b74f05:/# ping 172.22.0.10
root@5d9460b74f05:/# ping 172.22.0.11
root@5d9460b74f05:/# ping 172.22.0.12


總結:
172.22.0.10是server1中容器vm1的ip
172.22.0.11是server1中容器vm2的ip
172.22.0.12是server2中容器vm3的ip
172.23.0.11是server1中容器vm3的ip
當macvlan獨佔主機的網絡卡時,一個網絡卡只能建立一個macvlan網路,解決的方案是建立vlan的子介面並在建立新的容器時進行連線,之後給容器新增vlan子介面,大功告成