天天看點

利用OpenVSwitch建構多主機Docker網絡利用OpenVSwitch建構多主機Docker網絡

【編者的話】當你在一台主機上成功運作docker容器後,信心滿滿地打算将其擴充到多台主機時,卻發現前面的嘗試隻相當于寫了個hello world的入門程式,多主機的網絡設定成了下一道門檻。在你嘗試各種方案時不妨先看看本文,或許就會豁然開朗,發現原來也不複雜。嗯,是的,本文用到了 openvswitch。

在多台主機上運作卻是另外一回事……

可選方案:

分别在每台主機上運作docker,在公網或内網網卡上暴露端口以便容器間互相通訊。這可能比較麻煩,而且會引發安全問題。

在主機間的網狀網絡中建立一個共享網橋,讓docker服務在那運作容器。這聽起來有點複雜,不過……本文中我們将看到這可以非常容易地完成!

利用OpenVSwitch建構多主機Docker網絡利用OpenVSwitch建構多主機Docker網絡

multi-host-docker1.jpg

<a target="_blank"></a>

基本上,我們将執行以下步驟:

在每台伺服器上安裝docker;

在每台伺服器上安裝openvswitch;

自定義網絡設定用以自動在主機間建立網橋/隧道(在每台伺服器的<code>/etc/network/interfaces</code>裡);

自定義每個docker服務配置,隻處理<code>docker0</code> ip範圍的一小部分,防止新容器的ip位址發生重疊。

就是這樣。重新開機服務或重新開機伺服器後,你将獲得一個具備連接配接備援(link redundancy)的全網狀網絡,docker服務可以在專用的ip範圍(不會重疊)上運作容器,并且不需要在公網或内網網卡上暴露所有端口就能互聯。很棒,對麼?

簡單列一下我們用到的技術:

我們将假定伺服器運作的是ubuntu server 14.04.02 lts x64,對于其它系統,你可能需要修改下面提供的各項配置。

糟糕的是,預設倉庫裡openvswitch安裝包不可用(或過期了),我們需要自己建構<code>.deb</code>檔案(一次),然後分發給不同主機。為了保持生産機的整潔,可另外找台小主機來安裝開發包,并建構安裝包。

執行下列指令來建構安裝包(新版請按要求修改):

現在你有了新的<code>.deb</code>安裝包,接下來将其推送并安裝到所有主機上。

<code># 複制包到各主機并ssh登入</code>

<code>scp -r *deb user@remote_host:~/.</code>

<code>ssh user@remote_host</code>

<code></code>

<code># 安裝一些依賴(後面需要)并安裝包</code>

<code>sudo apt-get install -y bridge-utils</code>

<code>sudo dpkg -i openvswitch-common_2.3.1-1_amd64.deb \</code>

<code>         openvswitch-switch_2.3.1-1_amd64.deb</code>

你可以使用openvswitch提供的不同指令行工具來建構網狀網絡(比如<code>ovs-vsctl</code>),不過ubuntu提供了一個輔助工具讓你可以通過<code>/etc/network/interfaces</code>檔案定義網絡。

假定三台主機:1.1.1.1、2.2.2.2和3.3.3.3,可以通過上述ip互相ping通,它們是在公網或内網上并不重要。host1的<code>/etc/network/interfaces</code>大概如下。

在其它主機上要對這個配置上做些調整:<code>remote_ip</code>的ip位址要互相配對。

利用OpenVSwitch建構多主機Docker網絡利用OpenVSwitch建構多主機Docker網絡

multi-host-docker2.jpg

幾點說明:

生成樹協定(spanning tree protocol):如果應用該配置,将在3台伺服器中建立一個網絡回路,這可不行。給<code>br0</code>網橋添加<code>stp_enable=true</code>将確定一些<code>gre</code>隧道被切斷。同時確定網狀網絡的備援,允許網絡在其中一台主機下線時恢複。

以太網:14位元組——我們說的是網橋間的第2層;

ipv4:20位元組——容器/主機間通訊;

gre:4位元組——因為,嗯,這是個gre隧道;

也就是實體網卡mtu減去38位元組,結果是1462(基于正常的1500 mtu網卡)。

在auto定義中使用“<code>=</code>”:對于具有固定ip的伺服器這不是必需的,但有些雲服務商(這裡就不說是誰了……digital ocean(譯者:軟廣再次亂入))使用了一個依靠<code>ifquery --list --allow auto</code>的init服務(<code>/etc/init/cloud-init-container.conf</code>)。不加上“<code>=</code>”号将包含openvswitch網卡,并延遲整個啟動過程直到init腳本失敗并逾時。

