微服務還不瞭解就落後了。。Consul 入門教程(全)

一、什麼是服務發現

微服務的框架體系中,服務發現是不能不提的一個模塊。我相信瞭解或者熟悉微服務的童鞋應該都知道它的重要性。這裡我只是簡單的提一下,畢竟這不是我們的重點。我們看下面的一幅圖片:

微服務還不瞭解就落後了。。Consul 入門教程(全)

圖中,客戶端的一個接口,需要調用服務A-N。客戶端必須要知道所有服務的網絡位置的,以往的做法是配置是配置文件中,或者有些配置在數據庫中。這裡就帶出幾個問題:

  • 需要配置N個服務的網絡位置,加大配置的複雜性
  • 服務的網絡位置變化,都需要改變每個調用者的配置
  • 集群的情況下,難以做負載(反向代理的方式除外)

總結起來一句話:服務多了,配置很麻煩,問題多多

既然有這些問題,那麼服務發現就是解決這些問題的。話說,怎麼解決呢?我們再看一張圖

微服務還不瞭解就落後了。。Consul 入門教程(全)

與之前一張不同的是,加了個服務發現模塊。圖比較簡單,這邊文字描述下。服務A-N把當前自己的網絡位置註冊到服務發現模塊(這裡註冊的意思就是告訴),服務發現就以K-V的方式記錄下,K一般是服務名,V就是IP:PORT。服務發現模塊定時的輪詢查看這些服務能不能訪問的了(這就是健康檢查)。客戶端在調用服務A-N的時候,就跑去服務發現模塊問下它們的網絡位置,然後再調用它們的服務。這樣的方式是不是就可以解決上面的問題了呢?客戶端完全不需要記錄這些服務網絡位置,客戶端和服務端完全解耦!

這個過程大體是這樣,當然服務發現模塊沒這麼簡單。裡面包含的東西還很多。這樣表述只是方便理解。

圖中的服務發現模塊基本上就是微服務架構中服務發現的作用了。

二、consul 簡介

做服務發現的框架常用的有

zookeeper

eureka

etcd

consul

這裡就不比較哪個好哪個差了,需要的童鞋自己谷歌百度。

那麼consul是啥?consul就是提供服務發現的工具。然後下面是簡單的介紹:

consul是分佈式的、高可用、橫向擴展的。consul提供的一些關鍵特性:

service discovery:consul通過DNS或者HTTP接口使服務註冊和服務發現變的很容易,一些外部服務,例如saas提供的也可以一樣註冊。

health checking:健康檢測使consul可以快速的告警在集群中的操作。和服務發現的集成,可以防止服務轉發到故障的服務上面。

key/value storage:一個用來存儲動態配置的系統。提供簡單的HTTP接口,可以在任何地方操作。

multi-datacenter:無需複雜的配置,即可支持任意數量的區域。

我們這裡會介紹服務發現,健康檢查,還有一些基本KV存儲。多數據中心有機會另一篇文章再說。

總結:只要知道它是解決我上一部分提出的問題就行,其它的東西慢慢理解

三、consul的幾個概念

微服務還不瞭解就落後了。。Consul 入門教程(全)

上圖來自於consul官方文檔

我們只看數據中心1,可以看出consul的集群是由N個SERVER,加上M個CLIENT組成的。而不管是SERVER還是CLIENT,都是consul的一個節點,所有的服務都可以註冊到這些節點上,正是通過這些節點實現服務註冊信息的共享。除了這兩個,還有一些小細節,一一簡單介紹。

CLIENT

CLIENT表示consul的client模式,就是客戶端模式。是consul節點的一種模式,這種模式下,所有註冊到當前節點的服務會被轉發到SERVER,本身是不持久化這些信息。

SERVER

SERVER表示consul的server模式,表明這個consul是個server,這種模式下,功能和CLIENT都一樣,唯一不同的是,它會把所有的信息持久化的本地,這樣遇到故障,信息是可以被保留的。

SERVER-LEADER

中間那個SERVER下面有LEADER的字眼,表明這個SERVER是它們的老大,它和其它SERVER不一樣的一點是,它需要負責同步註冊的信息給其它的SERVER,同時也要負責各個節點的健康監測。

其它信息其它信息包括它們之間的通信方式,還有一些協議信息,算法。它們是用於保證節點之間的數據同步,實時性要求等等一系列集群問題的解決。這些有興趣的自己看看官方文檔。

四、安裝 Consul

  Consul 下載地址:https://www.consul.io/downloads.html,下載後解壓就是一個可執行的二進制文件consul,配置好環境變量,檢查 consul 是否可用:

[root@localhost ~]# consul 
Usage: consul [--version] [--help] <command> [<args>]
Available commands are:
agent Runs a Consul agent
catalog Interact with the catalog
event Fire a new event
exec Executes a command on Consul nodes
force-leave Forces a member of the cluster to enter the "left" state
info Provides debugging information for operators.
join Tell Consul agent to join cluster
keygen Generates a new encryption key
keyring Manages gossip layer encryption keys
kv Interact with the key-value store
leave Gracefully leaves the Consul cluster and shuts down
lock Execute a command holding a lock
maint Controls node or service maintenance mode
members Lists the members of a Consul cluster
monitor Stream logs from a Consul agent
operator Provides cluster-level tools for Consul operators
reload Triggers the agent to reload configuration files
rtt Estimates network round trip time between nodes
snapshot Saves, restores and inspects snapshots of Consul server state
validate Validate config files/directories
version Prints the Consul version
watch Watch for changes in Consul
/<args>/<command>

  如果出現上面這樣代表consul是沒問題的。

