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子介面,大功告成