docker0網橋:每台伺服器都需要自己的ip位址(比如<code>172.17.42.1</code>、<code>172.17.42.2</code>)。由于<code>docker0</code>網橋處在<code>br0</code>網橋之上,它們将(也應該!)可以互相連接配接。想象一下,要解決ip沖突會有多亂……這也是為什麼我們要在啟動時定義它,而不依賴docker服務來為我們建立這個網橋。

3台以上主機:你可以遵循相同的邏輯,并且:

添加額外的隧道(iface grex)來連接配接新主機。

在<code>br0</code>網橋定義中更新<code>ovs_ports</code>以包含<code>interfaces</code>檔案中定義的所有<code>gre</code>隧道。

聰明點……不要将每台伺服器跟其他主機一一連結……stp收斂(convergence)将需要更長的時間,并且無法提供任何除了多重額外鍊路備援之外的有用價值。

如果現在重新開機伺服器,你将擁有一個具備備援的網狀網絡,你可以運作以下指令來測試:

從host1上<code>ping 172.17.42.2</code>或其他ip;

在主機上運作<code>iperf</code>,通過<code>ifconfig</code>檢視使用中的連結;

在ping第三台主機時停止“中間”那台,檢視網絡收斂(通過stp)時ping中斷了幾秒鐘。

利用OpenVSwitch建構多主機Docker網絡利用OpenVSwitch建構多主機Docker網絡

multi-host-docker3.jpg

我們現在有了一個完善的網絡,每個docker服務都可以将它們的容器挂接到<code>docker0</code>網橋上。讓docker自動完成這步不是很棒麼?答案在于docker有能力配置設定一個最小的ip位址池!

對于該示例,我們假定:

每台主機(<code>1.1.1.1</code>、<code>2.2.2.2</code>、<code>3.3.3.3</code>)挂接到前面建立的<code>docker0</code>網橋上,其各自的ip位址是<code>172.17.42.1</code>、<code>172.17.42.2</code>、<code>172.17.42.3</code>;

給<code>docker0</code>網卡指定了一個/16的ip範圍;

給每台主機指定了一小塊<code>docker0</code>的ip範圍,以/18 <code>fixed-cidr</code>的形式儲存在它們的docker服務配置中。分别是<code>172.17.64.0/18</code>、<code>172.17.128.0/18</code>、<code>172.17.192.0/18</code>。

如果你的主機多于3台,你需要細分一個每個範圍,或根據組織需要對整個網絡拓撲結構進行重新考慮。

利用OpenVSwitch建構多主機Docker網絡利用OpenVSwitch建構多主機Docker網絡

multi-host-docker4.jpg

host1的配置檔案(<code>/etc/default/docker</code>)是這樣的:

<code>bridge=docker0</code>

<code>cidr=172.17.64.0/18</code>

<code>wait_ip() {</code>

<code>address=$(ip add show $bridge | grep 'inet ' | awk '{print $2}')</code>

<code>[ -z "$address" ] &amp;&amp; sleep $1 || :</code>

<code>}</code>

<code>wait_ip 5</code>

<code>wait_ip 15</code>

<code>docker_opts="</code>

<code>-h unix:///var/run/docker.sock</code>

<code>-h tcp://0.0.0.0:2375</code>

<code>--fixed-cidr=$cidr</code>

<code>--bridge $bridge</code>

<code>--mtu 1462</code>

<code>"</code>

你可以根據需要修改<code>docker_opts</code>配置,添加鏡像、不安全的registry、dns等等。

說明:

wait_ip:由于<code>docker0</code>網橋最後被建立,擷取ip位址可能需要花點時間。使用<code>wait_ip</code>“功能”,你可以在傳回docker init腳本前安全地等待幾秒鐘。該配置檔案是被真正的init腳本(<code>/etc/init/docker.conf</code>)所引用。

mtu:與前面相同原因,隻是一個預防措施,用于確定每個網卡被建立時會被指定正确的mtu。

-h tcp://……:如果你不想通過<code>0.0.0.0</code>将其“公開”(或綁定到伺服器“真實”網卡之一),你也可以将它安全地綁定到……該主機的<code>docker0</code> ip位址(比如<code>172.17.42.2</code>)!這樣,你可以從任何一台主機通路到私有網狀網絡裡的任何一個docker服務。

重新開機一下(至少保證啟動時所有東西都會自動上線)。

你可以試試以下指令看看一切是否正常。

這不是一份指導如何在多主機上設定docker的權威指南,歡迎大家提出批評(譯者注:譯稿也一樣,請大家多多指正)。很多想法是在整體安裝時産生的,本文盡可能詳細地說明了為何選擇這個或那個選項。

如果将分級網橋、vlan等包括進來,事情将更複雜,不過那超出了本文的範圍。;)

顯然,更完整的網絡是有需求的,而且看起來這個已經在開發中。

如果你讀完本文了,恭喜!

原文釋出時間:2015-03-30

本文來自雲栖合作夥伴“linux中國”

繼續閱讀