久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

docker container DNS如何配置

共計(jì) 9822 個(gè)字符,預(yù)計(jì)需要花費(fèi) 25 分鐘才能閱讀完成。

丸趣 TV 小編給大家分享一下 docker container DNS 如何配置,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

Configure container DNSDNS in default bridge networkOptionsDescription-h HOSTNAME or –hostname=HOSTNAME 在該容器啟動(dòng)時(shí),將 HOSTNAME 設(shè)置到容器內(nèi)的 /etc/hosts, /etc/hostname, /bin/bash 提示中。–link=CONTAINER_NAME or ID:ALIAS 在該容器啟動(dòng)時(shí),將 ALIAS 和 CONTAINER_NAME/ID 對(duì)應(yīng)的容器 IP 添加到 /etc/hosts. 如果 CONTAINER_NAME/ID 有多個(gè) IP 地址?–dns=IP_ADDRESS… 在該容器啟動(dòng)時(shí),將 nameserver IP_ADDRESS 添加到容器內(nèi)的 /etc/resolv.conf 中。可以配置多個(gè)。–dns-search=DOMAIN… 在該容器啟動(dòng)時(shí),將 DOMAIN 添加到容器內(nèi) /etc/resolv.conf 的 dns search 列表中。可以配置多個(gè)。–dns-opt=OPTION… 在該容器啟動(dòng)時(shí),將 OPTION 添加到容器內(nèi) /etc/resolv.conf 中的 options 選項(xiàng)中,可以配置多個(gè)。

說明:

如果 docker run 時(shí)不含 –dns=IP_ADDRESS…, –dns-search=DOMAIN…, or –dns-opt=OPTION… 參數(shù),docker daemon 會(huì)將 copy 本主機(jī)的 /etc/resolv.conf,然后對(duì)該 copy 進(jìn)行處理(將那些 /etc/resolv.conf 中 ping 不通的 nameserver 項(xiàng)給拋棄), 處理完成后留下的部分就作為該容器內(nèi)部的 /etc/resolv.conf。因此,如果你想利用宿主機(jī)中的 /etc/resolv.conf 配置的 nameserver 進(jìn)行域名解析,那么你需要宿主機(jī)中該 dns service 配置一個(gè)宿主機(jī)內(nèi)容器能 ping 通的 IP。

如果宿主機(jī)的 /etc/resolv.conf 內(nèi)容發(fā)生改變,docker daemon 有一個(gè)對(duì)應(yīng)的 file change notifier 會(huì) watch 到這一變化,然后根據(jù)容器狀態(tài)采取對(duì)應(yīng)的措施:

如果容器啟動(dòng)時(shí),用了 –dns, –dns-search, or –dns-opt 選項(xiàng),其啟動(dòng)時(shí)已經(jīng)修改了宿主機(jī)的 /etc/resolv.conf 過濾后的內(nèi)容,因此 docker daemon 永遠(yuǎn)不會(huì)更新這種容器的 /etc/resolv.conf。

如果容器狀態(tài)為 stopped,則立刻根據(jù)宿主機(jī)的 /etc/resolv.conf 內(nèi)容更新容器內(nèi)的 /etc/resolv.conf.

如果容器狀態(tài)為 running,則容器內(nèi)的 /etc/resolv.conf 將不會(huì)改變,直到該容器狀態(tài)變?yōu)?stopped.

如果容器啟動(dòng)后修改過容器內(nèi)的 /etc/resolv.conf,則不會(huì)對(duì)該容器進(jìn)行處理,否則可能會(huì)丟失已經(jīng)完成的修改,無論該容器為什么狀態(tài)。

注意: docker daemon 監(jiān)控宿主機(jī) /etc/resolv.conf 的這個(gè) file change notifier 的實(shí)現(xiàn)是依賴 linux 內(nèi)核的 inotify 特性,而 inotfy 特性不兼容 overlay fs,因此使用 overlay fs driver 的 docker deamon 將無法使用該 /etc/resolv.conf 自動(dòng)更新的功能。、

Embedded DNS in user-defined networks

在 docker 1.10 版本中,docker daemon 實(shí)現(xiàn)了一個(gè)叫做 embedded DNS server 的東西,用來當(dāng)你創(chuàng)建的容器滿足以下條件時(shí):

使用自定義網(wǎng)絡(luò);

容器創(chuàng)建時(shí)候通過 –name,–network-alias or –link 提供了一個(gè) name;

docker daemon 就會(huì)利用 embedded DNS server 對(duì)整個(gè)自定義網(wǎng)絡(luò)中所有容器進(jìn)行名字解析(你可以理解為一個(gè)網(wǎng)絡(luò)中的一種服務(wù)發(fā)現(xiàn))。

因此當(dāng)你啟動(dòng)容器時(shí)候滿足以上條件時(shí),該容器的域名解析就不應(yīng)該去考慮容器內(nèi)的 /etc/hosts, /etc/resolv.conf,應(yīng)該保持其不變,甚至為空,將需要解析的域名都配置到對(duì)應(yīng) embedded DNS server 中。具體配置參數(shù)及說明如下:

OptionsDescription–name=CONTAINER-NAME 在該容器啟動(dòng)時(shí),會(huì)將 CONTAINER-NAME 和該容器的 IP 配置到該容器連接到的自定義網(wǎng)絡(luò)中的 embedded DNS server 中,由它提供該自定義網(wǎng)絡(luò)范圍內(nèi)的域名解析 –network-alias=ALIAS 將容器的 name-ip map 配置到容器連接到的其他網(wǎng)絡(luò)的 embedded DNS server 中。PS:一個(gè)容器可能連接到多個(gè)網(wǎng)絡(luò)中。–link=CONTAINER_NAME:ALIAS 在該容器啟動(dòng)時(shí),將 ALIAS 和 CONTAINER_NAME/ID 對(duì)應(yīng)的容器 IP 配置到該容器連接到的自定義網(wǎng)絡(luò)中的 embedded DNS server 中,但僅限于配置了該 link 的容器能解析這條 rule。–dns=[IP_ADDRESS…] 當(dāng) embedded DNS server 無法解析該容器的某個(gè) dns query 時(shí),會(huì)將請求 foward 到這些 –dns 配置的 IP_ADDRESS DNS Server,由它們進(jìn)一步進(jìn)行域名解析。注意,這些 –dns 配置到 nameserver IP_ADDRESS 全部由對(duì)應(yīng)的 embedded DNS server 管理,并不會(huì)更新到容器內(nèi)的 /etc/resolv.conf.–dns-search=DOMAIN… 在該容器啟動(dòng)時(shí),會(huì)將 –dns-search 配置的 DOMAIN 們配置到 the embedded DNS server,并不會(huì)更新到容器內(nèi)的 /etc/resolv.conf。–dns-opt=OPTION… 在該容器啟動(dòng)時(shí),會(huì)將 –dns-opt 配置的 OPTION 們配置到 the embedded DNS server,并不會(huì)更新到容器內(nèi)的 /etc/resolv.conf。

說明:

如果 docker run 時(shí)不含 –dns=IP_ADDRESS…, –dns-search=DOMAIN…, or –dns-opt=OPTION… 參數(shù),docker daemon 會(huì)將 copy 本主機(jī)的 /etc/resolv.conf,然后對(duì)該 copy 進(jìn)行處理(將那些 /etc/resolv.conf 中 ping 不通的 nameserver 項(xiàng)給拋棄), 處理完成后留下的部分就作為該容器內(nèi)部的 /etc/resolv.conf。因此,如果你想利用宿主機(jī)中的 /etc/resolv.conf 配置的 nameserver 進(jìn)行域名解析,那么你需要宿主機(jī)中該 dns service 配置一個(gè)宿主機(jī)內(nèi)容器能 ping 通的 IP。

注意容器內(nèi) /etc/resolv.conf 中配置的 DNS server,只有當(dāng) the embedded DNS server 無法解析某個(gè) name 時(shí),才會(huì)用到。

embedded DNS server 源碼分析

所有 embedded DNS server 相關(guān)的代碼都在 libcontainer 項(xiàng)目中,幾個(gè)最主要的文件分別是 /libnetwork/resolver.go,/libnetwork/resolver_unix.go,sandbox_dns_unix.go。

OK, 先來看看 embedded DNS server 對(duì)象在 docker 中的定義:

libnetwork/resolver.go
// resolver implements the Resolver interface
type resolver struct {
 sb *sandbox
 extDNSList [maxExtDNS]extDNSEntry
 server *dns.Server
 conn *net.UDPConn
 tcpServer *dns.Server
 tcpListen *net.TCPListener
 err error
 count int32
 tStamp time.Time
 queryLock sync.Mutex
// Resolver represents the embedded DNS server in Docker. It operates
// by listening on container s loopback interface for DNS queries.
type Resolver interface {
 // Start starts the name server for the container
 Start() error
 // Stop stops the name server for the container. Stopped resolver
 // can be reused after running the SetupFunc again.
 Stop()
 // SetupFunc() provides the setup function that should be run
 // in the container s network namespace.
 SetupFunc() func()
 // NameServer() returns the IP of the DNS resolver for the
 // containers.
 NameServer() string
 // SetExtServers configures the external nameservers the resolver
 // should use to forward queries
 SetExtServers([]string)
 // ResolverOptions returns resolv.conf options that should be set
 ResolverOptions() []string
}

可見,resolver 就是 embedded DNS server,每個(gè) resolver 都 bind 一個(gè) sandbox,并定義了一個(gè)對(duì)應(yīng)的 dns.Server,還定義了外部 DNS 對(duì)象列表,但 embedded DNS server 無法解析某個(gè) name 時(shí),就會(huì) forward 到那些外部 DNS。

Resolver Interface 定義了 embedded DNS server 必須實(shí)現(xiàn)的接口,這里會(huì)重點(diǎn)關(guān)注 SetupFunc() 和 Start(),見下文分析。

dns.Server 的實(shí)現(xiàn),全部交給 github.com/miekg/dns,限于篇幅,這里我將不會(huì)跟進(jìn)去分析。

從整個(gè) container create 的流程上來看,docker daemon 對(duì) embedded DNS server 的處理是從 endpoint Join a sandbox 開始的:

libnetwork/endpoint.go

func (ep *endpoint) Join(sbox Sandbox, options ...EndpointOption) error {return ep.sbJoin(sb, options...)
func (ep *endpoint) sbJoin(sb *sandbox, options ...EndpointOption) error {if err = sb.populateNetworkResources(ep); err != nil {return err}

sandbox join a sandbox 的流程中,會(huì)調(diào)用 sandbox. populateNetworkResources 做網(wǎng)絡(luò)資源的設(shè)置,這其中就包括了 embedded DNS server 的啟動(dòng)。

libnetwork/sandbox.go
func (sb *sandbox) populateNetworkResources(ep *endpoint) error {if ep.needResolver() {sb.startResolver(false)

libnetwork/sandbox_dns_unix.go func (sb *sandbox) startResolver(restore bool) {sb.resolverOnce.Do(func() { var err error sb.resolver = NewResolver(sb) defer func() { if err != nil { sb.resolver = nil // In the case of live restore container is already running with // right resolv.conf contents created before. Just update the // external DNS servers from the restored sandbox for embedded // server to use. if !restore {err = sb.rebuildDNS() if err != nil {log.Errorf( Updating resolv.conf failed for container %s, %q , sb.ContainerID(), err) return sb.resolver.SetExtServers(sb.extDNS) sb.osSbox.InvokeFunc(sb.resolver.SetupFunc()) if err = sb.resolver.Start(); err != nil {log.Errorf( Resolver Setup/Start failed for container %s, %q , sb.ContainerID(), err) }

sandbox.startResolver 是流程關(guān)鍵:

通過 sanbdox.rebuildDNS 生成了 container 內(nèi)的 /etc/resolv.conf

通過 resolver.SetExtServers(sb.extDNS) 設(shè)置 embedded DNS server 的 forward DNS list

通過 resolver.SetupFunc() 啟動(dòng)兩個(gè)隨機(jī)可用端口作為 embedded DNS server(127.0.0.11)的 TCP 和 UDP Linstener

通過 resolver.Start() 對(duì)容器內(nèi)的 iptable 進(jìn)行設(shè)置 ( 見下),并通過 miekg/dns 啟動(dòng)一個(gè) nameserver 在 53 端口提供服務(wù)。

下面我將逐一介紹上面的各個(gè)步驟。

sanbdox.rebuildDNS

sanbdox.rebuildDNS 負(fù)責(zé)構(gòu)建容器內(nèi)的 resolv.conf,構(gòu)建規(guī)則就是第一節(jié)江參數(shù)配置時(shí)候提到的:

Save the external name servers in resolv.conf in the sandbox

Add only the embedded server s IP to container s resolv.conf

If the embedded server needs any resolv.conf options add it to the current list

libnetwork/sandbox_dns_unix.go
func (sb *sandbox) rebuildDNS() error {currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
 if err != nil {
 return err
 // localhost entries have already been filtered out from the list
 // retain only the v4 servers in sb for forwarding the DNS queries
 sb.extDNS = resolvconf.GetNameservers(currRC.Content, types.IPv4)
 var (dnsList = []string{sb.resolver.NameServer()}
 dnsOptionsList = resolvconf.GetOptions(currRC.Content)
 dnsSearchList = resolvconf.GetSearchDomains(currRC.Content)
 dnsList = append(dnsList, resolvconf.GetNameservers(currRC.Content, types.IPv6)...)
 resOptions := sb.resolver.ResolverOptions()
dnsOpt:
 dnsOptionsList = append(dnsOptionsList, resOptions...)
 _, err = resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
 return err
}

resolver.SetExtServers

設(shè)置 embedded DNS server 的 forward DNS list, 當(dāng) embedded DNS server 不能解析某 name 時(shí),就會(huì)將請求 forward 到 ExtServers。代碼很簡單,不多廢話。

libnetwork/resolver.go
func (r *resolver) SetExtServers(dns []string) {l := len(dns)
 if l   maxExtDNS {
 l = maxExtDNS
 for i := 0; i   l; i++ {r.extDNSList[i].ipStr = dns[i]
}

resolver.SetupFunc

啟動(dòng)兩個(gè)隨機(jī)可用端口作為 embedded DNS server(127.0.0.11)的 TCP 和 UDP Linstener。

libnetwork/resolver.go
func (r *resolver) SetupFunc() func() {return (func() {
 var err error
 // DNS operates primarily on UDP
 addr :=  net.UDPAddr{IP: net.ParseIP(resolverIP),
 r.conn, err = net.ListenUDP(udp , addr)
 // Listen on a TCP as well
 tcpaddr :=  net.TCPAddr{IP: net.ParseIP(resolverIP),
 r.tcpListen, err = net.ListenTCP(tcp , tcpaddr)
}

resolver.Start

resolver.Start 中兩個(gè)重要步驟,分別是:

setupIPTable 設(shè)置容器內(nèi)的 iptables

啟動(dòng) dns nameserver 在 53 端口開始提供域名解析服務(wù)

func (r *resolver) Start() error {if err := r.setupIPTable(); err != nil {return fmt.Errorf( setting up IP table rules failed: %v , err)
 tcpServer :=  dns.Server{Handler: r, Listener: r.tcpListen}
 r.tcpServer = tcpServer
 go func() {tcpServer.ActivateAndServe()
 return nil
}

先來看看怎么設(shè)置容器內(nèi)的 iptables 的:

func (r *resolver) setupIPTable() error {//  獲取 setupFunc() 時(shí)的兩個(gè)本地隨機(jī)監(jiān)聽端口
 laddr := r.conn.LocalAddr().String()
 ltcpaddr := r.tcpListen.Addr().String()
 cmd :=  exec.Cmd{Path: reexec.Self(),
 //  將這兩個(gè)端口傳給 setup-resolver 命令并啟動(dòng)執(zhí)行
 Args: append([]string{ setup-resolver}, r.sb.Key(), laddr, ltcpaddr),
 Stdout: os.Stdout,
 Stderr: os.Stderr,
 if err := cmd.Run(); err != nil {return fmt.Errorf( reexec failed: %v , err)
 return nil
// init 時(shí)就注冊 setup-resolver 對(duì)應(yīng)的 handler
func init() {reexec.Register( setup-resolver , reexecSetupResolver)
// setup-resolver 對(duì)應(yīng)的 handler 定義
func reexecSetupResolver() {
 //  封裝 iptables 數(shù)據(jù)
 _, ipPort, _ := net.SplitHostPort(os.Args[2])
 _, tcpPort, _ := net.SplitHostPort(os.Args[3])
 rules := [][]string{{ -t ,  nat ,  -I , outputChain,  -d , resolverIP,  -p ,  udp ,  --dport , dnsPort,  -j ,  DNAT ,  --to-destination , os.Args[2]},
 {-t ,  nat ,  -I , postroutingchain,  -s , resolverIP,  -p ,  udp ,  --sport , ipPort,  -j ,  SNAT ,  --to-source ,  :  + dnsPort},
 {-t ,  nat ,  -I , outputChain,  -d , resolverIP,  -p ,  tcp ,  --dport , dnsPort,  -j ,  DNAT ,  --to-destination , os.Args[3]},
 {-t ,  nat ,  -I , postroutingchain,  -s , resolverIP,  -p ,  tcp ,  --sport , tcpPort,  -j ,  SNAT ,  --to-source ,  :  + dnsPort},
 // insert outputChain and postroutingchain
}

在 reexecSetupResolver() 中清楚的定義了 iptables 添加 outputChain 和 postroutingchain,將到容器內(nèi)的 dns query 請求重定向到 embedded DNS server(127.0.0.11) 上的 udp/tcp 兩個(gè)隨機(jī)可用端口,embedded DNS server(127.0.0.11) 的返回?cái)?shù)據(jù)則重定向到容器內(nèi)的 53 端口,這樣完成了整個(gè) dns query 請求。

模型圖如下:

貼一張實(shí)例圖:

到這里,關(guān)于 embedded DNS server 的源碼分析就結(jié)束了。當(dāng)然,其中還有很多細(xì)節(jié),就留給讀者自己走讀代碼了。

福利

另外,借用同事 wuke 之前畫的一個(gè)時(shí)序圖,看看 embedded DNS server 的操作在整個(gè)容器 create 流程中的位置,我就不重復(fù)造輪子了。

以上是“docker container DNS 如何配置”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注丸趣 TV 行業(yè)資訊頻道!

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-08-16發(fā)表,共計(jì)9822字。
轉(zhuǎn)載說明:除特殊說明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請注明出處。
評(píng)論(沒有評(píng)論)
主站蜘蛛池模板: 丹江口市| 宁夏| 安宁市| 花莲县| 台江县| 塔城市| 香河县| 庐江县| 林州市| 天门市| 开平市| 茂名市| 田林县| 瓦房店市| 阿拉善左旗| 会昌县| 丰镇市| 油尖旺区| 西峡县| 贵南县| 新郑市| 牙克石市| 安塞县| 安庆市| 丹巴县| 永寿县| 灌南县| 宝丰县| 孝感市| 华容县| 枣庄市| 婺源县| 文山县| 同德县| 江口县| 阿图什市| 洪雅县| 高青县| 桃园县| 钟山县| 利津县|