五、運行 Consul Agent

  Consul安裝之後,代理必須運行。 代理可以在服務器或客戶端模式下運行。 每個數據中心都必須至少有一臺服務器,但推薦使用3臺或5臺服務器。 一個單一的服務器部署是非常不推薦的,因為在故障情況下數據丟失是不可避免的。

  所有其他代理以客戶端模式運行。 客戶端是一個非常輕量級的進程,它註冊服務,運行健康檢查,並將查詢轉發給服務器。 代理程序必須在集群中的每個節點上運行。

  為了簡單起見,我們現在將以開發模式啟動Consul代理。 這種模式對於快速簡單地啟動單節點Consul環境非常有用。 它並不打算在生產中使用,因為它不會持續任何狀態。

[root@localhost consul]# consul agent -dev
==> Starting Consul agent...
==> Consul agent running!
Version: 'v1.0.1'
Node ID: '590309a6-71f6-6145-fe40-d2c5e203687f'
Node name: 'localhost.localdomain'
Datacenter: 'dc1' (Segment: '')
Server: true (Bootstrap: false)
Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, DNS: 8600)
Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false
==> Log data will now stream in as it occurs:
2017/11/25 15:15:54 [DEBUG] Using random ID "590309a6-71f6-6145-fe40-d2c5e203687f" as node ID
2017/11/25 15:15:54 [INFO] raft: Initial configuration (index=1): [{Suffrage:Voter ID:590309a6-71f6-6145-fe40-d2c5e203687f Address:127.0.0.1:8300}]
2017/11/25 15:15:54 [INFO] serf: EventMemberJoin: localhost.localdomain.dc1 127.0.0.1
2017/11/25 15:15:54 [INFO] serf: EventMemberJoin: localhost.localdomain 127.0.0.1
2017/11/25 15:15:54 [INFO] agent: Started DNS server 127.0.0.1:8600 (udp)
2017/11/25 15:15:54 [INFO] raft: Node at 127.0.0.1:8300 [Follower] entering Follower state (Leader: "")
2017/11/25 15:15:54 [INFO] consul: Adding LAN server localhost.localdomain (Addr: tcp/127.0.0.1:8300) (DC: dc1)
2017/11/25 15:15:54 [INFO] consul: Handled member-join event for server "localhost.localdomain.dc1" in area "wan"
2017/11/25 15:15:54 [INFO] agent: Started DNS server 127.0.0.1:8600 (tcp)
2017/11/25 15:15:54 [INFO] agent: Started HTTP server on 127.0.0.1:8500 (tcp)
2017/11/25 15:15:54 [INFO] agent: started state syncer
2017/11/25 15:15:54 [WARN] raft: Heartbeat timeout from "" reached, starting election
2017/11/25 15:15:54 [INFO] raft: Node at 127.0.0.1:8300 [Candidate] entering Candidate state in term 2
2017/11/25 15:15:54 [DEBUG] raft: Votes needed: 1
2017/11/25 15:15:54 [DEBUG] raft: Vote granted from 590309a6-71f6-6145-fe40-d2c5e203687f in term 2. Tally: 1
2017/11/25 15:15:54 [INFO] raft: Election won. Tally: 1
2017/11/25 15:15:54 [INFO] raft: Node at 127.0.0.1:8300 [Leader] entering Leader state
2017/11/25 15:15:54 [INFO] consul: cluster leadership acquired
2017/11/25 15:15:54 [DEBUG] consul: Skipping self join check for "localhost.localdomain" since the cluster is too small
2017/11/25 15:15:54 [INFO] consul: member 'localhost.localdomain' joined, marking health alive
2017/11/25 15:15:54 [INFO] consul: New leader elected: localhost.localdomain
2017/11/25 15:15:54 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically
2017/11/25 15:15:54 [INFO] agent: Synced node info
2017/11/25 15:15:54 [DEBUG] agent: Node info in sync
2017/11/25 15:15:57 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically
2017/11/25 15:15:57 [DEBUG] agent: Node info in sync
2017/11/25 15:16:54 [DEBUG] consul: Skipping self join check for "localhost.localdomain" since the cluster is too small
2017/11/25 15:17:51 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically

2017/11/25 15:17:51 [DEBUG] agent: Node info in sync
2017/11/25 15:17:54 [DEBUG] manager: Rebalanced 1 servers, next active server is localhost.localdomain.dc1 (Addr: tcp/127.0.0.1:8300) (DC: dc1)
2017/11/25 15:17:54 [DEBUG] consul: Skipping self join check for "localhost.localdomain" since the cluster is too small

  如您所見,Consul代理已經啟動並輸出了一些日誌數據。 從日誌數據中,您可以看到我們的代理正在服務器模式下運行,並聲稱擁有集群領導權。 此外,當地成員已被標記為該集群的健康成員。

六、集群成員

  在另一個終端運行consul members,可以看到Consul集群的成員。 應該只看到一個成員(你自己):

[root@localhost ~]# consul members
Node Address Status Type Build Protocol DC Segment
localhost.localdomain 127.0.0.1:8301 alive server 1.0.1 2 dc1

  輸出顯示了我們自己的節點,它正在運行的地址,運行狀況,在集群中的角色以及一些版本信息。 額外的元數據可以通過提供-detailed標誌來查看。

[root@localhost ~]# consul members -detailed
Node Address Status Tags
localhost.localdomain 127.0.0.1:8301 alive build=1.0.1:9564c29,dc=dc1,id=590309a6-71f6-6145-fe40-d2c5e203687f,port=8300,raft_vsn=3,role=consul,segment=,vsn=2,vsn_max=3,vsn_min=2,wan_join_port=8302

members命令的輸出基於gossip協議,並最終一致。 也就是說,在任何時候,當地代理所看到的可能與服務器上的狀態不完全一致。 要獲得完全一致,請使用HTTP API再將HTTP請求轉發給Consul服務器:

[root@localhost ~]# curl localhost:8500/v1/catalog/nodes
[
{
"ID": "590309a6-71f6-6145-fe40-d2c5e203687f",
"Node": "localhost.localdomain",
"Address": "127.0.0.1",
"Datacenter": "dc1",
"TaggedAddresses": {
"lan": "127.0.0.1",
"wan": "127.0.0.1"
},
"Meta": {
"consul-network-segment": ""
},
"CreateIndex": 5,
"ModifyIndex": 6
}
]

  除了HTTP API之外,還可以使用DNS接口查詢節點。 請注意,必須確保將DNS查找默認情況下指向在端口8600上運行的Consul代理的DNS服務器。 DNS條目的格式(如“Armons-MacBook-Air.node.consul”)將在後面詳細介紹。

[root@localhost ~]# dig @127.0.0.1 -p 8600 localhost.localdomain.node.consul
'
; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 localhost.localdomain.node.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;localhost.localdomain.node.consul. IN A
;; ANSWER SECTION:
localhost.localdomain.node.consul. 0 IN A 127.0.0.1
;; Query time: 0 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: 六 11月 25 15:39:49 CST 2017
;; MSG SIZE rcvd: 78

七、停止 Agent

  可以使用Ctrl-C(中斷信號)正常停止代理。 中斷代理之後,您應該看到它離開集群並關閉。

  通過優雅地離開,Consul通知其他集群成員該節點離開。 如果強行殺死了代理進程,則集群的其他成員將檢測到該節點失敗。 成員離開時,其服務和檢查將從目錄中刪除。 當一個成員失敗時,其健康被簡單地標記為關鍵,但不會從目錄中刪除。 Consul將自動嘗試重新連接到失敗的節點,使其能夠從特定的網絡條件恢復,而不再聯繫離開的節點。

  此外,如果代理正在作為服務器運行,那麼優雅的離開對於避免造成影響一致協議的潛在可用性中斷很重要。 有關如何安全地添加和刪除服務器的詳細信息,請參閱指南部分。

八、註冊服務

1、服務定義

  服務可以通過提供服務定義或通過對HTTP API進行適當的調用來註冊。

  服務定義是註冊服務最常用的方式,所以我們將在這一步中使用這種方法。 我們將建立在上一步中介紹的代理配置。

  首先,為Consul配置創建一個目錄。 Consul將所有配置文件加載到配置目錄中,因此Unix系統上的一個通用約定是將目錄命名為/etc/consul.d(.d後綴意味著“該目錄包含一組配置文件”)。

[root@localhost etc]# sudo mkdir /etc/consul.d

  接下來,我們將編寫一個服務定義配置文件。 假設我們有一個名為“web”的服務在端口80上運行。另外,我們給它一個標籤,我們可以使用它作為查詢服務的附加方式:

[root@localhost ~]# echo '{"service": {"name": "web", "tags": ["rails"], "port": 80}}' | sudo tee /etc/consul.d/web.json

  現在,重新啟動代理程序,提供配置目錄:

[root@localhost ~]# consul agent -dev -config-dir=/etc/consul.d
==> Starting Consul agent...
==> Consul agent running!
Version: 'v1.0.1'
Node ID: '94236f1c-2a29-85c5-b235-dd916485be5b'
Node name: 'localhost.localdomain'
Datacenter: 'dc1' (Segment: '')
Server: true (Bootstrap: false)
Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, DNS: 8600)
Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false
==> Log data will now stream in as it occurs:
2017/11/25 16:16:51 [DEBUG] Using random ID "94236f1c-2a29-85c5-b235-dd916485be5b" as node ID
2017/11/25 16:16:51 [INFO] raft: Initial configuration (index=1): [{Suffrage:Voter ID:94236f1c-2a29-85c5-b235-dd916485be5b Address:127.0.0.1:8300}]
2017/11/25 16:16:51 [INFO] serf: EventMemberJoin: localhost.localdomain.dc1 127.0.0.1
2017/11/25 16:16:51 [INFO] serf: EventMemberJoin: localhost.localdomain 127.0.0.1
2017/11/25 16:16:51 [INFO] agent: Started DNS server 127.0.0.1:8600 (udp)
2017/11/25 16:16:51 [INFO] raft: Node at 127.0.0.1:8300 [Follower] entering Follower state (Leader: "")
2017/11/25 16:16:51 [INFO] consul: Adding LAN server localhost.localdomain (Addr: tcp/127.0.0.1:8300) (DC: dc1)
2017/11/25 16:16:51 [INFO] consul: Handled member-join event for server "localhost.localdomain.dc1" in area "wan"

2017/11/25 16:16:51 [INFO] agent: Started DNS server 127.0.0.1:8600 (tcp)
2017/11/25 16:16:51 [INFO] agent: Started HTTP server on 127.0.0.1:8500 (tcp)
2017/11/25 16:16:51 [INFO] agent: started state syncer
2017/11/25 16:16:52 [WARN] raft: Heartbeat timeout from "" reached, starting election
2017/11/25 16:16:52 [INFO] raft: Node at 127.0.0.1:8300 [Candidate] entering Candidate state in term 2
2017/11/25 16:16:52 [DEBUG] raft: Votes needed: 1
2017/11/25 16:16:52 [DEBUG] raft: Vote granted from 94236f1c-2a29-85c5-b235-dd916485be5b in term 2. Tally: 1
2017/11/25 16:16:52 [INFO] raft: Election won. Tally: 1
2017/11/25 16:16:52 [INFO] raft: Node at 127.0.0.1:8300 [Leader] entering Leader state
2017/11/25 16:16:52 [INFO] consul: cluster leadership acquired
2017/11/25 16:16:52 [DEBUG] consul: Skipping self join check for "localhost.localdomain" since the cluster is too small
2017/11/25 16:16:52 [INFO] consul: member 'localhost.localdomain' joined, marking health alive
2017/11/25 16:16:52 [INFO] consul: New leader elected: localhost.localdomain
2017/11/25 16:16:52 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically
2017/11/25 16:16:52 [INFO] agent: Synced service "web"
2017/11/25 16:16:52 [DEBUG] agent: Node info in sync
2017/11/25 16:16:52 [DEBUG] agent: Service "web" in sync
2017/11/25 16:16:52 [DEBUG] agent: Node info in sync
2017/11/25 16:16:52 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically
2017/11/25 16:16:52 [DEBUG] agent: Service "web" in sync
2017/11/25 16:16:52 [DEBUG] agent: Node info in sync

  您會注意到它在輸出中“同步”了Web服務。 這意味著代理程序從配置文件加載了服務定義,並已成功將其註冊到服務目錄中。

  如果您想註冊多個服務,您可以在Consul配置目錄中創建多個服務定義文件。

2、查詢服務

  一旦代理啟動並且服務同步,我們可以使用DNS或HTTP API來查詢服務。

DNS API

  我們首先使用DNS API來查詢我們的服務。 對於DNS API,服務的DNS名稱是NAME.service.consul。 默認情況下,所有DNS名稱始終在consul命名空間中,儘管這是可配置的。 服務子域告訴Consul我們正在查詢服務,NAME是服務的名稱。

  對於我們註冊的Web服務,這些約定和設置會生成web.service.consul的完全限定的域名:

[root@localhost ~]# dig @127.0.0.1 -p 8600 web.service.consul
; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 web.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;web.service.consul. IN A
;; ANSWER SECTION:
web.service.consul. 0 IN A 127.0.0.1
;; Query time: 0 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: 六 11月 25 16:22:29 CST 2017
;; MSG SIZE rcvd: 63

  正如你所看到的,一個A記錄返回了服務可用的節點的IP地址。 A記錄只能保存IP地址。

  您也可以使用DNS API來檢索整個地址/端口對作為SRV記錄:

[root@localhost ~]# dig @127.0.0.1 -p 8600 web.service.consul SRV
; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 web.service.consul SRV
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 3
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;web.service.consul. IN SRV
;; ANSWER SECTION:
web.service.consul. 0 IN SRV 1 1 80 localhost.localdomain.node.dc1.consul.
;; ADDITIONAL SECTION:
localhost.localdomain.node.dc1.consul. 0 IN A 127.0.0.1
localhost.localdomain.node.dc1.consul. 0 IN TXT "consul-network-segment="

;; Query time: 0 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: 六 11月 25 16:25:21 CST 2017
;; MSG SIZE rcvd: 156

  SRV記錄表示Web服務正在端口80上運行,並且存在於節點localhost.localdomain.node.dc1.consul.上。DNS使用該記錄的A記錄返回附加部分。

  最後,我們也可以使用DNS API來按標籤過濾服務。 基於標記的服務查詢的格式是TAG.NAME.service.consul。 在下面的例子中,我們向Consul詢問所有帶有“rails”標籤的web服務。 自從我們使用該標籤註冊我們的服務後,我們得到了成功的回應:

[root@localhost ~]# dig @127.0.0.1 -p 8600 rails.web.service.consul
; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 rails.web.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;rails.web.service.consul. IN A
;; ANSWER SECTION:
rails.web.service.consul. 0 IN A 127.0.0.1
;; Query time: 0 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: 六 11月 25 16:29:10 CST 2017
;; MSG SIZE rcvd: 69

HTTP API

  除了DNS API之外,HTTP API還可以用來查詢服務:

[root@localhost ~]# curl http://localhost:8500/v1/catalog/service/web
[
{

"ID": "94236f1c-2a29-85c5-b235-dd916485be5b",
"Node": "localhost.localdomain",
"Address": "127.0.0.1",
"Datacenter": "dc1",
"TaggedAddresses": {
"lan": "127.0.0.1",
"wan": "127.0.0.1"
},
"NodeMeta": {
"consul-network-segment": ""
},
"ServiceID": "web",
"ServiceName": "web",
"ServiceTags": [
"rails"
],
"ServiceAddress": "",
"ServicePort": 80,
"ServiceEnableTagOverride": false,
"CreateIndex": 6,
"ModifyIndex": 6
}
]

  目錄API提供了託管給定服務的所有節點。 正如我們稍後將看到的健康檢查一樣,您通常只需要查詢檢查通過的健康實例。 這是DNS正在做的事情。 這是一個查詢只查找健康的實例:

[root@localhost ~]# curl 'http://localhost:8500/v1/health/service/web?passing'
[
{
"Node": {
"ID": "94236f1c-2a29-85c5-b235-dd916485be5b",
"Node": "localhost.localdomain",
"Address": "127.0.0.1",
"Datacenter": "dc1",
"TaggedAddresses": {
"lan": "127.0.0.1",
"wan": "127.0.0.1"
},
"Meta": {
"consul-network-segment": ""
},
"CreateIndex": 5,

"ModifyIndex": 6
},
"Service": {
"ID": "web",
"Service": "web",
"Tags": [
"rails"
],
"Address": "",
"Port": 80,
"EnableTagOverride": false,
"CreateIndex": 6,
"ModifyIndex": 6
},
"Checks": [
{
"Node": "localhost.localdomain",
"CheckID": "serfHealth",
"Name": "Serf Health Status",
"Status": "passing",
"Notes": "",
"Output": "Agent alive and reachable",
"ServiceID": "",
"ServiceName": "",
"ServiceTags": [],
"Definition": {},
"CreateIndex": 5,
"ModifyIndex": 5
}
]
}
]

3、更新服務

  服務定義可以通過更改配置文件並向代理發送SIGHUP來更新。 這使您可以更新服務,而不會出現任何停機或無法提供服務查詢的情況。

  或者,可以使用HTTP API動態地添加,刪除和修改服務。

九、Consul 集群

  我們已經開始了我們的第一個代理,並註冊和查詢該代理的服務。 這顯示了使用Consul是多麼的容易,但並沒有表明如何將其擴展到可擴展的生產級服務發現基礎設施。 在這一步中,我們將創建我們的第一個真正的集群與多個成員。

  當一個Consul代理啟動時,它不知道任何其他節點:它是一個孤立的集群。 要了解其他集群成員,代理必須加入現有集群。 要加入現有的集群,只需要知道一個現有的成員。 代理加入後,會與該成員通訊,並迅速發現集群中的其他成員。 Consul代理可以加入任何其他代理,而不僅僅是服務器模式下的代理。

1、啟動代理

  在我們之前的例子中,我們使用了-dev標誌來快速設置一個開發服務器。 但是,這不足以在集群環境中使用。 我們將從這裡省略-dev標誌,而是指定我們的集群標誌。

  集群中的每個節點都必須具有唯一的名稱。 默認情況下,Consul使用機器的主機名,但我們將使用-node命令行選項手動覆蓋它。

  我們還將指定一個-bind:這是Consul偵聽的地址,它必須可以被集群中的所有其他節點訪問。 雖然綁定地址不是絕對必要的,但最好提供一個。 Consul將默認嘗試偵聽系統上的所有IPv4接口,但如果找到多個私有IP,將無法啟動錯誤。 由於生產服務器通常具有多個接口,因此指定一個綁定地址可確保您永遠不會將Consul綁定到錯誤的接口。

  第一個節點將作為我們在這個集群中唯一的服務器,我們用-server來指明這一點。

-bootstrap-expect選項向Consul服務器提示我們期望加入的其他服務器節點的數量。 此選項的用途是延遲複製日誌的引導,直到預期數量的服務器成功加入。

  我們已經將-enable_script_checks選項設置為true,以啟用可以執行外部腳本的運行狀況檢查。 這將在後面的例子中使用。 對於生產用途,您希望將ACL配置為與此配合使用,以控制註冊任意腳本的能力。

  最後,我們添加-config-dir選項,標記可以找到服務和檢查定義的位置。

  總而言之,這些設置產生一個這樣的consul代理命令:

[root@localhost ~]# consul agent -server -bootstrap-expect=1 -data-dir=/tmp/consul -node=agent-one -bind=192.168.100.101 -enable-script-checks=true -config-dir=/etc/consul.d

  現在,在另一個終端中,我們將連接到第二個節點。

  這次,我們將-bind設置為第二個節點的IP,並將-node設置為agent-two。 由於這個節點不會是Consul服務器,所以我們不提供-server。

  總而言之,這些設置產生一個這樣的consul代理命令:

[root@localhost ~]# consul agent -data-dir=/tmp/consul -node=agent-two -bind=192.168.100.102 -enable-script-checks=true -config-dir=/etc/consul.d

  此時,您有兩個Consul代理正在運行:一個服務器和一個客戶端。 兩個Consul代理人對彼此還是一無所知,都是他們自己的單節點集群的一部分。 您可以通過對每個代理運行consul members來驗證這一點,並注意到每個代理只能看到一個成員。

2、加入集群

  現在,我們將通過在新終端中運行以下命令來告訴第一個代理加入第二個代理:

[root@localhost ~]# consul join 192.168.100.101
Successfully joined cluster by contacting 1 nodes.

  如果在虛擬機裡面運行上面的命令提示下面的失敗的話,在每臺虛擬機上執行下這個命令:

[root@localhost ~]# consul join 192.168.100.101
Error joining address '192.168.100.101': Unexpected response code: 500 (1 error(s) occurred:
* Failed to join 192.168.100.101: dial tcp 192.168.100.101:8301: getsockopt: no route to host)
Failed to join any nodes.
[root@localhost ~]# sudo iptables -F

  您應該在每個代理日誌中看到一些日誌輸出。 如果仔細閱讀,您會看到他們收到了加入信息。 如果你對每個代理執行consul members,你會看到兩個代理人現在彼此瞭解:

[root@localhost ~]# consul members
Node Address Status Type Build Protocol DC Segment

agent-one 192.168.100.101:8301 alive server 1.0.1 2 dc1
agent-two 192.168.100.102:8301 alive client 1.0.1 2 dc1 <default>
/<default>

記住:要加入集群,Consul代理只需要瞭解一個現有的成員。 加入集群后,代理人互相傳播完整的會員信息。

3、在啟動時自動加入集群

  理想情況下,每當新節點出現在您的數據中心時,它就會自動加入Consul集群,無需人工干預。 Consul通過啟用AWS,Google Cloud或Azure中的實例的自動發現功能,使用給定的標籤 key/value來促進自動加入。 要使用集成,請將retry_join_ec2,retry_join_gce或retry_join_azure嵌套對象添加到您的Consul配置文件。 這將允許新的節點加入集群,而不需要任何硬編碼的配置。 或者,您可以在啟動時使用-join選項或start_join設置以及其他已知Consul代理的硬編碼地址加入集群。

4、查詢節點

  就像查詢服務一樣,Consul也有查詢節點的API。 您可以通過DNS或HTTP API執行此操作。

  對於DNS API,名稱的結構是NAME.node.consul或NAME.node.DATACENTER.consul。 如果數據中心被省略,Consul將僅搜索本地數據中心。

  例如,從“agent-one”中,我們可以查詢節點“agent-two”的地址:

[root@localhost etc]# dig @127.0.0.1 -p 8600 agent-two.node.consul
; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 agent-two.node.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;agent-two.node.consul. IN A
;; ANSWER SECTION:
agent-two.node.consul. 0 IN A 192.168.100.102
;; Query time: 0 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: 六 11月 25 17:31:29 CST 2017
;; MSG SIZE rcvd: 66

  除了服務之外,查找節點的能力對於系統管理任務來說是非常有用的。 例如,知道要通過SSH連接的節點的地址與將節點作為Consul集群的一部分並查詢它一樣簡單。

5、離開集群

  要離開集群,可以正常退出代理(使用Ctrl-C)或強制終止其中一個代理。 優雅地離開允許節點轉換到離開狀態; 否則,其他節點將檢測到它失敗。

十、健康檢查

  現在我們已經看到了運行Consul,添加節點和服務以及查詢這些節點和服務的簡單性。 在本節中,我們將介紹為節點和服務添加健康檢查。 健康檢查是服務發現的關鍵組件,可以防止使用不健康的服務。

  此步驟建立在之前創建的Consul集群上。 此時,您應該運行一個雙節點集群。

1、檢查定義

  與服務類似,可以通過提供檢查定義或通過對HTTP API進行適當的調用來註冊檢查。

  我們將使用檢查定義方法,因為就像服務一樣,定義是設置檢查最常用的方法。

  在第二個節點的Consul配置目錄中創建兩個定義文件:

[root@localhost ~]# echo '{"check": {"name": "ping", "script": "ping -c1 google.com >/dev/null", "interval": "30s"}}' >/etc/consul.d/ping.json
[root@localhost ~]# echo '{"service": {"name": "web", "tags": ["rails"], "port": 80, "check": {"script": "curl localhost >/dev/null 2>&1", "interval": "10s"}}}' >/etc/consul.d/web.json

  第一個定義添加了一個名為“ping”的主機級別的檢查。 此檢查運行間隔30秒,調用ping -c1 google.com。 在基於腳本的運行狀況檢查上,檢查以與啟動Consul進程相同的用戶身份運行。 如果該命令以非零退出碼退出,則該節點將被標記為不健康。 這是任何基於腳本的健康檢查的約定。

  第二個命令修改名為web的服務,添加一個檢查,每隔10秒通過curl發送一個請求,以驗證Web服務器是否可訪問。 與主機級運行狀況檢查一樣,如果腳本以非零退出代碼退出,服務將被標記為不健康。

  現在,重新啟動第二個代理,用consul reload加載它,或者發送一個SIGHUP信號。 您應該看到以下日誌行:

[root@localhost ~]# consul reload
Configuration reload triggered
2017/11/26 10:47:41 [INFO] Reloading configuration...
2017/11/26 10:47:41 [WARN] agent: check "service:web" has the 'script' field, which has been deprecated and replaced with the 'args' field. See https://www.consul.io/docs/agent/checks.html
2017/11/26 10:47:41 [WARN] agent: check "service:web" has the 'script' field, which has been deprecated and replaced with the 'args' field. See https://www.consul.io/docs/agent/checks.html
2017/11/26 10:47:41 [WARN] agent: check "ping" has the 'script' field, which has been deprecated and replaced with the 'args' field. See https://www.consul.io/docs/agent/checks.html
2017/11/26 10:47:41 [WARN] agent: check "ping" has the 'script' field, which has been deprecated and replaced with the 'args' field. See https://www.consul.io/docs/agent/checks.html
2017/11/26 10:47:41 [INFO] agent: Synced service "web"
2017/11/26 10:47:41 [INFO] agent: Synced check "ping"
2017/11/26 10:47:47 [WARN] agent: Check "service:web" is now critical
2017/11/26 10:47:57 [WARN] agent: Check "service:web" is now critical
2017/11/26 10:48:04 [WARN] agent: Check "ping" is now warning
2017/11/26 10:48:04 [INFO] agent: Synced check "ping"
2017/11/26 10:48:07 [WARN] agent: Check "service:web" is now critical
2017/11/26 10:48:17 [WARN] agent: Check "service:web" is now critical
2017/11/26 10:48:27 [WARN] agent: Check "service:web" is now critical

  前幾行表示代理已經同步了新的定義。 最後一行表明我們為Web服務添加的檢查是至關重要的。 這是因為我們實際上沒有運行Web服務器,所以curl測試失敗了!

