consul简介
為什么80%的碼農都做不了架構師?>>> ??
consul簡介
這篇文檔簡單介紹一下consul這款軟件的功能以及原理。
注: 本篇博客主要介紹簡單的功能使用,在本地環境快速搭建起運行環境。如果要在產品環境部署,請參考這篇文章: https://www.digitalocean.com/community/tutorials/how-to-configure-consul-in-a-production-environment-on-ubuntu-14-04
HashiCorp的CTO在infoq上有一個分享,ppt在此(需爬墻): http://www.slideshare.net/InfoQ/consul-serviceoriented-at-scale 。極具參考價值。介紹了consul的用例,以及設計思想等等,強烈推薦一閱。看過這篇ppt以及下面的訪談記錄,再看consul的文檔就十分清晰了
consul是什么
consul是HashiCorp公司推出的一款開源工具,用于實現分布式系統的服務發現與配置。與其他類似產品相比,提供更“一站式”的解決方案。consul內置有KV存儲,服務注冊/發現,健康檢查,HTTP+DNS API,Web UI等多種功能。
HashiCorp官方公布的一張consul的架構圖如下:
consul的優勢
- 使用 Raft 算法來保證一致性, 比復雜的 Paxos 算法更直接. 相比較而言, zookeeper 采用的是 Paxos, 而 etcd 使用的則是 Raft.
- 支持多數據中心,內外網的服務采用不同的端口進行監聽。 多數據中心集群可以避免單數據中心的單點故障,而其部署則需要考慮網絡延遲, 分片等情況等. zookeeper 和 etcd 均不提供多數據中心功能的支持.
- 支持健康檢查. etcd 不提供此功能.
- 支持 http 和 dns 協議接口. zookeeper 的集成較為復雜, etcd 只支持 http 協議.
- 官方提供web管理界面, etcd 無此功能.
與其他同類型的產品詳細對比,官方有一個比較詳盡的文檔: https://www.consul.io/intro/vs/zookeeper.html
簡單來說,相比zookeeper,consul要更輕量,依賴輕(Go VS Java),Raft算法要比Paxos算法簡單的多,而且效率高。
相比etcd,提供了更多的功能,比如DNS server,多數據中心同步,WebUI等等。
consul的簡單使用
consul的使用非常簡單,采用Go語言編寫,編譯出的文件無其他依賴。因此只需要從官方下載編譯好的二進制可執行程序直接運行就可以了。
# consul usage: consul [--version] [--help] <command> [<args>]Available commands are:agent Runs a Consul agentconfigtest Validate config fileevent Fire a new eventexec Executes a command on Consul nodesforce-leave Forces a member of the cluster to enter the "left" stateinfo Provides debugging information for operatorsjoin Tell Consul agent to join clusterkeygen Generates a new encryption keykeyring Manages gossip layer encryption keysleave Gracefully leaves the Consul cluster and shuts downlock Execute a command holding a lockmaint Controls node or service maintenance modemembers Lists the members of a Consul clustermonitor Stream logs from a Consul agentreload Triggers the agent to reload configuration filesrtt Estimates network round trip time between nodesversion Prints the Consul versionwatch Watch for changes in Consulconsul的運行方式
consul以agent形式運行。agent有兩種模式: server和client。
server的作用是提供一致性的保證,存儲著Raft信息。幾乎可以認為server是數據存儲中心,絕大多數的運行數據都保存在server。每個數據中心至少要保證一個server節點。官方建議每個數據中心保持3,5或7個server節點,以保證高可用。以server方式運行:
consul agent -server -data-dir /tmp/consulclient就比server輕量的多,基本上只提供和server交互的接口,作為訪問server的代理。以client方式運行:
# 去掉-server參數就是client模式,并且要join到一個cluster中。 # 也可以使用consul join命令手工加入到一個集群中 consul agent -data-dir /tmp/consul -join X.X.X.X以下功能演示均需要有server節點,因此使用以下命令啟動server:
consul agent -server -ui -bootstrap -client=0.0.0.0 -data-dir /tmp/consul加上-ui參數可以啟用內置的WebUI,使用瀏覽器訪問http://localhost:8500即可打開這個WebUI。
服務注冊
服務需要先進行注冊,才能實現健康檢查,服務發現等這些功能。
服務注冊的方法有兩種,一種是寫到配置文件中,啟動時加載。另一種是在consul啟動之后通過HTTP API動態添加。
服務注冊的方法相當簡單,寫一個json配置文件,定義服務名即可,以定義一個rtds服務為例:
{"service": {"name": "rtds"} }保存為rtds.json,然后重啟consul并加載這個配置文件:
consul agent -server -ui -bootstrap -client=0.0.0.0 -data-dir /tmp/consul -config-file rtds.json打開webui(8500端口)就可以看到這個service了。也可以通過HTTP API列出這個service:
$ curl 172.16.250.11:8500/v1/agent/services?pretty {"consul": {"ID": "consul","Service": "consul","Tags": [],"Address": "","Port": 8300,"EnableTagOverride": false,"CreateIndex": 0,"ModifyIndex": 0},"rtds": {"ID": "rtds","Service": "rtds","Tags": null,"Address": "","Port": 0,"EnableTagOverride": false,"CreateIndex": 0,"ModifyIndex": 0} }服務動態注冊的方式,向HTTP API發起PUT請求注冊新服務,body部分和json配置文件格式一致:
$ curl 172.16.250.11:8500/v1/agent/services?pretty {"consul": {"ID": "consul","Service": "consul","Tags": [],"Address": "","Port": 8300,"EnableTagOverride": false,"CreateIndex": 0,"ModifyIndex": 0} }$ curl -XPUT -d '{"name":"rtds"}' 172.16.250.11:8500/v1/agent/service/register $ curl 172.16.250.11:8500/v1/agent/services?pretty {"consul": {"ID": "consul","Service": "consul","Tags": [],"Address": "","Port": 8300,"EnableTagOverride": false,"CreateIndex": 0,"ModifyIndex": 0},"rtds": {"ID": "rtds","Service": "rtds","Tags": null,"Address": "","Port": 0,"EnableTagOverride": false,"CreateIndex": 0,"ModifyIndex": 0} }服務發現
consul對服務發現提供兩種接口: HTTP API和DNS查詢。
先看下HTTP API。列出已注冊的服務GET請求/v1/catalog/services即可列出。追加?dc=<dc_name>可以列出指定數據中心的注冊服務。 用GET請求/v1/catalog/service/<service_name>即可列出注冊此服務的全部節點信息,同樣可以追加?dc=參數:
$ curl 172.16.250.11:8500/v1/catalog/service/rtds?pretty [{"Node": "shifudaotest","Address": "172.16.250.11","ServiceID": "rtds","ServiceName": "rtds","ServiceTags": [],"ServiceAddress": "","ServicePort": 0,"ServiceEnableTagOverride": false,"CreateIndex": 276,"ModifyIndex": 277} ]DNS API: consul會占用一個DNS服務器端口8600,提供DNS查詢服務。每一個注冊的服務,會在consul提供一條NAME.service.consul的解析記錄。用DNS查詢工具就可以進行查詢:
$ dig @172.16.250.11 -p 8600 rtds.service.consul # 使用dig工具查詢rtds.service.consul解析記錄; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @172.16.250.11 -p 8600 rtds.service.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20558 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available;; QUESTION SECTION: ;rtds.service.consul. IN A;; ANSWER SECTION: rtds.service.consul. 0 IN A 172.16.250.11;; Query time: 47 msec ;; SERVER: 172.16.250.11#8600(172.16.250.11) ;; WHEN: Fri May 06 20:13:58 CST 2016 ;; MSG SIZE rcvd: 72可以看到rtds.service.consul有一條A記錄,指向172.16.250.11。
現在把rtds服務注銷掉。可以看到rtds.service.consul已經沒有任何解析記錄了。
$ curl 172.16.250.11:8500/v1/agent/service/deregister/rtds # 將rtds服務注銷 $ dig @172.16.250.11 -p 8600 rtds.service.consul ; <<>> DiG 9.9.5-3ubuntu0.8-Ubuntu <<>> @172.16.250.11 -p 8600 rtds.service.consul ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 62263 ;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; WARNING: recursion requested but not available;; QUESTION SECTION: ;rtds.service.consul. IN A;; AUTHORITY SECTION: consul. 0 IN SOA ns.consul. postmaster.consul. 1462537218 3600 600 86400 0;; Query time: 5 msec ;; SERVER: 172.16.250.11#8600(172.16.250.11) ;; WHEN: Fri May 06 20:21:05 CST 2016 ;; MSG SIZE rcvd: 105健康檢查
consul對注冊的服務都支持健康檢查。方法是在service下面再嵌套一個check配置即可。
{"service": {"name": "service_name","check": {}} }consul支持5種check方式:
- Script + Interval: 周期性運行某個可執行程序,根據程序退出碼確定服務是否存活
- HTTP + Interval: 周期性訪問某個http地址,根據返回碼是否為2xx確定服務是否存活。429將警告
- TCP + Interval: 周期性發起TCP請求,根據是否成功建立連接TCP連接確定服務是否存活
- Time to Live (TTL): 類似于心跳檢測。服務狀態是用過周期性向HTTP接口發起PUT請求確定的。超期沒有更新數據就判斷服務掛了
- Docker + Interval: 通過docker的api檢測docker內服務的狀態
如果某個服務需要檢測多項,可以使用checks配置:
{"checks": [{"id": "chk1","name": "mem","script": "/bin/check_mem","interval": "5s"},{"id": "chk2","name": "/health","http": "http://localhost:5000/health","interval": "15s"},{"id": "chk3","name": "cpu","script": "/bin/check_cpu","interval": "10s"},...] }比如rtds會監聽TCP 3130端口,我們通過周期檢測3130端口的存活性判斷rtds的存活,繼續修改rtds.json如下:
{"service": {"name": "rtds","check": {"name": "rtds TCP on port 3130","tcp": "localhost:3130","interval": "10s","timeout": "1s"}} }使用以下命令重啟consul,加載rtds.json配置:
consul agent -server -ui -bootstrap -client=0.0.0.0 -data-dir /tmp/consul -config-file rtds.json也可以像服務注冊那樣,不使用配置文件,啟動之后通過HTTP API添加服務與健康檢測策略。操作方法完全一樣,這里不做演示。
rtds未啟動時:
$ curl 172.16.250.11:8500/v1/health/checks/rtds?pretty [{"Node": "shifudaotest","CheckID": "service:rtds","Name": "Service 'rtds' check","Status": "critical", # 服務未啟動,所以狀態顯示此服務掛了"Notes": "","Output": "","ServiceID": "rtds","ServiceName": "rtds","CreateIndex": 444,"ModifyIndex": 462} ]$ nslookup -port=8600 rtds.service.consul 172.16.250.11 # nslookup也是一個dns測試工具 Server: 172.16.250.11 Address: 172.16.250.11#8600# 服務掛了,所以沒有rtds.service.consul的解析記錄啟動rtds,等上10秒(配置的檢測周期為10秒):
$ curl 172.16.250.11:8500/v1/health/checks/rtds?pretty [{"Node": "shifudaotest","CheckID": "service:rtds","Name": "Service 'rtds' check","Status": "passing", # 3130端口可以成功建立TCP連接,于是passing了"Notes": "","Output": "TCP connect localhost:3130: Success","ServiceID": "rtds","ServiceName": "rtds","CreateIndex": 444,"ModifyIndex": 499} ]$ nslookup -port=8600 rtds.service.consul 172.16.250.11 Server: 172.16.250.11 Address: 172.16.250.11#8600Name: rtds.service.consul Address: 172.16.250.11KV存儲
這個功能就沒太多要說明的了,基本用法就跟redis的用法差不多。
KV的API路徑是/v1/kv/<key>,支持GET,PUT,DELETE三種請求。如果key最后跟一個/,代表創建一級目錄。
$ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key1 true $ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/key2?flags=42 true $ curl -X PUT -d 'test' http://localhost:8500/v1/kv/web/sub/key3 true $ curl http://localhost:8500/v1/kv/?recurse [{"CreateIndex":97,"ModifyIndex":97,"Key":"web/key1","Flags":0,"Value":"dGVzdA=="},{"CreateIndex":98,"ModifyIndex":98,"Key":"web/key2","Flags":42,"Value":"dGVzdA=="},{"CreateIndex":99,"ModifyIndex":99,"Key":"web/sub/key3","Flags":0,"Value":"dGVzdA=="}]需要注意的consul返回的value是base64編碼,官方的解釋是為了防止出現非UTF-8字符,所以統一編碼成base64。第二個范例追加了一個flags參數,這個flags并非是由consul內部使用,而是提供給客戶端的保留字段,客戶端可以自定義其他含義。 如果追加?raw參數,將直接返回未經base64編碼的Value值。
此外,consul的KV存儲還支持Check-And-Set操作(當ModifyIndex匹配時才進行修改鍵值)。詳情參考官方文檔: https://www.consul.io/intro/getting-started/kv.html
ACL
consul提供訪問控制列表(Access Control List)功能,通過ACL可以實現權限控制。consul的ACL是Capability-based security(能力基礎安全)。
也就是這種ACL是每一級路徑都可以而配置單獨權限,默認策略是子權限繼承父權限。比如/kv/key/的權限是deny,那么/kv/key/sub1這樣的路徑無法訪問。如果再追加一條規則/kv/key/sub2的權限是read,那么/kv/key/sub2/key這樣的key有只讀權限,其余的key均無法訪問。通過帶上?token=參數驗證ACL權限,ACL配置是針對每個token的。如果不帶token參數,則默認anonymous。
啟用ACL只能在配置文件中指定。創建一個config.json文件,寫入以下內容:
{"acl_datacenter": "dc1","acl_default_policy": "deny","acl_master_token": "master" }對dc1這個數據中心(默認的數據中心)啟動ACL,默認的ACL規則是deny(即不指定權限時,默認為deny),擁有管理權限的token是master。
加載這個配置啟動consul agent:
consul agent -server -ui -bootstrap -client=0.0.0.0 -data-dir /tmp/consul -config-file config.json現在再請求kv,發現會返回404:
curl -v '172.16.250.11:8500/v1/kv/?recurse' # -v參數可以看到返回碼是404帶上master token再請求這個API,就沒問題:
$ curl '172.16.250.11:8500/v1/kv/?token=master&recurse' [{"LockIndex":0,"Key":"web/key1","Flags":0,"Value":"bW9kaWZpZWQ=","CreateIndex":633,"ModifyIndex":634}]現在創建一個token mytoken,對kv/web/有只讀權限,對service/rtds有讀寫權限,可以這么做:
$ curl -XPUT -d @- '172.16.250.11:8500/v1/acl/create?token=master' <<EOF {"Type": "client","Name": "mytoken","Rules": "service \"rtds\" {\n policy = \"write\"\n }\n key \"web/\" {\n policy = \"read\"\n }" } EOF {"ID":"1f8799ce-6f45-427c-f8e6-3878f9eda582"}consul會返回一個ID: 1f8799ce-6f45-427c-f8e6-3878f9eda582。將這個值作為token參數傳遞給HTTP API就擁有了對應的權限。
$ curl '172.16.250.11:8500/v1/kv/?recurse&token=1f8799ce-6f45-427c-f8e6-3878f9eda582&pretty' [{"LockIndex": 0,"Key": "web/key1","Flags": 0,"Value": "bW9kaWZpZWQ=","CreateIndex": 633,"ModifyIndex": 634} ]可以看到帶上這個token以后,就可以讀取web/key1的值了,而之前是404。
其他功能
以上幾個功能都是WebUI上可以可視化操作的功能,是最常見的功能。其他還有一些只能用API操作的功能。比如consul exec直接調用RPC接口,而非HTTP接口。consul event向消息總線發送自定義消息。consul watch監聽消息總線異步響應,甚至還支持分布式鎖等等。這些功能可以詳細參考官方文檔,用到的時候再查閱官方文檔。
轉載于:https://my.oschina.net/abcfy2/blog/675665
總結
- 上一篇: XSD文件结构详解
- 下一篇: 花三千块钱求推荐一个靠谱的C++工程师