037.Kubernetes集群網絡-Docker網絡實現


一 Docker網絡

1.1 Docker網絡類型

標准的Docker支持以下4類網絡模式:
  • host模式:使用--net=host指定。
  • container模式:使用--net=container:NAME_or_ID指定。
  • none模式:使用--net=none指定。
  • bridge模式:使用--net=bridge指定,為默認設置。
在Kubernetes管理模式下通常只會使用bridge模式,如下介紹在bridge模式下Docker是如何支持網絡的。
提示:更多Docker網絡參考《006.Docker網絡管理》。

二 bridge模式

2.1 bridge模型

在bridge模式下,Docker Daemon第1次啟動時會創建一個虛擬的網橋,默認的名稱是docker0,然后在私有網絡空間中給這個網橋分配一個子網。針對由Docker創建的每一個容器,都會創建一個虛擬的以太網設備(Veth設備對),其中一端關聯到網橋上,另一端使用Linux的網絡命名空間技術,映射到容器內的eth0設備,然后從網橋的地址段內給eth0接口分配一個IP地址。
如圖所示為Docker的默認橋接網絡模型:
clipboard
其中ip1是網橋的IP地址,Docker Daemon會在幾個備選地址段里給它選一個地址,通常是以172開頭的一個地址。這個地址和主機的IP地址是不重疊的。ip2是Docker在啟動容器時,在這個地址段選擇的一個沒有使用的IP地址分配給容器。相應的MAC地址也根據這個IP地址,在02:42:ac:11:00:00和02:42:ac:11:ff:ff的范圍內生成,這樣做可以確保不會有ARP沖突。
啟動后,Docker還將Veth對的名稱映射到eth0網絡接口。ip3就是主機的網卡地址。
通常,ip1、ip2和ip3是不同的IP段,所以在默認不做任何特殊配置的情況下,在外部是看不到ip1和ip2的。
這樣做的結果就是,在同一台機器內的容器之間可以相互通信,不同主機上的容器不能相互通信,實際上它們甚至有可能在相同的網絡地址范圍內(不同主機上的docker0的地址段可能是一樣的)。
為了讓它們跨節點互相通信,就必須在主機的地址上分配端口,然后通過這個端口路由或代理到容器上。這種做法顯然意味着一定要在容器之間小心謹慎地協調好端口的分配,或者使用動態端口的分配技術。
在不同應用之間協調好端口分配是十分困難的事情,特別是集群水平擴展時。而動態的端口分配也會帶來高度復雜性,例如:每個應用程序都只能將端口看作一個符號(因為是動態分配的,所以無法提前設置)。
而且API Server要在分配完后,將動態端口插入配置的合適位置,服務也必須能互相找到對方等。這些都是Docker的網絡模型在跨主機訪問時面臨的問題。
注意:更多跨主機的Docker通信方案,可參考《006.Docker網絡管理》。

2.2 網絡規則

  • 查看Docker啟動后的系統情況
Docker網絡中,在bridge模式下Docker Daemon啟動時創建docker0網橋,並在網橋使用的網段為容器分配IP。
Docker Daemon剛啟動並且還沒有啟動任何容器時,網絡協議棧的配置情況如下:
[root@docker ~]# ip addr
[root@docker ~]# iptables-save
clipboard
clipboard
Docker創建了docker0網橋,並添加了iptables規則。docker0網橋和iptables規則都處於root命名空間中。對這些規則的說明如下:
  1. 在NAT表中有3條記錄,前兩條匹配生效后,都會繼續執行DOCKER鏈,而此時DOCKER鏈為空,所以前兩條只是做了一個框架,並沒有實際效果。
  2. NAT表第3條的含義是,若本地發出的數據包不是發往docker0的,即是發往主機之外的設備的,則都需要進行動態地址修改(MASQUERADE),將源地址從容器的地址(172段)修改為宿主機網卡的IP地址,之后就可以發送給外面的網絡了。
  3. 在FILTER表中,第1條也是一個框架,因為后繼的DOCKER鏈是空的。
  4. 在FILTER表中,第3條是說,docker0發出的包,如果需要Forward到非docker0的本地IP地址的設備,則是允許的。這樣,docker0設備的包就可以根據路由規則中轉到宿主機的網卡設備,從而訪問外面的網絡。
  5. FILTER表中,第4條是說,docker0的包還可以被中轉給docker0本身,即連接在docker0網橋上的不同容器之間的通信也是允許的。
  6. FILTER表中,第2條是說,如果接收到的數據包屬於以前已經建立好的連接,那么允許直接通過。這樣接收到的數據包自然又走回docker0,並中轉到相應的容器。
除了如上Netfilter的設置,Linux的ip_forward功能也被Docker Daemon打開了:
[root@docker ~]# cat /proc/sys/net/ipv4/ip_forward
1
[root@docker ~]# ip route
default via 172.24.9.1 dev eth0
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.24.9.0/24 dev eth0 proto kernel scope link src 172.24.9.138
  • 查看容器啟動后的情況(容器無端口映射)
首先啟動一個容器,如Registry容器(不使用任何端口鏡像參數),看一下網絡堆棧部分相關的變化:
[root@docker ~]# docker run --name register -d registry #運行容器
[root@docker ~]# ip addr
[root@docker ~]# iptables-save
[root@docker ~]# ip route
clipboard
  1. 宿主機器上的Netfilter和路由表都沒有變化,說明在不進行端口映射時,Docker的默認網絡是沒有特殊處理的。相關的NAT和FILTER這兩個Netfilter鏈還是空的。
  2. 宿主機上的Veth對已經建立,並連接到容器內。
[root@docker ~]# docker exec -ti register /bin/sh #容器內查看相關信息
/ # ip route
/ # ip addr
clipboard
如上默認停止的回環設備lo已經被啟動,外面宿主機連接進來的Veth設備也被命名成了eth0,並且已經配置了地址172.17.0.2。路由信息表包含一條到docker0的子網路由和一條到docker0的默認路由。
查看容器啟動后的情況(容器有端口映射)
[root@docker ~]# docker run --name register -d -p 1180:5000 registry #帶端口映射啟動registry
[root@docker ~]# iptables-save
clipboard
如上新增的規則可以看出,Docker服務在NAT和FILTER兩個表內添加的兩個DOCKER子鏈都是給端口映射用的。在本例中我們需要把外面宿主機的1180端口映射到容器的5000端口。
通過分析可知,無論是宿主機接收到的還是宿主機本地協議棧發出的,目標地址是本地IP地址的包都會經過NAT表中的DOCKER子鏈。Docker為每一個端口映射都在這個鏈上增加了到實際容器目標地址和目標端口的轉換。經過這個DNAT的規則修改后的IP包,會重新經過路由模塊的判斷進行轉發。由於目標地址和端口已經是容器的地址和端口,所以數據自然就被轉發到docker0上,從而被轉發到對應的容器內部。
當然在Forward時,也需要在DOCKER子鏈中添加一條規則,如果目標端口和地址是指定容器的數據,則允許通過。在Docker按照端口映射的方式啟動容器時,主要的不同就是上述iptables部分。而容器內部的路由和網絡設備,都和不做端口映射時一樣,沒有任何變化。

三 Docker網絡局限

3.1 Docker的網絡局限

從Docker對Linux網絡協議棧的示例可知,Docker一開始沒有考慮到多主機互聯的網絡解決方案。Docker一直以來的理念都是“簡單為美”。通常,虛擬化技術中最為復雜的部分就是虛擬化網絡技術。
多主機互聯相關方案有Libnetwork,Libnetwork針對目前Docker的網絡實現,Docker使用的Libnetwork組件只是將Docker平台中的網絡子系統模塊化為一個獨立庫的簡單嘗試,離成熟和完善還有一段距離。
提示:更多Docker網絡實現方案參考:《007.基於Docker的Etcd分布式部署》、《008.Docker Flannel+Etcd分布式網絡部署》。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM