Consul與外部服務
HashiCorp Consul是一個服務網格,用於服務發現、執行時配置和微服務應用程式和基礎設施的服務分割。Consul允許註冊和發現“內部”服務到您的基礎設施,以及“外部”服務,例如第三方SaaS提供的服務,以及其他不可能直接執行Consul代理的環境。
這篇博文解釋瞭如何與Consul的外部服務合作,以及如何使用Consul ESM(外部服務監視器)來對這些服務進行健康檢查。我們將介紹:
- 這個主題的關鍵術語的術語表
- 內部服務註冊和健康檢查
- 外部服務註冊和健康檢查
- 拉/推健康檢查
- 使用Consul ESM監控外部服務的健康狀況
本文中的所有示例都使用Consul agent(
$ consul agent -dev -enable-script-checks -node=web -ui
隨著Consul dev agent的執行,本文中的示例使用curl與Consul的HTTP API以及Consul的Web UI進行互動,在http://127.0.0.1:8500上可訪問。
這個主題的關鍵術語的術語表
- 代理(Agent): Consul叢集的每個成員上的長時間執行的守護程序。代理可以在client或server模式下執行。
- 節點(Node): 節點表示執行代理的“物理”機器。這可能是一個裸露的金屬裝置、VM或容器。
- 服務(Service): 服務是應用程式或程序,註冊在Consul目錄中以供發現。服務可以是內部的(在您的資料中心內)或外部的(如RDS叢集),並且可以選擇與之相關聯的健康檢查。
- 檢查(Check): 檢查是一個本地執行的命令或操作,它返回附加物件的狀態。檢查可以附加到節點和服務上。
- 目錄(Catalog): 目錄是所有已註冊節點、服務和檢查的註冊中心。
內部服務註冊和健康檢查
首先,我們來看看如何註冊內部服務。在Consul的上下文中,內部服務是由Consul代理可以直接執行的節點(機器)提供的。
內部服務通過服務定義註冊。服務定義可以由Consul代理啟動時載入的配置檔案提供,也可以通過/agent/service/register的本地HTTP API端點提供。
我們將用以下配置註冊一個內部web示例,web.json:
{
"id": "web1",
"name": "web",
"port": 80,
"check": {
"name": "ping check",
"args": ["ping","-c1","www.google.com"],
"interval": "30s",
"status": "passing"
}
}
這個示例web服務將具有惟一的id web1、邏輯名稱web、執行在埠80上並進行一次健康檢查。
通過使用PUT請求呼叫HTTP API來註冊示例web服務:
$ curl --request PUT --data @web.json localhost:8500/v1/agent/service/register
要驗證示例web服務已註冊上去,請查詢/catalog/service/:service 端點:
$ curl localhost:8500/v1/catalog/service/web
[
{
"ID": "a2ebf70e-f912-54b5-2354-c65e2a2808de",
"Node": "web",
"Address": "127.0.0.1",
"Datacenter": "dc1",
"TaggedAddresses": {
"lan": "127.0.0.1",
"wan": "127.0.0.1"
},
"NodeMeta": {
"consul-network-segment": ""
},
"ServiceID": "web1",
"ServiceName": "web",
"ServiceAddress": "",
"ServiceMeta": {},
"ServicePort": 80,
"ServiceEnableTagOverride": false,
"CreateIndex": 7,
"ModifyIndex": 7
}
]
向 agent/service/register 端點註冊服務定義將本地節點註冊為服務提供者。節點上的本地Consul代理負責為註冊的服務進行健康檢查,並相應地更新目錄。
在我們的示例web服務中,我們使用以下配置定義了一個健康檢查:
"check": {
"name": "ping check",
"args": ["ping","-c1","www.google.com"],
"interval": "30s",
"status": "passing"
}
這個健康檢查驗證我們的web服務可以通過每30秒ping一次 google.com連線到公共網際網路。對於實際的web服務,應該配置更有用的健康檢查。Consul提供幾種健康檢查方式,包括:指令碼,HTTP, TCP,存活時間(TTL), Docker,和gPRC。
要檢驗為註冊到給定本地節點的服務配置的所有健康檢查,請使用/agent/checks/ 端點:
$ curl localhost:8500/v1/agent/checks
{
"service:web1": {
"Node": "web",
"CheckID": "service:web1",
"Name": "ping check",
"Status": "passing",
"Notes": "",
"Output": "PING www.google.com (172.217.3.164): 56 data bytes\n64 bytes from 172.217.3.164: icmp_seq=0 ttl=52 time=21.902 ms\n\n--- www.google.com ping statistics ---\n1 packets transmitted, 1 packets received, 0.0% packet loss\nround-trip min/avg/max/stddev = 21.902/21.902/21.902/0.000 ms\n",
"ServiceID": "web1",
"ServiceName": "web",
"ServiceTags": [
"rails"
],
"Definition": {},
"CreateIndex": 0,
"ModifyIndex": 0
}
}
可以使用/health/service/:service 查詢單個服務的健康狀況,使用/health/node/:node 查詢單個節點的健康狀態。
健康檢查也可以在Consul UI上檢視:
外部服務註冊和健康檢查
在Consul的上下文中,外部服務是由不能執行Consul代理的節點提供的服務。這些節點可能位於基礎設施內部(例如大型機、虛擬裝置或不支援的平臺)或基礎設施外部(例如SaaS平臺)。
因為根據定義,外部服務在沒有執行Consul代理的節點上執行,因此無法向本地代理註冊。相反,它們必須使用/catalog/register端點 直接與目錄一起註冊。這個端點的物件上下文是節點,而不是像/agent/service/register 端點那樣的服務。當使用/catalog/register端點時,將註冊整個節點。而使用/agent/service/register 端點(這是我們在上面的第一個例子中使用的端點),本地節點上下文中的單個服務被註冊。
直接通過目錄註冊的外部服務的配置與通過代理註冊的內部服務的配置略有不同:
- 節點(Node)和地址(Address)都是必需的,因為它們不能從本地節點Consul代理自動確定。
- 服務(Service)和健康檢查(Checks)是分開定義的。
- 如果提供的ServiceID與該節點上的服務ID匹配,則該檢查將被視為服務級健康檢查,而不是節點級健康檢查。
- 可以為Definition 欄位提供TCP或HTTP健康檢查的詳細資訊。有關更多資訊,請參閱健康檢查。
要演示外部服務註冊是如何工作的,請考慮谷歌提供的外部搜尋服務。我們用以下配置來註冊這個服務,extern.json:
{
"Node": "google",
"Address": "www.google.com",
"NodeMeta": {
"external-node": "true",
"external-probe": "true"
},
"Service": {
"ID": "search1",
"Service": "search",
"Port": 80
},
"Checks": [{
"Name": "http-check",
"status": "passing",
"Definition": {
"http": "https://www.google.com",
"interval": "30s"
}
}]
}
該配置定義了一個名為google 的節點,可以在地址www.google.com上訪問,該節點提供一個search服務,ID為search1,執行在埠80上。它還定義了每30秒執行一次的http型別健康檢查,並設定了該檢查的初始狀態 passing。
通常,外部服務是通過專門用於此目的的節點註冊的,因此我們將繼續使用Consul dev代理(localhost)進行示例,就好像它是在和內部web服務(例如“Web”)不同的另一個節點(例如“External Services”)上執行一樣。
下面這張圖顯示了向Consul註冊內部和外部服務之間的區別:
使用PUT請求註冊外部服務:
$ curl --request PUT --data @external.json localhost:8500/v1/catalog/register
true
與通過代理端點註冊的內部服務一樣,我們可以通過查詢/catalog/service/:service 端點來驗證外部服務的註冊:
$ curl localhost:8500/v1/catalog/service/search
[
{
"ID": "",
"Node": "google",
"Address": "www.google.com",
"Datacenter": "dc1",
"TaggedAddresses": null,
"NodeMeta": {
"external-node": "true",
"external-probe": "true"
},
"ServiceID": "search1",
"ServiceName": "search",
"ServiceTags": [],
"ServiceAddress": "",
"ServiceMeta": {},
"ServicePort": 80,
"ServiceEnableTagOverride": false,
"CreateIndex": 246,
"ModifyIndex": 246
}
]
在我們的內部web服務示例中,我們通過查詢本地代理端點 /agent/checks 來驗證健康檢查是活躍的。如果在新增外部服務之後再次查詢此內容,我們將不會看到列出的健康檢查,因為它是在服務目錄中註冊的,而不是本地代理。相反,我們需要查詢目錄級端點,例如/health/service/:service、/health/node/:node、/health/state/:state。
我們還可以看到Consul UI中列出的服務和健康檢查:
從上面可以看到,目錄中有一個健康檢查條目。但是,因為這個節點和服務是直接在目錄中註冊的,所以沒有設定實際的健康檢查,也不會監視節點的健康狀況。
為了演示直接通過目錄註冊的健康檢查與通過本地代理註冊的健康檢查之間的區別,可以在模擬停機前後查詢節點健康狀況。
要模擬停機,請斷開與internet的連線,稍等片刻,並檢查Consul UI:
在上面的輸出中,我們看到內部web服務的不再通過健康檢查,但是在不應該看到外部search服務通過健康檢查時,卻看到健康檢查通過了(passing)。在斷開internet連線時,這兩個服務的健康檢查都應該失敗,但只有對內部web服務的檢查顯示為失敗。
拉和推健康檢查
傳統健康檢查的一個問題是拉動式模型的使用。定期,監視伺服器詢問所有節點是否健康,節點以狀態響應。這就造成了瓶頸,因為隨著節點數量的增加,監視服務的流量也在增加。這會阻塞本地網路流量,並給叢集帶來不必要的負載。
Consul使用一個基於推送的模型,其中代理僅在狀態更改時傳送事件。因此,即使是大型叢集也只有很少的請求。邊緣觸發監測的問題是沒有活性心跳。也就是說,在沒有任何更新的情況下,Consul不知道檢查是否處於穩定狀態,或者伺服器是否死亡。Consul通過使用基於gossip協議的故障檢測器來解決這個問題。所有叢集成員都參與一個後臺gossip,不管叢集大小如何,這個gossip都有一個恆定的負載。gossip和edge觸發的更新的組合允許Consul擴充套件到非常大的叢集大小,而不需要過載。
因為Consul monitoring 要求Consul代理在被監視的服務上執行,所以不會對外部服務執行健康檢查。要啟用外部服務的健康監視,請使用Consul External Service Monitor(ESM)。
使用Consul ESM監控外部服務
Consul ESM是一個與Consul一起執行的守護程序,用於執行外部節點的健康檢查並更新目錄中那些健康檢查的狀態。ESM的多個例項可以執行以獲得可用性,並且ESM將通過持有一個Consul中的鎖來執行領導人選舉。然後,領導者將繼續監視Consul對目錄的更新,並執行在它發現的任何外部節點上定義的健康檢查。這允許外部註冊的服務和檢查訪問與Consul代理在本地註冊相同的功能。
與先前的圖表更新顯示Consul ESM如何與Consul合作監測外部服務的健康狀況:
Consul ESM是作為一個單一的二進位制檔案提供的。要安裝,請下載適合您系統的版本,並使其在您的路徑中可用。本文中的示例使用Consul ESM v0.2.0。
開啟一個新的終端,執行 consul-esm啟用Consul ESM。
$ consul-esm
2018/06/14 12:50:44 [INFO] Connecting to Consul on 127.0.0.1:8500...
Consul ESM running!
Datacenter: (default)
Service: "consul-esm"
Leader Key: "consul-esm/lock"
Node Reconnect Timeout: "72h0m0s"
Log data will now stream in as it occurs:
2018/06/14 12:50:44 [INFO] Waiting to obtain leadership...
2018/06/14 12:50:44 [INFO] Obtained leadership
如果您的internet提供者不允許UDP ping,為了使本文中的示例正常工作,您可能需要在配置檔案中設定ping_type = "socket",並使用該配置檔案啟動consult -esm。如果你正在使用macOS,你將需要執行sudo:
$ sudo consul-esm -config-file=./consul-esm.hcl
示例外部服務定義中包含以下節點元資料(NodeMeta),這些元資料使Consul ESM能夠進行健康監視:
- “external-node”標識該節點是Consul ESM應該監視的外部節點。
- “external-probe”:“true”告訴Consul ESM定期對節點執行ping,並維護節點的外部節點健康檢查(類似於Consul代理使用的serfHealth檢查)。
一旦Consul ESM執行,再次模擬從網際網路連線中斷。現在,在Consul UI中,可以看到我們的外部服務的健康檢查更新為critical 狀態:
Consul ESM支援HTTP和TCP健康檢查。Ping健康檢查自動添加了"external-probe": "true".
總結
Consul內部服務是由直接執行Consul代理的節點提供的服務。外部服務是由不能執行Consul代理的節點提供的服務。
內部服務通過本地Consul代理在服務定義中註冊。節點上的本地Consul代理負責執行為服務註冊的任何健康檢查,並相應地更新目錄。外部服務必須直接與目錄註冊,因為根據定義,它們在沒有Consul代理的節點上執行。
內部和外部服務都可以進行健康檢查。Consul的健康檢查使用基於推送的模型,其中代理僅在狀態更改時傳送事件。Consul提供幾種健康檢查,包括:指令碼,HTTP, TCP,TTL, Docker,和gPRC。因為Consul監視要求Consul代理在被監視的服務上執行,所以不會對外部服務執行健康檢查。要啟用外部服務的健康監視,請使用Consul External Service Monitor (ESM)。