2、檢查健康狀態

  現在我們已經添加了一些簡單的檢查,我們可以使用HTTP API來檢查它們。 首先,我們可以使用這個命令查找任何失敗的檢查(注意,這可以在任一節點上運行):

[root@localhost etc]# curl http://localhost:8500/v1/health/state/critical
[{"Node":"agent-two","CheckID":"service:web","Name":"Service 'web' check","Status":"critical","Notes":"","Output":"","ServiceID":"web","ServiceName":"web","ServiceTags":["rails"],"Definition":{},"CreateIndex":230,"ModifyIndex":262}]

  我們可以看到,只有一個檢查,我們的Web服務檢查,在危險(critical)狀態。

  另外,我們可以嘗試使用DNS查詢Web服務。 由於服務不健康,Consul不會返回任何結果:

[root@localhost ~]# dig @127.0.0.1 -p 8600 web.service.consul
; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 web.service.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;web.service.consul. IN A
;; AUTHORITY SECTION:
consul. 0 IN SOA ns.consul. hostmaster.consul. 1511666146 3600 600 86400 0
;; Query time: 1 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: 日 11月 26 11:15:46 CST 2017
;; MSG SIZE rcvd: 97

十一、KV Data

  Consul除了提供服務發現和綜合健康檢查之外,還提供一個易於使用的KV存儲。 這可以用來保存動態配置,協助服務協調,建立leader選舉,並使開發人員可以考慮構建的任何東西。

1、簡單使用

  為了演示有多簡單,我們將操作K / V存儲中的幾個鍵。 有兩種方式與Consul KV存儲進行交互:通過HTTP API和Consul KV CLI。 以下示例顯示使用Consul KV CLI,因為它是最容易入門的。 對於更高級的集成,您可能需要使用Consul KV HTTP API。

  首先讓我們探索KV存儲。 我們可以向Consul詢問名為redis / config / minconns的路徑上的key的值:

[root@localhost ~]# consul kv get redis/config/minconns
Error! No key exists at: redis/config/minconns

  正如你所看到的,我們沒有得到任何結果,這是合理的,因為KV存儲沒有數據。 接下來,我們可以insert或put 值到 KV 存儲中。

[root@localhost ~]# consul kv put redis/config/minconns 1
Success! Data written to: redis/config/minconns
[root@localhost ~]# consul kv put redis/config/maxconns 25
Success! Data written to: redis/config/maxconns
[root@localhost ~]# consul kv put -flags=42 redis/config/users/admin abcd1234
Success! Data written to: redis/config/users/admin

  現在我們在存儲中有key,我們可以查詢單個 key 的 value:

[root@localhost ~]# consul kv get redis/config/minconns
1

  Consul保留有關使用-detailed標誌檢索的字段的其他元數據:

[root@localhost ~]# consul kv get -detailed redis/config/minconns
CreateIndex 517
Flags 0
Key redis/config/minconns
LockIndex 0
ModifyIndex 517
Session -
Value 1

  對於“redis / config / users / admin”這個鍵,我們設置了一個標誌值42。所有的鍵都支持設置一個64位的整數標誌值。 這不是Consul在內部使用的,但客戶可以使用它為任何KV添加有意義的元數據。

  可以使用遞歸選項列出存儲的所有 key和 value。 結果將以字典順序返回:

[root@localhost ~]# consul kv get -recurse
redis/config/maxconns:25
redis/config/minconns:1
redis/config/users/admin:abcd1234

  要從Consul KV中刪除一個 key,發出“刪除” 命令:

[root@localhost ~]# consul kv delete redis/config/minconns
Success! Deleted key: redis/config/minconns

  也可以使用遞歸選項刪除整個前綴:

[root@localhost ~]# consul kv delete -recurse redis
Success! Deleted keys with prefix: redis

  要更新現有key的值,請在相同路徑上put一個值:

[root@localhost ~]# consul kv put foo bar
Success! Data written to: foo
[root@localhost ~]# consul kv get foo
bar
[root@localhost ~]# consul kv put foo zip
Success! Data written to: foo
[root@localhost ~]# consul kv get foo
zip

  Consul可以使用Check-And-Set操作提供原子鍵更新。 要執行CAS操作,請指定-cas選項:

[root@localhost ~]# consul kv get -detailed foo
CreateIndex 710
Flags 0
Key foo
LockIndex 0

ModifyIndex 716
Session -
Value bar
[root@localhost ~]# consul kv put -cas -modify-index=716 foo bar
Success! Data written to: foo
[root@localhost ~]# consul kv put -cas -modify-index=716 foo bar
Error! Did not write to foo: CAS failed

  在這種情況下,第一個CAS更新成功,因為索引是716。第二個操作失敗,因為索引不再是716。

十二、Consul Web UI

  Consul支持web ui界面。UI可用於查看所有服務和節點,查看所有運行狀況檢查及其當前狀態,以及讀取和設置鍵/值數據。 用戶界面自動支持多數據中心。

  要設置自帶的UI,請使用-ui參數啟動Consul代理:

consul agent -ui

  UI可以在與HTTP API相同的端口上的/ui路徑中使用。 默認情況下,這是http://localhost:8500/ui。

  您可以在這裡查看Consul Web UI的現場演示。

十三、Docker下安裝consul

1、拉取鏡像

 docker search consul

2、啟動consul

  • 啟動節點1(server模式)
  • docker run -d -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' --name=node1 consul agent -server -bind=172.17.0.2 -bootstrap-expect=3 -node=node1
  • -node:節點的名稱
  • -bind:綁定的一個地址,用於節點之間通信的地址,可以是內外網,必須是可以訪問到的地址
  • -server:這個就是表示這個節點是個SERVER
  • -bootstrap-expect:這個就是表示期望提供的SERVER節點數目,數目一達到,它就會被激活,然後就是LEADER了
  • 啟動節點2-3(server模式)
  • docker run -d -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' --name=node2 consul agent -server -bind=172.17.0.3 -join=172.17.0.2 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=node2 docker run -d -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' --name=node3 consul agent -server -bind=172.17.0.4 -join=172.17.0.2 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=node3 -client=172.17.0.4
  • -join:這個表示啟動的時候,要加入到哪個集群內,這裡就是說要加入到節點1的集群
  • -node-id:這個貌似版本8才加入的,這裡用這個來指定唯一的節點ID,可以查看這個issue
  • -client:這個表示註冊或者查詢等一系列客戶端對它操作的IP,如果不指定這個IP,默認是127.0.0.1。
  • 啟動節點4(client模式)
  • docker run -d -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}' --name=node4 consul agent -bind=172.17.0.5 -retry-join=172.17.0.2 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=node4
  • 除了沒有-server,其它都是一樣的,沒有這個就說明這個節點是CLIENT
  • 查看下集群的狀態
  • docker exec -t node1 consul members
微服務還不瞭解就落後了。。Consul 入門教程(全)

4個節點都列出來了。Status表示它們的狀態,都是alive。Type表示它們的類型,三個SERVER一個CLIENT,和我們之前啟動的一樣。DC表示數據中心,都是dc1。

  • 節點異常consul的處理
  • LEADER 掛了
  • leader掛了,consul會重新選取出新的leader,只要超過一半的SERVER還活著,集群是可以正常工作的。node1是leader,所以把這個容器停了。
  • docker stop node1
  • 看看其他節點的日誌(node2):

微服務還不瞭解就落後了。。Consul 入門教程(全)


  • 日誌打印,心跳檢查node1的ip超時,接著開始選舉。node2被選舉為新的leader。我們查看下現在的leader:
  • curl http://172.17.0.4:8500/v1/status/leader
  • 返回的內容:
  • "172.17.0.3:8300"
  • 172.17.0.3 就是 node2節點的IP

3、註冊個服務

使用HTTP API 註冊個服務,使用[接口API](https://www.consul.io/api/agent/service.html API)調用

調用 http://consul:8500/v1/agent/service/register PUT 註冊一個服務。request body:

{
"ID": "userServiceId", //服務id
"Name": "userService", //服務名
"Tags": [ //服務的tag,自定義,可以根據這個tag來區分同一個服務名的服務
"primary",
"v1"
],
"Address": "127.0.0.1",//服務註冊到consul的IP,服務發現,發現的就是這個IP

"Port": 8000, //服務註冊consul的PORT,發現的就是這個PORT
"EnableTagOverride": false,
"Check": { //健康檢查部分
"DeregisterCriticalServiceAfter": "90m",
"HTTP": "http://www.baidu.com", //指定健康檢查的URL,調用後只要返回20X,consul都認為是健康的
"Interval": "10s" //健康檢查間隔時間,每隔10s,調用一次上面的URL
}
}

使用curl調用

curl http://172.17.0.4:8500/v1/agent/service/register -X PUT -i -H "Content-Type:application/json" -d '{
"ID": "userServiceId",
"Name": "userService",
"Tags": [
"primary",
"v1"
],
"Address": "127.0.0.1",
"Port": 8000,
"EnableTagOverride": false,
"Check": {
"DeregisterCriticalServiceAfter": "90m",
"HTTP": "http://www.baidu.com",
"Interval": "10s"
}
}'

4、發現個服務

剛剛註冊了名為userService的服務,我們現在發現(查詢)下這個服務

curl http://172.17.0.4:8500/v1/catalog/service/userService

返回的響應:

[ 

{
"Address": "172.17.0.4",
"CreateIndex": 880,
"ID": "e6e9a8cb-c47e-4be9-b13e-a24a1582e825",
"ModifyIndex": 880,
"Node": "node3",
"NodeMeta": {},
"ServiceAddress": "127.0.0.1",
"ServiceEnableTagOverride": false,
"ServiceID": "userServiceId",
"ServiceName": "userService",
"ServicePort": 8000,
"ServiceTags": [
"primary",
"v1"
],
"TaggedAddresses": {
"lan": "172.17.0.4",
"wan": "172.17.0.4"
}
}
]

內容有了吧,這個就是我們剛剛註冊的服務的信息,就可以獲取到

服務的名稱是“userService”

服務地址是“127.0.0.1”

服務的端口是“8000”

5、存儲個K/V

設置一個值到user/config/connections 內容為5

docker exec -t node1 consul kv put user/config/connections 5

6、獲取特定的值

docker exec -t node1 consul kv get -detailed user/config/connections
微服務還不瞭解就落後了。。Consul 入門教程(全)

值的內容為5,還有key等相關的值。


分享到:


相關文章: