1. 程式人生 > >分散式進階(十二)Docker固定Container IP

分散式進階(十二)Docker固定Container IP

               

使用pipework工具。

前提:每個Container所做的工作現在還很少,可以不用savecommit

為了便於通訊,自定義一個網橋(192.168.1.180/24),使之IP與宿主主機IP在同一網段內。

bridge模式

bridge模式是Docker預設的網路設定,此模式會為每一個容器分配Network Namespace、設定IP等,並將一個主機上的Docker容器連線到一個虛擬網橋上。下面著重介紹一下此模式。

bridge模式的拓撲

Docker server啟動時,會在主機上建立一個名為docker0的虛擬網橋,此主機上啟動的Docker容器會連線到這個虛擬網橋上。虛擬網橋的工作方式和物理交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網路中。

接下來就要為容器分配IP了,Docker會從RFC1918所定義的私有IP網段中,選擇一個和宿主機不同的IP地址和子網分配給docker0,連線到docker0的容器就從這個子網中選擇一個未佔用的IP使用。

如一般Docker會使用172.17.0.0/16這個網段,並將172.17.42.1/16分配給docker0網橋(在主機上使用ifconfig命令是可以看到docker0的,可以認為它是網橋的管理介面,在宿主機上作為一塊虛擬網絡卡使用)。

單機環境下的網路拓撲如下,主機地址為10.10.101.105/24

 

為了使本地網路中的機器和Docker容器更方便的通訊,我們經常會有將Docker容器配置到和主機同一網段的需求。這個需求其實很容易實現,我們只要將

Docker容器和主機的網絡卡橋接起來,再給Docker容器配上IP就可以了。

#安裝pipework

wget https://github.com/jpetazzo/pipework/archive/master.zip #下載 pipework

unzip master.zip            #解壓

cp pipework-master/pipework  /usr/bin/   #拷貝pipework到 /usr/bin/

chmod +x /usr/bin/pipework    #賦予該命令執行許可權

自定義一個網橋:

brctl addbr br0

ifconfig br0 192.168.1.188 netmask 255.255.255.0

編輯/etc/defautl/docker.io檔案,追加以下內容,指定使用的網橋:

DOCKER_OPTS="-b=br0"

再次啟動docker

service docker.io start 

Contianer未繫結IP之前,其IP地址果然會改變。

注:veth裝置是成雙成對出現的,一端是容器內部命名eth0,一端是加入到網橋並命名的veth17f560a(通常命名為veth*),他們組成了一個數據傳輸通道,一端進一端出,veth裝置連線了兩個網路裝置並實現了資料通訊。

Pipework有個缺點就是給容器指定完固定IP,如果容器重啟,那麼固定IP會消失,還需要重新指定,容器量大時可寫個指令碼來完成。

思路:利用jsvc建立服務,在linux啟動時自動建立指定IP的網橋br0,然後利用pipework工具為容器c1-c4新增新的網絡卡(前提:容器c1-c4均已處以啟動態),將其連線到新建立的br0網橋上,以此建立指定IP的容器。

其中的一個問題是:如何在Ubuntujava程式碼中呼叫shell指令碼。

/** 

     * 執行shell指令碼 

     * @param shell 需要執行的shell指令碼 

     */  

    public static void execShell(String shell){  

        try {  

            Runtime rt = Runtime.getRuntime();  

            rt.exec(shell);  

        } catch (Exception e) {  

            e.printStackTrace();  

        }  

    }  

還有一個方法就是在linux啟動時直接執行shell指令碼:

只需編輯/etc/init.d/rc.local檔案,在最後加上你的指令碼即可。 

比如:我已經編寫了一個指令碼shell.sh,存放在/home/mars704/Desktop/ 下面 

在終端輸入 gedit /etc/init.d/rc.local編輯檔案,在結尾出加入: 

/home/mars704/Desktop/sh.sh 即可開機自動載入指令碼

原理:

首先,linux隨機啟動的服務程式都在/etc/init.d這個資料夾裡,裡面的檔案全部都是指令碼檔案(指令碼程式簡單的說就是把要執行的程式寫到一個檔案裡讓系統能夠按順序執行,類似windows下的autorun.dat檔案),

另外在/etc這個資料夾裡還有諸如名為rc1.d, rc2.d一直到rc6.d的資料夾,這些都是linux不同的runlevel,我們一般進入的X windows多使用者的執行級別是第5級,也就是rc5.d

在這個資料夾下的指令碼檔案就是執行第5級時要隨機啟動的服務程式。需要注意的是,在每個rc (1-6).d資料夾下的檔案其實都是/etc/init.d資料夾下的檔案的一個軟連線(類似windows中的快捷方式)

,也就是說,在 /etc/init.d資料夾下是全部的服務程式,而每個rc(1-6).d只連結它自己啟動需要的相應的服務程式!  

要啟動scim(某一程式),我們首先要知道scim程式在哪裡,用locate命令可以找到,scim/usr/bin/scim這裡,其中usr表示是屬於使用者的,binlinux裡表示可以執行的程式。

這樣,我就可以編寫一個指令碼程式,把它放到/etc/init.d裡,然後在rc5.d裡做一個相應的軟連結就可以了。 

ln -s a b 中的 就是原始檔,b是連結檔名,其作用是當進入b目錄,實際上是連結進入了a目錄

這個指令碼其實很簡單,就兩行: 

#!/bin/bash 

/usr/bin/scim 

第一行是宣告用什麼終端執行這個指令碼,第二行就是要執行的命令。 

還需要注意的一點是,在rc5.d裡,每個連結的名字都是以S或者K開頭的,S開頭的表示是系統啟動是要隨機啟動的,K開頭的是不隨機啟動的。這樣,你就可以知道,如果我要哪個服務隨機啟動,

就把它名字第一個字母K改成S就可以了,當然,把S改成K後,這個服務就不能隨機啟動了。因此,我這個連結 還要起名為SXXX,這樣系統才能讓它隨機啟動。

RH下,rc.local是預設啟動的最後一個指令碼檔案,所以,

如果你想要隨機啟動,還有一種方法就是在rc.local的尾部加入/usr/bin/scim,這樣就可以了。

四個節點配置好了固定IP,節點間的架構圖如下:

 

                                                                                                       圖一

注:Docker啟動時會在主機上自動建立一個docker0虛擬網橋,實際上是一個linux網橋,可以理解為一個軟體交換機。它會在掛在其上的介面之間進行轉發。

同時,Docker會隨機分配一個本地未佔用的私有網段(在RFC1918中定義)中的一個地址給docker0介面。此後啟動的容器內的網口也會自動分配一個同一網段的地址。

 

                                                                                               圖二

注:圖二是自己所寫有關配置自定義網橋,給container新增固定IPshell指令碼

 

                                                                                                    圖三

注:圖三是Linux重啟後所起到的效果。

疑惑:配置指令碼中明明定製了四個啟動容器,結果卻只啟動了三個。經檢查,啟動的三個容器其IP地址均已固定。

 

                                                                                                          圖四 

注:在Ubuntu命令列輸入以上命令時提示如上資訊。錯誤原因及解決措施見部落格"分散式進階(十一) 常見錯誤彙總"

 

                                                                                                           圖五

注:抱著試試看的心態,自己又運行了一個容器,結果奇蹟了,前面的915容器啟動了,而新啟動的容器aef卻沒能啟動,難道啟動的容器總會比自己定義所啟動的容器少一個,這個問題有待於進一步解決。