共計 5893 個字符,預計需要花費 15 分鐘才能閱讀完成。
這篇文章給大家分享的是有關 OpenStack 容器網絡項目 Kuryr 的示例分析的內容。丸趣 TV 小編覺得挺實用的,因此分享給大家做個參考,一起跟隨丸趣 TV 小編過來看看吧。
容器近幾年非常流行,有很多項目都考慮將容器與 SDN 結合。Kuryr 就是其中一個項目。Kuryr 項目在 OpenStack big tent 下,目的是將容器網絡與 openstack Neutron 對接。Kuryr 給人的第一印象是:這又是一個在 Neutron 框架下的項目,能夠通過 Neutron 統一的北向接口來控制容器網絡的 SDN 項目。但是實際上,Kuryr 是將 Neutron 作為南向接口,來與容器網絡對接。Kuryr 的北向是容器網絡接口,南向是 OpenStack Neutron。
Kuryr 背景介紹
正式介紹前,先說下 Kuryr 這個單詞。Kuryr 是一個捷克語單詞 kuryr,對應英語里面是 courier,對應的中文意思就是信使,送信的人。從這個名字能看出來,Kuryr 不生產信息,只是網絡世界的搬運工。這個從項目的圖標也可以看出來。另外,由于都是拉丁語系,所以可以不負責任的說,Kuryr 的發音應該是與 courier 類似。
Kuryr 最開始創立的時候,其目的是為了提供 Docker 與 Neutron 的連接。將 Neutron 的網絡服務帶給 docker。隨著容器的發展,容器網絡的發展也出現了分歧。主要分為兩派,一個是 Docker 原生的 CNM(Container Network Model),另一個是兼容性更好的 CNI(Container Network Interface)。Kuryr 相應的也出現了兩個分支,一個是 kuryr-libnetwork(CNM),另一個是 kuryr-kubernetes(CNI)。
Kuryr 在 Libnetwork 中如何工作
kuryr-libnetwork 是運行在 Libnetwork 框架下的一個 plugin。要理解 kuryr-libnetwork 如何工作,首先要看一下 Libnetwork。Libnetwork 是從 Docker Engine 和 libcontainer 中將網絡邏輯模塊化之后獨立出來的的項目,并且替代了原有的 Docker Engine 網絡子系統。Libnetwork 定義了一個靈活的模型,使用 local 或者 remote driver 來向 container 提供網絡服務。kuryr-libnetwork 就是 Libnetwork 的一個 remote driver 實現,現在已經成為 Docker 官網推薦的一個 remote driver。
Libnetwork 的 driver 可以看是 Docker 的一個 plugin,與 Docker 的其他 plugin 共用一套 plugin 管理框架。也就是說,Libnetwork 的 remote driver 與 Docker Engine 中的其他 plugin 用一樣的方式激活,并使用同樣的協議。有關 Libnetwork remote driver 需要實現的接口在 Libnetwork 的 Git 上都有詳細的描述。
kuryr-libnetwork 需要做的就是實現這些接口。可以從 kuryr-libnetwork 的代碼中看出來。Libnetwork 通過調用 remote driver 的 Plugin.Activate 接口,來查看 remote driver 實現了什么內容。從 kuryr-libnetwork 的代碼中能看到,它實現了兩個功能:NetworkDriver, IPAMDriver.
@app.route(/Plugin.Activate , methods=[ POST])
def plugin_activate():
Returns the list of the implemented drivers.
This function returns the list of the implemented drivers defaults to
``[NetworkDriver, IpamDriver]`` in the handshake of the remote driver,
which happens right before the first request against Kuryr.
See the following link for more details about the spec:
docker/libnetwork # noqa
app.logger.debug(Received /Plugin.Activate)
return flask.jsonify(const.SCHEMA[ PLUGIN_ACTIVATE])
Kuryr 是怎么作為 remote driver 注冊到 Libnetwork 中呢?這個問題應該這樣看,Libnetwork 是怎樣發現 Kuryr 的?這要依賴于 Docker 的 plugin discovery 機制。當用戶或者容器需要使用 Docker 的 plugin 的時候,他 / 它只需要指定 plugin 的名字。Docker 會在相應的目錄中查找與 plugin 名字相同的文件,文件中定義了如何連接該 plugin。
如果用 devstack 安裝 kuryr-libnetwork,devstack 的腳本會在 /usr/lib/docker/plugins/kuryr 創建一個文件夾,里面的文件內容也很簡單,默認是:http://127.0.0.1:23750。也就是說,kuryr-libnetwork 實際上就起了一個 http server,這個 http server 提供了 Libnetwork 所需的所有接口。Docker 找到有這樣的文件之后,就通過文件的內容與 Kuryr 進行通信。
所以 Libnetwork 與 Kuryr 的交互是這樣:
Libnetwork:有人要用一個叫 Kuryr 的 plugin,讓我找找看。哦,Kuryr 你好,你有什么功能?
Kuryr:我有 NetworkDriver, IpamDriver 這些功能,怎樣,開心嗎?
Kuryr 如何與 Neutron 連接
上面講的 Kuryr 如何與 Docker Libnetwork 連接。再來看看 Kuryr 如何與 OpenStack Neutron 對接。由于同是 OpenStack 陣營下的項目,并且都是 Python 語言開發的,所以,沒有懸念,Kuryr 用 neutronclient 與 Neutron 連接。所以總體來看,Kuryr 的工作方式如下:
由于 Kuryr 跟下面實際的 L2 實現中間還隔了個 Neutron,所以 Kuryr 不是太依賴 L2 的實現。上圖是 Gal Sagie 列出的 Kuryr 支持的一些 Neutron L2 實現方式。在此之外,我試過 kuryr-libnetwork 和 Dragonflow 的集成,并沒有太多需要注意的地方,有機會可以專門說說這個。
接下來看看 Kuryr-libnetwork 如何在 Neutron 和 Docker 中間做一個 courier。由于北向是 Libnetwork,南向是 Neutron,所以可以想象,kuryr-libnetwork 做的事情就是接收 Libnetwork 的資源模型,轉化成 Neutron 的資源模型。先來看看 Libnetwork 的資源模型,也就前面說過的容器網絡兩派之一 CNM。CNM 由三個數據模型組成:
Network Sandbox:定義了容器的網絡配置
Endpoint:容器用來接入網絡的網卡,存在于 Sandbox 中,一個 Sandbox 中可以有多個 Endpoint
Network:相當于一個 Switch,Endpoint 接入在 Network 上。不同的 Network 之間是隔離的。
對應 Neutron,Endpoint 是 Neutron 中的 Port,而 Network 是 Neutron 中的 Subnet。為什么 Network 對應的不是 Neutron 中的 Network?可能是因為 Libnetwork 與 Neutron 的網絡定義的區別的,不過至少在一個 Neutron Network 中只有一個 Subnet 時,兩者在名字上是能對應的。
除此之外,Kuryr 還依賴 OpenStack Neutron 中的另一個特性:subnetpool。Subnetpool 是 Neutron 里面的一個純邏輯概念,它能夠保證所有在 subnetpool 中的 subnet,IP 地址段不重合。Kuryr 借助這個特性保證了由其提供的 Docker Network,IP 地址是唯一的。
Kuryr 將 Libnetwork 發來的請求轉換成相應的 Neutron 的請求,發送給 Neutron。
Kuryr 連通容器網絡與虛機網絡
但是實際網絡的連通,沒法通過 Neutron 的 API 來告訴 Neutron 怎么做,Neutron 不知道容器的網絡怎么接出來,也不提供這樣的 API。這部分需要 Kuryr 自己來完成,這也就是 Kuryr 的 Magic 所在(否則跟一個代理有什么區別)。最后來看看這部分吧。
當 Docker 創建一個容器,并且需要創建 Endpoint 的時候,請求發送到了作為 Libnetwork 的 remote driver—Kuryr 上。Kuryr 接到這個請求首先會創建 Neutron port:
neutron_port, subnets = _create_or_update_port(
neutron_network_id, endpoint_id, interface_cidrv4,
interface_cidrv6, interface_mac)
之后會根據配置文件的內容,調用相應的 driver,目前支持的 driver 有 veth,用來連接主機容器網絡,另一個是 nested,用來連接虛機內的容器網絡。當然,這里的主機,虛機都是相對 OpenStack 來說的,嚴格的說,OpenStack 的主機也可以是一個虛機,例如我的開發環境。接下來以 veth driver 為例來說明。先看代碼吧:
try:
with ip.create(ifname=host_ifname, kind=KIND,
reuse=True, peer=container_ifname) as host_veth:
if not utils.is_up(host_veth):
host_veth.up()
with ip.interfaces[container_ifname] as container_veth:
utils._configure_container_iface(
container_veth, subnets,
fixed_ips=port.get(utils.FIXED_IP_KEY),
mtu=mtu, hwaddr=port[utils.MAC_ADDRESS_KEY].lower())
except pyroute2.CreateException:
raise exceptions.VethCreationFailure( Virtual device creation failed.)
except pyroute2.CommitException:
raise exceptions.VethCreationFailure( Could not configure the container virtual device networking.)
try:
stdout, stderr = _configure_host_iface(
host_ifname, endpoint_id, port_id,
port[network_id], port.get(project_id) or port[tenant_id],
port[utils.MAC_ADDRESS_KEY],
kind=port.get(constants.VIF_TYPE_KEY),
details=port.get(constants.VIF_DETAILS_KEY))
except Exception:
with excutils.save_and_reraise_exception():
utils.remove_device(host_ifname)
與 Docker 網絡中的 bridge 模式類似,Driver 首先創建了一個 veth pair 對,兩個網卡,其中一塊是 container interface,用來接在容器的 network namespace,并通過調用_configure_container_iface 來進行配置;另一塊是 host interface,通過調用_configure_host_iface 接入到 Neutron 的 L2 拓撲中。
Host interface 的處理方式是專門為 OpenStack Neutron 定制的。這里需要注意的是,不同的 SDN 底層的 L2 拓撲是不一樣的,OpenVswitch,LinuxBridge,Midonet 等等。Kuryr 是怎么來支持不同的 L2 底層?首先,注意看 OpenStack Neutron 的 port 信息,可以發現有這么一個屬性:binding:vif_type。這個屬性表示了該 port 是處于什么樣的 L2 底層。Kuryr 針對不同的 L2 實現了一些 shell 腳本,用來將指定的網卡接入到 Neutron 的 L2 拓撲中,這些腳本位于 /usr/libexec/kuryr 目錄下,它們與 binding:vif_type 的值一一對應。所以,Kuryr 要做的就是讀取 Neutron port 信息,找到對應的 shell 腳本,通過調用 shell,將 veth pair 中的 host interface 接入到 OpenStack Neutron 的 L2 拓撲中。接入之后,容器實際上與虛機處于一個 L2 網絡,自然能與虛機通訊。另一方面,也可以使用 Neutron 提供的各種服務,Security group,QoS 等等。
目前 kuryr 支持的 L2 網絡類型有:bridge iovisor midonet ovs tap unbound
等等,這跟 OpenStack Nova 使用 Neutron 的方式是不是很像。Nova 調用 Neutron API 創建 port,Nova 實際的創建網卡,綁定到虛機中。
感謝各位的閱讀!關于“OpenStack 容器網絡項目 Kuryr 的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!