Docker網絡原理
本文主要講解 Docker 的網絡原理。在此之前,最好對網絡命名空間、Veth 設備對、網橋、路由、netfilter 與 iptables 等Linux基礎網絡知識有所了解,詳見《Docker的Linux網絡基礎》。
一、Docker 的網絡原理
1. Docker 的網絡模式
標準的 Docker 支持 4 種網絡模式,可以在使用 docker run 命令啟動容器的時候通過 --net 參數指定容器的網絡模式:
(1)bridge:--net=bridge,Docker 默認的網絡模式,新建的容器將擁有獨立的網絡命名空間,并連接到 Docker 的網橋 docker0 中。
(2)container:--net=container:NAME_or_ID,新建的容器將與指定容器使用同一個網絡命名空間,共享網絡棧,可以直接通過 lo 環回接口進行通信,但其他資源還是相互隔離的。
(3)host:--net=host,新建的容器將與宿主機使用同一個網絡命名空間,但其他資源還是隔離的。容器進程可以跟主機其它 root 進程一樣打開低范圍的端口,如果進一步的使用 --privileged=true,容器會被允許直接配置主機的網絡堆棧。
(4)none:--net=none,新建的容器將擁有獨立的網絡命名空間,但不進行網絡配置,后續需要手動配置。
2. Docker 啟動后的系統情況
(1)創建了 docker0 網橋并分配了 IP 地址
Docker Daemon 首次啟動時會創建一個虛擬網橋,默認的名稱是 docker0,然后按照 RPC1918 的模型在私有網絡空間中給這個網橋分配一個子網。Docker Daemon 會在幾個備選地址段里給 docker0 選一個地址,通常是以 172 開頭的一個地址。
(2)添加了 iptables 規則
第 6 條:從 docker0 發出的包可以被中轉給 docker0 本身,即連接在 docker0 網橋上的不同容器之間的通信是允許的。
第 3 條:如果接收到發給 docker0 網橋的數據包屬于以前已經建立好的連接,那么允許直接通過,這樣接收到的數據包自然又走回 docker0 并中轉到相應的容器。
第 5 條:從 docker0 發出的包,如果需要轉發到非 docker0 本地 IP 地址的設備,則是允許的,這樣 docker0 設備發出的包就可以根據路由規則中轉到宿主機的網卡設備,從而訪問外面的網絡了。
第 1 條:若本地 docker0 網段發出的數據包不是發往 docker0 的,而是發往主機之外的設備的,則都需要進行動態地址修改 (MASQUERADE) ,將源地址從容器的地址修改為宿主機網卡的 IP 地址,之后就可以發送給外面的網絡了。
(3)Linux 的 ip_forward 功能開啟
二、bridge 網絡模式
在 bridge 模式下,針對由 Docker 建的每一個容器,都會創建一個虛擬以太網設備 —— Veth 設備對,其中一端關聯到網橋 docker0 上,另一端使用 Linux 的網絡命名空間技術映射到容器內的 eth0 設備,然后在網橋的地址段內給 eth0 接口分配一個沒有使用過的 IP 地址。
Docker 的 bridge 模式的網絡模型如下:
docker0 地址段默認情況下在宿主機外部是不可見的,所以在同一臺機器內的容器之間可以相互通信,不同主機上的容器不能相互通信,實際上它們甚至有可能在相同的網絡地址范圍內(不同主機上的 docker0 地址段可能是一樣的)。
為了讓它們跨節點相互通信,就必須在主機的地址上分配端口,然后通過這個端口將網絡流量路由或代理到目標容器上。這樣做顯然意味著一定要在容器之間小心謹慎地協調好端口的分配情況,或者使用動態端口的分配技術,而這二者都是困難且會增加復雜度的事情。這都是 Docker 的網絡模型在跨主機訪問時面臨的問題。
(1)創建一個 Docker 容器,默認使用 bridge 網絡模式,同時指定端口映射
將宿主機 8080 端口映射到容器 4000 端口。
(2)查看容器的網絡模式
使用了 Docker 的默認網絡模式——bridge。
(3)查看網橋連接與容器路由
宿主機上的 Veth 設備對已經建立,連接容器與網橋 docker0。
容器內默認停止的回環設備 lo 被啟動,外面宿主機連接進來的 Veth 設備也被命名成了 eth0, 并且已經配置了地址 172.17.0 2。
容器內路由信息表包含一條到 docker0 的子網路由和一條到 docker0 的默認路由。
(4)查看 iptables 規則
請求宿主機 8080 端口的數據包目的地址將被轉換為容器的服務地址 172.17.0.2:4000。
三、container 網絡模式
使用 container 網絡模式創建的容器將與指定容器使用同一個網絡命名空間,共享網絡棧,可以直接通過 lo 環回接口進行通信,但其他資源還是相互隔離的。
(1)使用 container 網絡模式創建一個容器
(2)查看容器網絡模式
(3)查看容器網絡
可以看到,container 模式的容器與指定容器處于同一網絡命名空間,使用同一個 ip,兩個容器之間可通過 lo 設備通信,使用端口不可重復。
container 網絡模式的容器無法進行端口映射。
四、host 網絡模式
使用 host 網絡模式創建的容器將與宿主機使用同一個網絡命名空間,但其他資源還是隔離的。容器進程可以跟主機其它 root 進程一樣打開低范圍的端口,如果進一步的使用 --privileged=true,容器會被允許直接配置主機的網絡堆棧。
(1)使用 host 網絡模式創建一個容器
(2)查看容器網絡模式
(3)查看容器網絡
容器與宿主機使用同一網絡命名空間,在容器中可以看到 docker0 網橋。
(4)查看宿主機端口占用
容器直接占用宿主機的端口。
五、none 網絡模式
使用 none 網絡模式創建的容器將擁有獨立的網絡命名空間,但不進行網絡配置,后續需要手動配置。
(1)使用 none 網絡模式創建一個容器
(2)查看容器網絡模式
(3)查看容器網絡
只有 lo 設備,暫無 veth 設備,未設置 ip。
六、Docker 網絡的局限性
Docker 一直以來的理念都是“簡單為美”,所以一開始沒有考慮到多機互聯的網絡解決方案。若要基于 Docker 的網絡模型實現跨主機訪問,要么在容器之間小心謹慎地協調好端口的分配情況,要么使用動態端口的分配技術,但這二者都是困難且會增加復雜度的事情。
參考:
《Kubernetes 權威指南第 5 版》

浙公網安備 33010602011771號