智匯華雲|Docker容器網絡解析

2020-12-20 華雲數據

企業IT建設開始大規模使用Docker時,你會發現需要了解很多關於網絡的知識。作為目前最火的輕量級容器技術,Docker有很多令人稱道的功能,如Docker的鏡像管理。

然而,Docker的建設也會碰到一系列的挑戰,根據調查報告指出,容器的網絡和安全實現成為容器雲平臺建設最主要的挑戰,當企業開始將重要的企業核心應用遷移至容器平臺,如果缺乏足夠的網絡和安全管控將會給業務上線帶來潛在威脅。

因此,我們有必要深入了解Docker的網絡知識,以滿足更高的網絡需求。本期「智匯華雲」專欄為您帶來「 Docker容器網絡解析」。

本期嘉賓

華雲數據計算網絡開發組網絡技術經理 黃茂峰

Docker 容器網絡的發展歷史

在 Dokcer 發布之初,Docker 是將網絡、管理、安全等集成在一起的,其中網絡模塊可以為容器提供橋接網絡、主機網絡等簡單的網絡功能。

從 1.7 版本開始,Docker正是把網絡和存儲這兩部分的功能都以插件化形式剝離出來,允許用戶通過指令來選擇不同的後端實現。剝離出來的獨立容器網絡項目叫 libnetwork。

在 1.9 版本時,Docker 又引入了一整套 network 子命令和跨主機網絡支持,這允許用戶可以根據他們應用的拓撲結構創建虛擬網絡並將容器接入其所對應的網絡。

什麼是 Docker Libnetwork

為了標準化網絡的驅動開發步驟和支持多種網絡驅動,Docker 將網絡部分代碼被抽離成為了單獨的網絡庫(Libnetwork),Libnetwork 提供了可以用於開發多種網絡驅動的標準化接口和組件。

Docker daemon 通過調用 Libnetwork 對外提供的 API 完成網絡的創建和管理等功能,Libnetwork 內置了5種驅動來提供不同類型的網絡: bridge driver, host driver, null driver, overlay driver, remote driver

bridge driver

此驅動為Docker的默認設置驅動,使用這個驅動的時候,libnetwork將創建出來的Docker容器連接到Docker網橋上。作為最常規的模式,bridge模式已經可以滿足Docker容器最基本的使用需求了。然而其與外界通信使用NAT,增加了通信的複雜性,在複雜場景下使用會有諸多限制。

host driver

使用這種驅動的時候,libnetwork將不為Docker容器創建網絡協議棧,即不會創建獨立的network namespace。Docker容器中的進程處於宿主機的網絡環境中,相當於Docker容器和宿主機共同用一個network namespace,使用宿主機的網卡、IP和埠等信息。

但是,容器其他方面,如文件系統、進程列表等還是和宿主機隔離的。host模式很好地解決了容器與外界通信的地址轉換問題,可以直接使用宿主機的IP進行通信,不存在虛擬化網絡帶來的額外性能負擔。但是host驅動也降低了容器與容器之間、容器與宿主機之間網絡層面的隔離性,引起網絡資源的競爭與衝突。

因此可以認為host驅動適用於對於容器集群規模不大的場景。

null driver

使用這種驅動的時候,Docker容器擁有自己的network namespace,但是並不為Docker容器進行任何網絡配置。也就是說,這個Docker容器除了network namespace自帶的loopback網卡名,沒有其他任何網卡、IP、路由等信息,需要用戶為Docker容器添加網卡、配置IP等。

這種模式如果不進行特定的配置是無法正常使用的,但是優點也非常明顯,它給了用戶最大的自由度來自定義容器的網絡環境。

overlay driver

此驅動採用IETE標準的VXLAN方式,並且是VXLAN中被普遍認為最適合大規模的雲計算虛擬化環境的SDN controller模式。在使用過程中,需要一個額外的配置存儲服務,例如Consul、etcd和zookeeper。還需要在啟動Docker daemon的時候額外添加參數來指定所使用的配置存儲服務地址。

remote Driver

這個驅動實際上並未做真正的網絡服務實現,而是調用了用戶自行實現的網絡驅動插件,使libnetwork實現了驅動的可插件化,更好地滿足了用戶的多種需求。用戶只需要根據libnetwork提供的協議標準,實現其所要求的各個接口並向Docker daemon進行註冊。

什麼是 Docker CNM

Docker Libnetwork 中使用了 CNM 的容器網絡模式概念,CNM定義了構建容器虛擬化網絡的模型,此後容器網絡模式也被抽象變成了統一接口的驅動。

CNM 中主要有 sandbox、endpoint 和 network 3 種核心組件CNM 中核心組件的使用模型如下圖:

沙盒 (sandbox):一個沙盒包含了一個容器網絡棧的信息。沙盒可以對容器的接口(interface)、路由和 DNS 設置等進行管理,沙盒的實現可以是Linux netns、FreeBSD Jail 或者類似的機制,一個沙盒可以有多個端點和多個網絡。

端點 (endpoint):一個端點可以加入一個沙盒和一個網絡。端點的實現可以是 veth pair、ovs 內部埠或者相似的設備,一個端點只屬於一個網絡並且只屬於一個沙盒。

網絡 (network):一個網絡是一組可以直接互相聯通的端點。網絡的實現可以是 Linux bridge、VLAN等,一個網絡可以包含多個端點。

Libnetwork Remote driver

kuryr-libnetwork 是 Libnetwork 框架下的一種 remote driver 實現,現在已經成為Docker 官網推薦的一個 remote driver,kuryr-libnetwork 需要做的就是實現 Libnetwork remote driver 需要實現的接口.

常見的 remote driver 要實現的接口如下,格式:HTTP POST + JSON Body

/Plugin.Activate no payload -- Handshake/NetworkDriver.GetCapabilities -- Set capability

/NetworkDriver.DiscoverNew -- DiscoverNew Notification

/NetworkDriver.DiscoverDelete -- DiscoverDelete Notification

/NetworkDriver.AllocateNetwork -- Allocate network specific resources, only called in docker swarm mode

/NetworkDriver.FreeNetwork -- Free network specific resources, only called in docker swarm mode

/NetworkDriver.CreateNetwork -- Create network

/NetworkDriver.DeleteNetwork -- Delete network

/NetworkDriver.CreateEndpoint -- Create endpoint

/NetworkDriver.EndpointOperInfo -- Endpoint operational info

/NetworkDriver.DeleteEndpoint -- Delete endpoint

/NetworkDriver.Join -- Join an endpoint to a sandbox

/NetworkDriver.Leave -- Remove an endpoint from a sandbox

IPAM Driver

在 Libnetwork 中,CNM 模塊通過 IPAM Driver 管理 IP 地址的分配,Libnetwork 內含有一個默認的IPAM驅動,同時它也允許動態地增加第三方IPAM驅動。

在用戶創建網絡時可以指定 Libnetwork 使用的 IPAM 驅動, Kuryr 項目通過實現了 IPAM 的驅動接口,成為了Docker 的第三方 libnetwork IPAM driver。

常見的 IPAM driver 要實現的接口如下,格式:HTTP POST + JSON Body

/IpamDriver.GetCapabilities -- provides the IPAM driver capabilities. it's called during the registration of the IPAM driver.

/IpamDriver.GetDefaultAddressSpaces -- returns the default local and global address space names for this IPAM. it's called after the registration of the IPAM driver

/IpamDriver.RequestPool -- registering an address pool with the IPAM driver. multiple identical calls must return the same result.

/IpamDriver.RequestAddress -- allocates the IP address

/IpamDriver.ReleaseAddress -- deallocates the IP address

/IpamDriver.ReleasePool -- releasing a previously registered address pool

Docker 網絡的生命周期

Docker 用戶可以通過與 CNM 的 Object 以及 API 的交互來管理對應容器的網絡,下面是一個典型的容器網絡生命周期:

1、Driver要向NetworkController註冊。內置的Driver在Libnetwork內註冊,遠程的Driver則通過Plugin mechanism註冊。每一個Driver處理特定的networkType。

2、libnetwork.New():NetworkController通過libnetwork.New()創建,用於Network的創建以及通過一些特定的Options配置Driver。

3、controller.NewNetwork():Network通過給這個API提供name和networkType來創建,networkType參數用來選擇特定的Driver並且將創建的Network和該Driver相關聯。從此以後,對於Network的任何操作都由Driver處理。controller.NewNetwork() 還有一個可選的options參數,用於提供特定Driver的options和Labels。

4、network.CreateEndpoint():可以用於在給定的Network中創建一個新的Endpoint。同時該API還有一個可選的options參數供Driver使用。這個"options"既可以攜帶已知的labels,也可以攜帶和特定Driver相關的labels。之後調用相應的Driver的driver.CreateEndpoint,它可以為在一個Endpoint在Network中被創建時,為它們保留IP位址。Driver會通過driverapi中定義的InterfaceInfo進行這些地址的賦值。IP位址將和endpoint暴露的埠用來完善Endpoint作為Service的定義。事實上,Service endpoint不是其他什麼東西,僅僅只是一個網絡地址以及該應用的容器監聽的埠號。

5、endpoint.Join():用於將Endpoint與一個容器相連接。Join操作會先創建一個Sandbox如果對應的容器中還沒有的話。Driver可以使用Sandbox Key來識別連接到同一個容器的多個Endpoint。這個API同樣接受可選的options參數供Driver使用。

- 雖然這並不是Libnetwork直接的設計要求,但是我們鼓勵像Docker這樣的用戶在執行容器的Start()操作時,即在容器可以操作之前,調用endpoint.Join()。

- 另一個關於endpoint.join()這個API經常被提到的問題是,為什麼我們需要一個API創建Endpoint和另一個API來join endpoint。事實上Endpoint代表的是一個Service,它可能有,也可能並沒有容器支持。當一個Endpoint被創建的時候,會預留它所需的資源,因此任何容器都能連接該Endpoint並且獲得一個一致的網絡行為。

6、endpoint.Leave():會在容器停止的時候被調用。Driver可以清除它在調用Join()時獲取的狀態。Libnetwork會在最後一個Endpoint離開的時候刪除Sandbox。但是只要該Endpoint依舊存在,Libnetwork會依然保有IP位址並且在有新的容器加入的時候進行重用。這保證了容器的資源在停止並重啟的過程中能夠重用。

7、endpoint.Delete():用於從一個Network中刪除Endpoint。這將導致Endpoint的刪除以及清空緩存的sandbox.Info。

8、network.Delete():用於刪除Network。如果還有Endpoint連接到該網絡,Libnetwork是不允許對它進行刪除的。

Docker 網絡命名空間

docker 常常使用 linux netns 實現網絡資源隔離,但使用 ip netns 命令卻無法查看,這是因為 docker 默認把創建的網絡命名空間連結文件隱藏起來了,導致 ip netns 命令無法讀取,可以通過下面的方法復現 docker 的 ip netns 命名空間。

# 創建一個帶有橋接網絡的 docker 容器

$ docker run -it -d --rm --name mytest --network bridge cirros /bin/sh

c093857c756028b4d4f37b16262d017239236bde22a3545f8769fd17366f183a

$ docker ps | grep mytest

c093857c7560 cirros "/bin/sh" 6 seconds ago Up 2 seconds mytest

# 可以通過 inspect 命令查看該容器的 ip 地址和進程號

$ docker inspect mytest |egrep '"IPAddress"|"Pid"'

"Pid": 14908,

"IPAddress": "172.17.0.2",

# 通過進程號參考容器進程

$ ps -fp 14908

UID PID PPID C STIME CMD

root 14889 1676 0 11:42 containerd-shim -namespace moby \

-workdir

/var/lib/containerd/io.containerd.runtime.v1.linux/moby/c093857c756028b4d4f37b16262d017239236bde22a3545f8769fd17366f183a \

-address /run/containerd/containerd.sock \

-containerd-binary /usr/bin/containerd \

-runtime-root /var/run/docker/runtime-runc

# 通過 nsenter 進入容器網絡空間

$ nsenter --target 14908 --net ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN

link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

inet 127.0.0.1/8 scope host lo

valid_lft forever preferred_lft forever

54: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP

link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0

inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0

valid_lft forever preferred_lft forever

# 通過軟連接容器命名空間實現在 ip netns 下顯示

$ ls /proc/14908/ns/net

lrwxrwxrwx 1 root root 0 Jul 25 11:42 /proc/14908/ns/net -> net:[4026532445]

$ ln -s /proc/14908/ns/net /var/run/netns/mytest

# 最後檢查一下

$ ip netns

mytest (id: 1)

$ ip netns exec mytest ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN

link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

inet 127.0.0.1/8 scope host lo

valid_lft forever preferred_lft forever

54: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP

link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0

inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0

valid_lft forever preferred_lft forever

Docker 主機名與DNS

一個鏡像可以啟動多個容器,但是它們的主機名和網絡信息並不一樣,也即是說主機名和網絡信息並非是被寫入鏡像中的。實際上容器中/etc/目錄下有三個文件是容器啟動後被虛擬文件覆蓋的,分別是/etc/hostname、/etc/hosts、/etc/resolv.conf。對這三個文件的修改不會被docker commit保存,也就是不會保存在鏡像中,重啟容器也會導致修改失效。

$ docker exec -it mytest mount | grep etc

