基於Docker的Consul集羣實現服務發現

 

服務發現
html

其實簡單說,服務發現就是解耦服務與IP地址之間的硬綁定關係,
以典型的集羣爲例,對於集羣來講,是有多個節點的,這些節點對應多個IP(或者同一個IP的不一樣端口號),集羣中不一樣節點責任是不同的。
好比說一個數據集羣中,能夠分爲讀節點或者寫節點,寫節點和讀節點都是相對的,不是硬綁定的,某一個邏輯節點,隨着故障轉移及恢復,是能夠變換身份的(寫變讀,讀變寫;主降從,從升主等等)
集羣對外提供服務的時候,對於外界來講,集羣中節點身份變換的時候須要對外透明,外界無需由於集羣節點的身份變換而更改配置,這就須要一個解耦合的服務。
Consul,zookeeper等中間件,就是作這個透明轉換的,也就是服務發現。這裏簡單測試consul做爲服務發現的實現。
Consul是一種服務解耦解決方案(service mesh solution,糾結了很久不知道怎麼翻譯)提供具備服務發現配置和分段功能的全功能控制系統(control plane)
這些功能中的每個均可以根據須要單獨使用也能夠一塊兒使用以構建完整的服務解耦 即使是用了谷歌翻譯的狀況下,這段翻譯糾結了半天,不知道怎麼翻譯合適。

以下是按照本身對consul作服務發現的理解,簡單整理的邏輯結構圖,其原理仍是比較容易理解的。
Consul is a service mesh solution providing a full featured control plane with service discovery, configuration, and segmentation functionality. Each of these features can be used individually as needed, or they can be used together to build a full service mesh. Consul requires a data plane and supports both a proxy and native integration model. Consul ships with a simple built-in proxy so that everything works out of the box, but also supports 3rd party proxy integrations such as Envoy. https://www.consul.io/intro/index.html
它提供以下幾個關鍵功能
服務發現
  Consul的某些客戶端能夠提供一個服務例如api或者mysql其它客戶端可使用Consul去發現這個服務的提供者
  使用DNS或者HTTP應用能夠很容易的找到他們所依賴的服務
健康檢查
  Consul客戶端能夠提供一些健康檢查這些健康檢查能夠關聯到一個指定的服務服務是否返回200 OK),也能夠關聯到本地節點內存使用率是否在90%如下)。
  這些信息能夠被一個操做員用來監控集羣的健康狀態被服務發現組件路由時用來遠離不健康的主機
鍵值存儲 
  應用可使用Consul提供的分層鍵值存儲用於一些目的包括動態配置特徵標記協做leader選舉等等經過一個簡單的HTTP API能夠很容易的使用這個組件
多數據中心 
  Consul對多數據中心有很是好的支持這意味着Consul用戶沒必要擔憂因爲建立更多抽象層而產生的多個區域
Consul被設計爲對DevOps羣體和應用開發者友好他很是適合現代的可伸縮的基礎設施
 
 
本文基於docker來實現consul的服務發現配置,方法consul agent是經過json註冊的模式實現服務註冊,
其中consul的服務端是3節點的集羣,客戶點是6節點3主3從的redis服務器集羣,consul實現redis集羣中讀寫服務註冊於發現。

儘管Redis cluster有多IP方式驅動鏈接,這裏僅僅爲了測試「服務發現」的。
其實原本想測試MySQL單主模式的MGR,實現讀寫分離的服務發現,可是MySQL有點過重了,機器配置不夠,因此作了Redis的集羣來測試服務發現
 
 
consul服務端集羣安裝配置
做爲服務發現的載體,consul是可使用單節點運行的,做爲解析服務的載體,是一個很是重要的角色,集羣化具備更強的抗災性,所以更多的時候是以多節點集羣的方式運行解析服務的這個載體。

這裏使用三個節點做爲consul的集羣服務端來運行,三個consul的服務節點IP分別是:172.18.0.11 ,172.18.0.12,172.18.0.13,須要固定IP
docker network create --subnet=172.18.0.11/16 mynetwork 
docker run -itd --name consul01 --net mynetwork --ip 172.18.0.11 -v /usr/local/docker_file/consul01/:/usr/local/ centos  
docker run -itd --name consul02 --net mynetwork --ip 172.18.0.12 -v /usr/local/docker_file/consul02/:/usr/local/ centos  
docker run -itd --name consul03 --net mynetwork --ip 172.18.0.13 -v /usr/local/docker_file/consul03/:/usr/local/ centos  
分別在每一個容器中建立consul服務(unzip consul_1.6.2_linux_amd64.zip解壓縮便可,很是簡單)
三個容器節點的server.json節點配置文件以下,惟一的區別就是bind_addr指定爲當前節點的IP
以下是172.18.0.11節點的配置,不一樣節點僅需修改bind_addr爲對應機器(容器)的IP

/usr/local/server.json 
{ "datacenter": "dc1", "data_dir": "/usr/local/", "log_level": "INFO", "server": true, "bootstrap_expect": 3, "bind_addr": "172.18.0.11", "client_addr": "0.0.0.0", "start_join": ["172.18.0.11","172.18.0.12","172.18.0.13"], "ui":true }
依次登陸三個容器中,以server模式啓動consul服務
./consul agent -server -config-dir=/usr/local > /usr/local/consul.log &
因爲配置文件中制定了集羣的IP列表,所以無需顯式加入集羣(cluster join),正常狀況下,啓動三個節點後,會自動組成一個集羣,而且自動選舉出來一個leader。
consul 集羣服務的狀態
./consul members --http-addr 172.18.0.11:8500
./consul operator raft list-peers -http-addr=172.18.0.12:8500


consul客戶端安裝配置
容器客戶端節點安裝,6個節點IP分別是:172.18.0.21,172.18.0.22,172.18.0.23,172.18.0.24,172.18.0.25,172.18.0.26
docker run -itd --name redis01 --net mynetwork --ip 172.18.0.21 -v /usr/local/docker_file/redis01/:/usr/local/ centos 
docker run -itd --name redis02 --net mynetwork --ip 172.18.0.22 -v /usr/local/docker_file/redis02/:/usr/local/ centos 
docker run -itd --name redis03 --net mynetwork --ip 172.18.0.23 -v /usr/local/docker_file/redis03/:/usr/local/ centos 
docker run -itd --name redis04 --net mynetwork --ip 172.18.0.24 -v /usr/local/docker_file/redis04/:/usr/local/ centos 
docker run -itd --name redis05 --net mynetwork --ip 172.18.0.25 -v /usr/local/docker_file/redis05/:/usr/local/ centos 
docker run -itd --name redis06 --net mynetwork --ip 172.18.0.26 -v /usr/local/docker_file/redis06/:/usr/local/ centos
 
6個client節點的配置以及服務定義,服務探測腳本以下
以下是172.18.0.21節點的配置,不一樣節點僅需修改bind_addr爲對應機器(容器)的IP

client.json
{
  "data_dir": "usr/local/consuldata",
  "enable_script_checks": true,
  "bind_addr": "172.18.0.21",
  "retry_join": ["172.18.0.11","172.18.0.12","172.18.0.13"],
  "retry_interval": "30s",
  "rejoin_after_leave": true,
  "start_join": ["172.18.0.11","172.18.0.12","172.18.0.13"]
}
分別啓動三個client節點的consul服務,以client的模式運行,啓動後,正常狀況下會自動加入到consul的服務端集羣中。
./consul agent -config-dir=/usr/local/consuldata > /usr/local/consuldata/consul.log &
./consul members --http-addr 172.18.0.11:8500
 
 
consul客戶端代理服務註冊
6個容器節點依次安裝redis,作成一個集羣(步驟略),這裏的consul客戶端代理的是一個3中3從的Redis集羣,這裏不列出來Redis集羣的安裝。
Redis集羣安裝參考http://www.javashuo.com/article/p-gndkpqts-d.html,仍是很是方便的,在本地(容器節點)一鍵建立6個節點3主3從的集羣。
其中主節點是172.18.0.21,172.18.0.22,172.18.0.23,從節點是172.18.0.24,172.18.0.25,172.18.0.26

這裏是使用 w-master-redis-8888.service.consul名字做爲三個redis集羣節點的服務代理。
172.18.0.21節點上的redis-master-8888.json(172.18.0.22,172.18.0.23,172.18.0.24,172.18.0.25,172.18.0.26 類同,僅需修改address)
{
  "services": 
  [
    {
      "name": "w-master-redis-8888",
      "tags": [
        "master"
      ],
      "address": "172.18.0.21",
      "port": 8888,
      "checks": [
        {
         "args":["sh","-c","/usr/local/consuldata/check_redis_master.sh 172.18.0.21 8888 ******"],
         "Shell":"/bin/bash",
         "interval": "15s"
        }
      ]
    }
  ]
}

redis-slave-8888.json mysql

{
  "services": 
  [
    {
      "name": "r-slave-redis-8888",
      "tags": [
        "master"
      ],
      "address": "172.18.0.21",
      "port": 8888,
      "checks": [
        {
         "args":["sh","-c","/usr/local/consuldata/check_redis_slave.sh 172.18.0.21 8888 ******"],
         "Shell":"/bin/bash",
         "interval": "15s"
        }
      ]
    }
  ]
}

Consul client節點的Redis主節點(寫節點)服務檢查腳本check_redis_master.sh
如下腳原本源於http://www.javashuo.com/article/p-xrsvsuad-m.html,作了簡單的修改,在節點的身份判斷邏輯上須要增強。
linux

#!/bin/bash host=$1 myport=$2 auth=$3
if [ ! -n "$auth" ] then auth='\"\"'
fi comm="/usr/local/redis_instance/redis8888/bin/redis-cli -h $host -p $myport -a $auth " role=`echo 'INFO Replication'|$comm |grep -Ec 'role:master'` echo 'INFO Replication'|$comm if [ $role -ne 1 ] then exit 2
fi

Consul client節點的Redis從節點服務檢查腳本check_redis_slave.sh
redis

#!/bin/bash
host=$1
myport=$2
auth=$3
if [ ! -n "$auth" ]
then
auth='\"\"'
fi
comm="/usr/local/redis_instance/redis8888/bin/redis-cli -h $host -p $myport -a $auth "
role=`echo 'INFO Replication'|$comm |grep -Ec 'role:slave'`
echo $role
echo 'INFO Replication'|$comm


if [ $role -ne 1 ]
then
    exit 2
fi

 

Consul服務發現sql

redis集羣配置成功後,從新加載代理服務,consul reload,一切正常的話,consul服務端就能夠解析配置的服務了。
以下注冊了兩個服務,分別是r-slave-redis-8888,w-master-redis-8888,分別表明Redis集羣的讀寫節點。
docker

能夠看到,成功地解析了 w-master-redis-8888.service.consul這個服務,映射到172.18.0.21,172.18.0.22,172.18.0.23三個節點。
須要注意的是,這三個節點都是寫節點,這裏僅僅是爲了實現服務發現(儘管redis 有多IP的驅動支持)

r-slave-redis-8888.service.consul服務的解析,指向了三個從節點,172.18.0.24,172.18.0.25,172.18.0.26shell

故障轉移以後的服務發現:模擬主節點故障,對172.18.0.21節點手動故障轉移,如今172.18.0.21與172.18.0.24角色交換數據庫

Redis集羣故障轉之後的服務發現解析結果 對於w-master-redis-8888.service.consul這個服務,成功解析到172.18.0.24,172.18.0.22,172.18.0.23三個主節點

json

Redis集羣故障轉之後的服務發現解析結果 對於w-master-redis-8888.service.consul這個服務,成功解析到172.18.0.24,172.18.0.22,172.18.0.23三個主節點
bootstrap

 

遇到的問題:
1,cosnul服務端集羣的時候,clustercenter一開始自定義了一個名稱myconsule_datacenter,致使client節點死活加不進來,按照默認的dc1就沒有問題
目前還不理解這個datacenter的命名規則是什麼?
2,容器節點中的shell腳本要授予可執行權限chmod +x check_XXX.sh
3,其餘異常問題,必定要看日誌,搜索一下基本上都有結果。
如下純粹是Redis集羣的問題,與Consul沒有直接關係,僅做爲本測試中遇到的問題。
4,容器節點的Redis集羣時,須要移除bind_ip的127.0.0.1節點,直接配置docker建立容器時候的IP,建立集羣的時候會一致等待,waiting for the cluster to join
這一點redis-cli --cluster作的很扯淡,明明找不到節點,還要死等,不人爲終止的話,他會一直waiting
5,Redis集羣時候,由於主從都是相對的,須要相互識別對方,主從節點都要指定「masterauth」和「requirepass」,且密碼一致,不然執行cluster  failover提示成功,但故障轉移不成功
6,遇到一個靈異的問題(以前單機多實例的時候也遇到過),在啓動容器上的Redis服務的時候,若是使用絕對路徑啓動,在建立集羣的時候會出現從節點沒法添加到集羣中去的狀況,中止服務,以相對路徑方式重啓以後就沒有這個問題


總的來講consul這個中間件使用起來還算是比較簡單,配置也很清爽,不像某些中間件使人做嘔的配置結構(mycat???)
這裏沒有配置多數據中心模式,僅配置了單數據中心模式,做爲一款服務發現的中間件,是徹底沒有問題的,尤爲是做爲MySQL集羣不支持多IP鏈接驅動的數據庫鏈接。


參考:

相關文章
相關標籤/搜索