Docker Embedded DNS

因為工作需要,去學習了下Docker的embedded DNS. 這個功能似乎是1.10才加進來的,用來對Docker自帶的overlay網絡提供DNS服務(容器)發現。我學習的是Docker1.10.3版本,對應的libnetwork是release/v0.7。這個版本的Embedded DNS僅支持IPv4,后續的1.11版本還會支持IPv6.

Container Network Model(CNM)

Docker的容器網絡模型如下圖所示:


CNM from github.com/docker/libnetwork

其中

  • 圖中少了一個關鍵組件:NetworkController,他是一個Docker Daemon唯一的,用來管理Docker的所有網絡環境,跟Docker Daemon打交到;
  • 每個Sandbox對應一個Container;
  • 每個Network對應了一個網絡環境(logical connectivity zone),他背后對應一個network driver,一些關鍵過程是調用其api;
  • 每個Endpoint對應一個Sandbox到Network的邏輯鏈接(logical connection).

How it works

什么情況下會使用embedded DNS

方法Daemon.connectToNetwork()是被調用來將一個container連接到某個網絡的。

func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
    if endpointConfig == nil {
        endpointConfig = &networktypes.EndpointSettings{}
    }
    n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings)
    if err != nil {
        return err
    }
    if n == nil {
        return nil
    }

    controller := daemon.netController

    sb := daemon.getNetworkSandbox(container)
    createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb)  // <--------
    if err != nil {
        return err
    }

    endpointName := strings.TrimPrefix(container.Name, "/")
    ep, err := n.CreateEndpoint(endpointName, createOptions...)
    if err != nil {
        return err
    }
  ......

其中BuildCreateEndpointOptions方法返回了創建一個endpoint所需要的option。而此方法中的如下代碼直接指定了是否要使用embedded DNS。

  if !containertypes.NetworkMode(n.Name()).IsUserDefined() {  // using embedded DNS if not user defined network mode
    createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
  }

在package github.com/docker/engine-api/types/container中定義的方法IsUserDefined()會判斷網絡名不為default, bridge, host, none, container時,則認為是用戶定義網絡,進而enable了embedded DNS。

// IsDefault indicates whether container uses the default network stack.
func (n NetworkMode) IsDefault() bool {
    return n == "default"
}

// NetworkName returns the name of the network stack.
func (n NetworkMode) NetworkName() string {
    if n.IsBridge() {
        return "bridge"
    } else if n.IsHost() {
        return "host"
    } else if n.IsContainer() {
        return "container"
    } else if n.IsNone() {
        return "none"
    } else if n.IsDefault() {
        return "default"
    } else if n.IsUserDefined() {
        return n.UserDefined()
    }
    return ""
}

......

// IsUserDefined indicates user-created network
func (n NetworkMode) IsUserDefined() bool {
    return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer()
}

而整個embedded DNS的生命周期,其實可以從兩個角度來看

從Container的角度

Docker Network Embedded DNS
  1. Sandbox每次通過一個Endpoint去Join一個Network都會去發布一把這個ep,sb.populateNetworkResources(ep). 其中回去判斷一把這個Network是否需要resolver,即Embedded DNS. 如果是用戶定義的Network則會enable embedder DNS功能sb.startResolver()。anyway,Sandbox都會將這個ep的信息保存到NetworkController的一個Map解構中networkController.svcDB。他保存了每個Network中的每個ep的name、alias和分配的IP的對應關系。是跨host的name resolution的根據。(libnetwork/sandbox.go

  2. sb.startResolver( )方法中會做embedded DNS的初始化和啟動工作:

  1. sb.rebuildDNS()首先會記錄初始時容器內部的/etc/resolv.conf文件的內容,然后更新/etc/resolv.conf文件,將servername指向127.0.0.11。(127.0.0.0/8網段都是loopback地址

    resolv.conf in container

  2. sb.resolver.SetExtServers(sb.extDNS)將之前讀取的容器初始/etc/resolv.conf文件的nameserver作為embedded DNS的recursive DNS,當embedded DNS不能resolve name的時候就delegate到extDNS。注意這也是為什么--nameserver參數還能工作的原因,雖然容器內的/etc/resolv.conf文件顯示的nameserver還是127.0.0.11

  3. sb.osSbox.InvokeFunc(sb.resolver.SetupFunc())在Container環境中申請tcp和udp兩個隨機端口,姑且命其為tcp_port和udp_port。

  4. sb.resolver.Start()啟動embedded DNS:

    • r.setupIPTable()添加iptables規則將127.0.0.11:53的name resolution query通過DNAT轉發到127.0.0.11:tcp_port127.0.0.11:udp_port(DNS query默認是udp,效率高)。將出去的query通過SNAT轉換回127.0.0.11:53
    • 調用github.com/miekg/dns包的api啟動兩個DNS server分別監聽tcp_port和udp_port。
      iptables and port info
  1. 當DNS query來的時候,resolver會去handle:r.ServeDNS( )。resolver會在方法r.handleIPQuery( )里去resolve name。他會delegate給Sandboxsb.ResolveName( ),然后是去NetworkController里的SvcDB里查找:。沒找到就delegate到ExtDNS。

從Docker Daemon的角度

Docker Network Embedded DNS Process (zoom-in-able)

其中紫色部分為上一節關于embedded DNS的啟動過程。(圖片可通過瀏覽器放大。。。
這部分是整個環境的搭建流程:

  1. 在Daemo被創建的時候NewDaemon( )會初始化網絡環境d.initNetworkController( ),其中會創建NetworkControllerlibnetwork.New( )。此時,會在NetworkController里開啟一個loopc.startWatch( ),一直監聽watchunwatch兩個channel。這兩個channel分別接受被創建的Endpoint實例被刪除的Endpoint實例然后分別調用c.processEndpointCreate( )c.processEndpointDelete( )分別去維護NetworkController里的SvcDB里的ep name/alias和IP的對應關系。

  2. 當調用n.CreateEndpoint( )ep.Join( )時,會往NetworkController的watchchannel里放入當前的ep,從而完成一個DNS record的注冊

  3. 當調用ep.Delete( )時,會往NetworkController的unwatchchannel里放入當前ep,以完成這個DNS record的注銷。

整個embedded DNS的環境就是這個樣子。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容