目錄
當應用程式由多個服務或層次組成,為了使這些應用程式或服務能夠彼此間進行通信,需要知道這些服務部署的位置。這些資訊可以存儲在類似于Etcd或ZooKeeper等分布式的鍵值存儲系統中,也可以通過DNS查找到服務的部署位置。本篇來看看Consul提供的服務發現功能。
當有多個彼此獨立的服務需要協同工作時,就需要一種機制來可以讓一個應用或者元件發現其運作環境以及其它應用或元件的資訊。Consul就可以提供這些功能:
服務配置 - 它可以提供一個鍵值存儲系統來儲存和共享鍵值對,類似于etcd和ZooKeeper。
服務發現 - 它提供一個可以用來注冊服務和提供DNS的API,類似于SkyDNS。
服務監控 - 它提供一個API用于注冊健康檢查,類似于Nagios。
在使用Consul時,可以使用它的全部或部分功能,這些功能之間并沒有依賴。比如如果已經有了監控的基礎設施,沒必要再用Consul取代它們。
一個典型的Consul setup類似于下圖:
在Consul中資料的存儲是由server agent負責的。它們組成一個consensus叢集-這個概念存在于大多數的分布式資料存儲系統中。簡單來說,如果有半數以上的server agents可用,則可以確定資料可以恢複。
所有想要與Consul互動的機器都應該運作一個Consul client agent。這些agents将請求轉發給servers并且進行健康檢查。
這裡我們通過Docker進行Consul的部署,為了簡單起見,Consul server并沒有組成consensus叢集,我們隻是使用了一個節點進行搭建,此節點的機器名為centos7-A,IP位址為192.168.71.167:
1
2
3
4
5
6
7
8
9[[email protected] ~]$ docker pull consul
...
[[email protected] ~]$ docker run -d --net=host \
-e 'CONSUL_ALLOW_PRIVILEGED_PORTS=' \
--name consul_server consul agent -server \
-bind=192.168.71.167 -bootstrap-expect=1 \
-dns-port=53 -client=192.168.71.167 \
-recursor 8.8.8.8 -recursor 8.8.4.4
4f580aa073cfc4108c3bdad23dacd140bd90b4a40467422d895252b09da8ef21
上面的docker run指令有幾點需要注意:
這裡使用的是consul鏡像的最新版本v0.7.0。
使用了--net=host的指令行參數。此參數使得docker容器越過了net namespace的隔離,解決了潛在的UDP通信的問題,而且這種用法不用手動指定所有的端口映射。
使用了-e 'CONSUL_ALLOW_PRIVILEGED_PORTS='環境變量,使用了-dns-port=53指令行選項。這允許容器綁定到标準的DNS端口53上。如果不指定這兩項,consul會預設綁定到本地回環lo位址的8600端口上。
提供了兩個recursor參數。這告訴Consul當請求位址并不能由consul自己解析的話,它到哪裡去查詢其它的DNS伺服器。這裡指定了google提供的兩個dns伺服器的ip。
-bootstrap-expect=1參數意味着Consul叢集使用1個agent便可以開始操作,這沒有提供高可用的特性。此參數通常設定為3(或更多)來確定叢集直到需要數量的伺服器加入叢集後才能開始操作。為了将更多的server agent加入叢集,需要使用-join參數。
bind指定的是叢集間通信使用的ip位址,client指定的是用戶端需要通路的ip位址。
下面在第二台機器上,啟動一個client agent,并且将其加入叢集,此節點的機器名為centos7,IP位址為192.168.71.131:
1
2
3
4
5[[email protected] ~]$ docker run -d --net=host -e 'CONSUL_ALLOW_PRIVILEGED_PORTS=' \
--name consul_client consul agent -dns-port=53 \
-bind=192.168.71.131 -client=172.17.0.1 -join 192.168.71.167 \
-recursor 8.8.8.8 -recursor 8.8.4.4
c2567b364729b23980c8229249a4060d3facd87667387c523cbafdf8d9da4a63
上面需要注意的是我們指定-client的ip位址為主機上docker0(docker網橋)的ip位址,這樣指定是便于本機的其它docker容器使用此位址與consul互動。
下面驗證一下client agent是否已經加連接配接上了server agent。這裡使用curl指令:
1
2
3[[email protected] ~]$ curl -sSL 172.17.0.1:8500/v1/agent/members| python -m json.tool | grep Addr
"Addr": "192.168.71.131",
"Addr": "192.168.71.167",
可見client已經連接配接上了server。下面探索一下怎樣進行服務注冊和服務發現。典型的注冊過程是當容器或服務啟動後,其通過對本地consul client agent的API調用,促使client agent将資訊分發到server agents上。這裡我們使用手動的注冊步驟:
1
2
3
4
5
6
7
8
9
10
11
12[[email protected] ~]$ docker run -d --name files -p 8000:80 ubuntu:14.04 \
python3 -m http.server 80
6eda22ee7bddaf6ebd18aeb5bffe5e26b3e366fae5a8a31d2433c72f04d3574e
[[email protected] ~]$ docker inspect -f '{{.NetworkSettings.IPAddress}}' files
172.17.0.2
[[email protected] ~]$ curl 172.17.0.2
...
[[email protected] ~]$ curl -X PUT --data-binary '{"Name":"files","Port":8000}' \
172.17.0.1:8500/v1/agent/service/register
[[email protected] ~]$ docker logs consul_client | tail -1
2016/09/27 06:21:41 [INFO] agent: Synced service 'files'
上面第1、2行 指令建立了一個HTTP server容器;第4行指令得到該容器的IP;第6行驗證了容器的正常運作;最關鍵的是第9、10行指令,它通過curl通路了Consul的HTTP API來注冊服務,其中服務名稱是必須的,這裡我們指定為files,其它都是可選項;第11行指令通過consul的日志确認了service已經同步,是以我們可以通過DNS接口來得到其資訊。下面我們就通過dig指令來查詢服務的DNS資訊,來驗證剛才的操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23[[email protected] ~]$ dig @192.168.71.167 files.service.consul +short
192.168.71.131
[[email protected] ~]$ dig @172.17.0.1 files.service.consul +short
192.168.71.131
[[email protected] ~]$ dig @172.17.0.1 files.service.consul srv +short
1 1 8000 centos7.node.dc1.consul.
[[email protected] ~]$ docker run -it --dns 172.17.0.1 ubuntu:14.04 bash
[email protected]:/# ping www.baidu.com
PING www.a.shifen.com (220.181.112.244) 56(84) bytes of data.
64 bytes from 220.181.112.244: icmp_seq=1 ttl=127 time=5.05 ms
64 bytes from 220.181.112.244: icmp_seq=2 ttl=127 time=2.40 ms
^C
--- www.a.shifen.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 2.406/3.729/5.052/1.323 ms
[email protected]:/# ping files.service.consul
PING files.service.consul (192.168.71.131) 56(84) bytes of data.
64 bytes from centos7.node.dc1.consul (192.168.71.131): icmp_seq=1 ttl=64 time=0.056 ms
64 bytes from centos7.node.dc1.consul (192.168.71.131): icmp_seq=2 ttl=64 time=0.076 ms
^C
--- files.service.consul ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.056/0.066/0.076/0.010 ms
上面第1行指令從server agent DNS查詢服務的IP位址,這個DNS服務對不在consul叢集中的任何可以通路到此IP的機器都可用;
第3行指令從本機的client agent DNS來查詢服務的IP位址;
第5行指令從client agent DNS查詢SRV的記錄,SRV記錄是通過DNS給出服務資訊的一種方式,上面的指令傳回了服務的端口号以及提供服務的機器的節點名稱;
第7行指令啟動了一個新的容器,并且指定該容器應該使用本地client agent提供的DNS服務,然後進入容器的bash測試是否可以解析位址;
第8行通過ping百度确認可以解析百度的域名;
第16行通過ping前面配置的服務名,确認該服務也可以正常解析。
通過上面的測試,我們發現Resolvable和Consul DNS服務非常相似。它們之間最大的不同就是Consul可以讓你在多個節點之間查找容器,而Resolvable隻是在單台節點上查找。