/dev/mapper/centos-root on /etc/resolv.conf type xfs (rw,relatime,attr2,inode64,noquota)

/dev/mapper/centos-root on /etc/hostname type xfs (rw,relatime,attr2,inode64,noquota)

/dev/mapper/centos-root on /etc/hosts type xfs (rw,relatime,attr2,inode64,noquota)

- 這樣能解決主機名的問題,同時也能讓DNS及時更新(改變resolv.conf)。

- 由於這些文件的維護方法隨著Docker版本演進而不斷變化,因此儘量不修改這些文件,而是通過Docker提供的參數進行相關設置。

參考資料

https://github.com/docker/libnetwork/blob/master/docs/design.md

http://dockone.io/article/1306

https://www.oreilly.com/library/view/learning-docker-networking/9781785280955/

https://feisky.gitbooks.io/sdn/container/cnm/

https://www.nuagenetworks.net/blog/container-networking-standards/

想要了解更多華雲數據的相關信息,歡迎撥打諮詢熱線:400-808-4000

相關焦點

  • 雲計算核心技術Docker教程:Docker容器使用
    要退出客戶端程序,直接輸入 exit:查看所有的容器命令如下:$ docker ps -a使用 docker start 啟動一個已停止的容器:$ docker start <容器 ID>$ docker run -itd --name ubuntu-test ubuntu /bin/bash要停止一個容器運行使用如下命令:$ docker stop <容器 ID>要重啟一個容器運行使用如下命令:
  • 雲計算核心技術Docker教程:Docker容器中開啟SSH服務
    在docker容器中我們不止需要通過宿主機進行登錄對容器進行修改,我還有事還希望直接通過SSH登錄到docker容器中進行一些修改,這樣的話我們需要將容器中ssh埠映射到宿主機,然後再容器中安裝openssh服務。
  • 不用Docker也能構建容器的4種方法
    Docker 之外的選擇有一些項目試圖讓「docker」回到它原本的組件身份,也就是我們最初都喜愛的用戶體驗:Docker——Docker現在使用containerd來運行容器,並且支持使用buildkit進行高效的緩存式構建。
  • 利用雲伺服器搭建解鎖免費聽網易雲灰歌曲的代理-docker版
    註:本教程僅作為學習參考使用,請支持正版一、最近在GitHub上發現一個有趣的項目:UnblockNeteaseMusic,可以解鎖網易雲灰色歌曲,利用docker超簡單搭建。二、搭建步驟1、 yum install docker -y ###安裝docker2 、 systemctl start docker ####啟動docker3、systemctl enable docker #########默認開啟
  • Docker 入門教程
    (2)提供彈性的雲服務。因為 Docker 容器可以隨開隨關,很適合動態擴容和縮容。(3)組建微服務架構。通過多個容器,一臺機器可以跑多個服務,因此在本機就可以模擬出微服務架構。這個例子中,Node 進程運行在 Docker 容器的虛擬環境裡面,進程接觸到的文件系統和網絡接口都是虛擬的,與本機的文件系統和網絡接口是隔離的,因此需要定義容器與物理機的埠映射(map)。現在,在容器的命令行,按下 Ctrl + c 停止 Node 進程,然後按下 Ctrl + d (或者輸入 exit)退出容器。
  • 誰是容器中的「戰鬥機」?Docker與Chef、LXC等容器對比
    Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然後發布到任何流行的 Linux 機器上,也可以實現虛擬化。Docker可以自動化打包和部署任何應用、創建一個輕量級私有PaaS雲、搭建開發測試環境、部署可擴展的Web應用等。
  • docker下高並發和高可用之docker swarm使用
    ,操作步驟參考Linux下安裝和使用Docker安裝完,使用命令sudo systemctl start docker啟動docker,再通過命令docker version查看docker版本信息利用docker swarm 命令來指定其中一臺虛擬機為docker的Manager管理機docker swarm init --advertise-addr
  • Kubernetes決定棄用Docker,到底會影響到誰?
    近幾年,Kubernetes 已經成為自有機房、雲上廣泛使用的容器編排方案,最廣泛的使用方式是 Kubernetes+Docker。從 DevOps 人員的角度,一面用 kubctl 命令、k8s API 來操作集群,一面在單機用 Docker 命令來管理鏡像、運行鏡像。
  • Docker命令行入門大全:這18條,你不得不知
    version — 列出關於Docker客戶端以及伺服器版本的信息 docker login — 登錄到Docker鏡像倉庫 docker system prune — 刪除所有未使用的容器、網絡以及無名稱的鏡像(虛懸鏡像)容器命令詳解啟動容器術語「創建」,「開始」和「運行」在日常生活中都具有相似的語義
  • 30分鐘帶你了解Web工程師必知的Docker知識
    容器與鏡像的關係類似於面向對象編程中的對象與類。,子容器與宿主機共用一套作業系統。IPC:每個容器依舊使用linux內核中進程交互的方法,實現進程間通信Mount:每個容器的文件系統是獨立的Net:每個容器的網絡是隔離User:每個容器的用戶和組ID是隔離,每個容器都擁有root用戶
  • 【GITC】搜狐雲臺陳偉:基於docker的自動化運維管理架構與實踐
    Docker的橫空出世,讓人們看到了build、ship、run一體化的希望,而DomeOS正是希望基於docker 的容器化技術,解決用戶從代碼自動編譯打包,到線上運行維護的全套需求。搜狐雲臺除了可靠地雲存儲服務、頂尖的圖片處理技術,還有人臉檢測、黃反圖識別、廣告圖識別等方面的研究。  陳偉表示「我們是幫人解決問題的,存儲和圖片的需求通過搜狐雲臺得到了很好的解決,但是我們也發現了流程中很多新的問題。」  ● 傳統運維模式的問題  陳偉在會場和大家分享了搜狐雲臺團隊在多年雲存儲開發運維過程中遇到的問題。
  • 【希雲cSphere】1.0版本發布,正式商用
    cSphere產品經過十多個版本的迭代,以及在大量企業真實環境中的使用反饋,歷經一年時間,在今天我們正式宣布:希雲cSphere正式進入企業商用階段。希雲cSphere1.0的發布,同樣標誌著國內Docker技術的發展已經進入到了一個新的裡程碑!!標誌著企業落地docker可以真正放心!!
  • 雲計算核心技術Docker教程:Docker 守護進程dockerd默認的CGROUP父級
    該--cgroup-parent選項允許您設置用於容器的默認cgroup父級。如果未設置此選項,則默認為/docker對於fs cgroup驅動程序和system.slicesystemd cgroup驅動程序。
  • 雲計算核心技術Docker教程: events/inspect命令詳解
    在docker客戶端命令行中我們可以使用events命令從伺服器獲取實時事件便於查找調試問題,使用inspect命令獲取容器或鏡像的元數據。示例docker events : 從伺服器獲取實時事件語法docker events [OPTIONS]OPTIONS說明:-f :根據條件過濾事件;--since :從指定的時間戳後顯示所有事件;--until :流水時間顯示到指定的時間為止;例如,顯示docker 2020
  • 雲計算核心技術Docker教程:events/inspect命令詳解
    在docker客戶端命令行中我們可以使用events命令從伺服器獲取實時事件便於查找調試問題,使用inspect命令獲取容器或鏡像的元數據。示例docker events : 從伺服器獲取實時事件語法docker events [OPTIONS]OPTIONS說明:-f :根據條件過濾事件;
  • 推薦給IT新手的11個Docker免費上手項目
    Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的鏡像中,然後發布到任何流行的 Linux或Windows 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何接口。
  • Docker實踐者不能錯過Container大會的九大理由
    如今,Docker擁有 超過500個代碼貢獻者,20個核心Maintainer,超過8000個創建在GitHub上的Docker相關項目,30多個國家90多個城市舉辦的超過250個Docker技術聚會,以及大於 50萬次的boot2docker下載 。擁有特殊優勢的Docker已經引爆熱潮。
  • Kubernetes Init Container (初始化容器)
    然後,Init容器對資源請求和容器處理不同,並且它們必須在Pod就緒之前完成運行理解Init容器Pod 能夠具有多個容器,應用運行在容器裡面,但是它也可能有一個或多個領先於應用容器啟動的Init容器Init容器與普通容器非常像,除了以下兩點:
  • docker-9:使用ambari-2.7.3部署大數據集群—兩節點demo
    >(6).資源耗費附錄1.ambari相關的yum repo附錄2.參考文章(1).docker部署ambarigit clone https://github.com/hepyu/docker-ambari-2.7.git
  • 「智」匯山城,雲、數、智的「三江匯流」
    雲、數、智的「三江交匯」智慧城市的建設,是一個複雜的系統,任何單一的技術,都不能實現一個完整的智慧。浪潮認為:「雲計算是新生產力,大數據是新生產資料,AI是新生產工具,區塊鏈是新生產關係,雲計算、大數據、AI、區塊鏈等信息技術的快速發展與融合應用,將推動新型網際網路發展。」