基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

零壹技術棧發表於2018-06-20

前言

近年微服務架構在網際網路應用領域中愈來愈火,引入微服務主要解決了單體應用多個模組的緊耦合無法擴充套件運維困難等問題。微服務架構就是按照功能粒度將業務模組進行垂直拆分,對單體應用本身進行服務化元件化,每個元件單獨部署為小應用(從DBUI)。微服務與微服務之間通過Service API進行互動,同時為了支援水平擴充套件效能提升服務可用性,單個服務允許同時部署一個或者多個服務例項。在執行時,每個例項通常是一個雲虛擬機器或者Docker容器

微服務系統內部多個服務的例項之間如何通訊?如何感知到彼此的存在和銷燬?生產者服務如何知道消費者服務的地址?如何實現服務與註冊中心的解耦?這就需要一個第三方的服務註冊中心,提供對生產者服務節點的註冊管理和消費者服務節點的發現管理。


正文

1. 服務發現與註冊

1.1. 具體流程

  • 服務註冊中心:作為整個架構中的核心,要支援分散式持久化儲存註冊資訊變動實時通知消費者。
  • 服務提供者: 服務以 docker 容器化方式部署(實現服務埠動態生成),可以通過 docker-compose 的方式來管理。通過 Registrator 檢測到 docker 程式資訊以完成服務的自動註冊
  • 服務消費者:要使用服務提供者提供的服務,和服務提供者往往是動態相互轉位置的。

一個較為完整的服務註冊與發現流程如下:

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

  1. 註冊服務:服務提供者到註冊中心註冊
  2. 訂閱服務:服務消費者到註冊中心訂閱服務資訊,對其進行監聽
  3. 快取服務列表:本地快取服務列表,減少與註冊中心的網路通訊;
  4. 呼叫服務:先查詢本地快取,找不到再去註冊中心拉取服務地址,然後傳送服務請求;
  5. 變更通知:服務節點變動時 (新增刪除等),註冊中心將通知監聽節點,更新服務資訊。

1.2. 相關元件

一個服務發現系統主要由三部分組成:

  1. 註冊器(registrator):根據服務執行狀態,註冊/登出服務。主要要解決的問題是,何時發起註冊/登出動作。
  2. 登錄檔(registry):儲存服務資訊。常見的解決方案有zookeeper、etcd、cousul等。
  3. 發現機制(discovery):從登錄檔讀取服務資訊,給使用者封裝訪問介面。

1.3. 第三方實現

對於第三方的服務註冊與發現的實現,現有的工具主要有以下三種:

  1. zookeeper:一個高效能、分散式應用程式協調服務,用於名稱服務、分散式鎖定、共享資源同步和分散式配置管理。
  2. Etcd:一個採用HTTP協議的健/值對儲存系統,主要用於共享配置和服務發現,提供的功能相對Zookeeper和Consul相對簡單。
  3. Consul:一個分散式高可用的服務發現和配置共享的軟體,支援服務發現與註冊、多資料中心、健康檢查和分散式鍵/值儲存。

簡單對比:

與Zookeeper和etcd不一樣,Consul內嵌實現了服務發現系統,不需要構建自己的系統或使用第三方系統,客戶只需要註冊服務,並通過DNS或HTTP介面執行服務發現。

2. Consul和Registrator

2.1. Consul簡介

Consul是什麼

Consul 是一種分散式的、高可用支援水平擴充套件的的服務註冊與發現工具。它大致包括以下特性:

  • 服務發現Consul 通過 DNS 或者 HTTP 介面使服務註冊和服務發現變的很容易。一些外部服務,例如 saas 提供的也可以一樣註冊;
  • 健康檢查:健康檢測使 consul 可以快速的告警在叢集中的操作。和服務發現的整合,可以防止服務轉發到故障的服務上面;
  • 鍵/值儲存:一個用來儲存動態配置的系統。提供簡單的 HTTP 介面,可以在任何地方操作;
  • 多資料中心:支援多資料中心以避免單點故障,內外網的服務採用不同的埠進行監聽。而其部署則需要考慮網路延遲, 分片等情況等。zookeeperetcd均不提供多資料中心功能的支援;
  • 一致性演算法:採用 Raft 一致性協議演算法,比Paxos演算法好用。 使用 GOSSIP 協議管理成員和廣播訊息, 並且支援 ACL 訪問控制;
  • 服務管理Dashboard:提供一個 Web UI 的服務註冊於健康狀態監控的管理頁面。

Consul的幾個概念

下圖是Consul官方文件提供的架構設計圖:

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

圖中包含兩個Consul資料中心,每個資料中心都是一個consul的叢集。在資料中心1中,可以看出consul的叢集是由NSERVER,加上MCLIENT組成的。而不管是SERVER還是CLIENT,都是consul叢集的一個節點。所有的服務都可以註冊到這些節點上,正是通過這些節點實現服務註冊資訊的共享。除了這兩個,還有一些小細節 一一 簡單介紹。

  • CLIENT

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

  • SERVER

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

  • SERVER-LEADER

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

  • 其它資訊

其它資訊包括各個節點之間的通訊方式,還有一些協議資訊演算法。它們是用於保證節點之間的資料同步實時性要求等等一系列叢集問題的解決。這些有興趣的自己看看官方文件。

2.2. Registrator簡介

什麼是Registrator Registrator是一個獨立於服務登錄檔的自動服務註冊/登出元件,一般以Docker container的方式進行部署。Registrator會自動偵測它所在的宿主機上的所有Docker容器狀態(啟用/銷燬),並根據容器狀態到對應的服務註冊列表註冊/登出服務。

事實上,Registrator通過讀取同一臺宿主機的其他容器Container環境變數進行服務註冊健康檢查定義等操作。

Registrator支援可插拔式服務登錄檔配置,目前支援包括Consul, etcdSkyDNS 2三種註冊工具。

2.3. Docker安裝Consul叢集

2.3.1. 叢集節點規劃

我本地的使用的是Ubuntu16.04的虛擬機器:

容器名稱 容器IP地址 對映埠號 宿主機IP地址 服務執行模式
node1 172.17.0.2 8500 -> 8500 192.168.127.128 Server Master
node2 172.17.0.3 9500 -> 8500 192.168.127.128 Server
node3 172.17.0.4 10500 -> 8500 192.168.127.128 Server
node4 172.17.0.5 11500 -> 8500 192.168.127.128 Client

2.3.2. Consul叢集安裝

Consul的配置引數資訊說明:

引數列表 引數的含義和使用場景說明
advertise 通知展現地址用來改變我們給叢集中的其他節點展現的地址,一般情況下-bind地址就是展現地址
bootstrap 用來控制一個server是否在bootstrap模式,在一個datacenter中只能有一個server處於bootstrap模式,當一個server處於bootstrap模式時,可以自己選舉為raft leader
bootstrap-expect 在一個datacenter中期望提供的server節點數目,當該值提供的時候,consul一直等到達到指定sever數目的時候才會引導整個叢集,該標記不能和bootstrap共用
bind 該地址用來在叢集內部的通訊IP地址,叢集內的所有節點到地址都必須是可達的,預設是0.0.0.0
client consul繫結在哪個client地址上,這個地址提供HTTP、DNS、RPC等服務,預設是127.0.0.1
config-file 明確的指定要載入哪個配置檔案
config-dir 配置檔案目錄,裡面所有以.json結尾的檔案都會被載入
data-dir 提供一個目錄用來存放agent的狀態,所有的agent允許都需要該目錄,該目錄必須是穩定的,系統重啟後都繼續存在
dc 該標記控制agent允許的datacenter的名稱,預設是dc1
encrypt 指定secret key,使consul在通訊時進行加密,key可以通過consul keygen生成,同一個叢集中的節點必須使用相同的key
join 加入一個已經啟動的agent的ip地址,可以多次指定多個agent的地址。如果consul不能加入任何指定的地址中,則agent會啟動失敗,預設agent啟動時不會加入任何節點
retry-interval 兩次join之間的時間間隔,預設是30s
retry-max 嘗試重複join的次數,預設是0,也就是無限次嘗試
log-level consul agent啟動後顯示的日誌資訊級別。預設是info,可選:trace、debug、info、warn、err
node 節點在叢集中的名稱,在一個叢集中必須是唯一的,預設是該節點的主機名
protocol consul使用的協議版本
rejoin 使consul忽略先前的離開,在再次啟動後仍舊嘗試加入叢集中
server 定義agent執行在server模式,每個叢集至少有一個server,建議每個叢集的server不要超過5個
syslog 開啟系統日誌功能,只在linux/osx上生效
pid-file 提供一個路徑來存放pid檔案,可以使用該檔案進行SIGINT/SIGHUP(關閉/更新)agent

2.4. Docker安裝Consul叢集

2.4.1. 拉取consul官方映象

madison@ubuntu:~$ docker pull consul:latest
複製程式碼

2.4.2. 啟動Server節點

執行consul映象,啟動Server Master節點node1

node1:

madison@ubuntu:~$ docker run -d --name=node1 --restart=always \
             -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' \
             -p 8300:8300 \
             -p 8301:8301 \
             -p 8301:8301/udp \
             -p 8302:8302/udp \
             -p 8302:8302 \
             -p 8400:8400 \
             -p 8500:8500 \
             -p 8600:8600 \
             -h node1 \
             consul agent -server -bind=172.17.0.2 -bootstrap-expect=3 -node=node1 \
             -data-dir=/tmp/data-dir -client 0.0.0.0 -ui

複製程式碼

檢視node1的日誌,追蹤執行情況:

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

現在叢集中還沒有選舉leader節點,繼續啟動其餘兩臺Server節點node2node3

node2:

madison@ubuntu:~$ docker run -d --name=node2 --restart=always \
             -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' \
             -p 9300:8300  \
             -p 9301:8301 \
             -p 9301:8301/udp \
             -p 9302:8302/udp \
             -p 9302:8302 \
             -p 9400:8400 \
             -p 9500:8500 \
             -p 9600:8600 \
             -h node2 \
             consul agent -server -bind=172.17.0.3 \
             -join=192.168.127.128 -node-id=$(uuidgen | awk '{print tolower($0)}') \
             -node=node2 \
             -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
複製程式碼

檢視node2節點的程式啟動日誌:

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

node3:

madison@ubuntu:~$ docker run -d --name=node3 --restart=always \
             -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' \
             -p 10300:8300  \
             -p 10301:8301 \
             -p 10301:8301/udp \
             -p 10302:8302/udp \
             -p 10302:8302 \
             -p 10400:8400 \
             -p 10500:8500 \
             -p 10600:8600 \
             -h node2 \
             consul agent -server -bind=172.17.0.4 \
             -join=192.168.127.128 -node-id=$(uuidgen | awk '{print tolower($0)}') \
             -node=node3 \
             -data-dir=/tmp/data-dir -client 0.0.0.0 -ui
複製程式碼

檢視node3節點的程式啟動日誌:

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

當3個Server節點都啟動並正常執行時,觀察node2node3的程式日誌,可以發現node1被選舉為leader節點,也就是這個資料中心Server Master

再次檢視node1節點的程式啟動日誌:

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

觀察日誌發現,node2node3都成功join到了node1所在的資料中心dc1。當叢集中有3臺Consul Server啟動時,node1被選舉為dc1中的主節點。然後,node1會通過心跳檢查的方式,不斷地對node2node3進行健康檢查。

2.4.4. 啟動Client節點

node4:

madison@ubuntu:~$ docker run -d --name=node4  --restart=always \
            -e 'CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}' \
            -p 11300:8300 \
            -p 11301:8301 \
            -p 11301:8301/udp \
            -p 11302:8302/udp \
            -p 11302:8302 \
            -p 11400:8400 \
            -p 11500:8500 \
            -p 11600:8600 \
            -h node4 \
            consul agent -bind=172.17.0.5 -retry-join=192.168.127.128  \
            -node-id=$(uuidgen | awk '{print tolower($0)}') \
            -node=node4 -client 0.0.0.0 -ui
複製程式碼

檢視node4節點的程式啟動日誌:

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

可以發現:node4是以Client模式啟動執行的。啟動後完成後,把dc1資料中心中的以Server模式啟動的節點node1node2node3都新增到本地快取列表中。當客戶端向node4發起服務發現的請求後,node4會通過RPC將請求轉發給Server節點中的其中一臺做處理。

2.4.5. 檢視叢集狀態

madison@ubuntu:~$ docker exec -t node1 consul members
複製程式碼

dc1資料中心中的4個節點node1, node2, node3node4分別成功啟動,Status表示他們的狀態,都為alivenode1, node2, node3Server模式啟動,而node4Client模式啟動。

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

2.5. Docker安裝Registrator

2.5.1. 拉取Registrator的映象

madison@ubuntu:~$ docker pull gliderlabs/registrator:latest
複製程式碼

2.5.2. 啟動Registrator節點

madison@ubuntu:~$ docker run -d --name=registrator \
             -v /var/run/docker.sock:/tmp/docker.sock \
             --net=host \
             gliderlabs/registrator -ip="192.168.127.128" consul://192.168.127.128:8500
複製程式碼

--net指定為host表明使用主機模式。 -ip用於指定宿主機的IP地址,用於健康檢查的通訊地址。 consul://192.168.127.128:8500: 使用Consul作為服務登錄檔,指定具體的Consul通訊地址進行服務註冊和登出(注意:8500是Consul對外暴露的HTTP通訊埠)。

檢視Registrator的容器程式啟動日誌:

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

Registrator在啟動過程完成了以下幾步操作:

  1. 檢視Consul資料中心的leader節點,作為服務登錄檔;
  2. 同步當前宿主機的啟用容器,以及所有的服務埠;
  3. 分別將各個容器釋出的服務地址/埠註冊到Consul的服務註冊列表。

2.5.3. 檢視Consul的註冊狀態

Consul提供了一個Web UI來視覺化服務註冊列表通訊節點資料中心鍵/值儲存等,直接訪問宿主機的8500埠。

服務註冊列表

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

NODES節點下掛載著dc1資料中心中的所有的Consul節點,包括Consul ServerClient

通訊節點列表

基於Docker + Consul + Registrator的服務註冊與發現叢集搭建

啟動Registrator以後,宿主機中的所有容器把服務都註冊到ConsulSERVICES上,測試完成!


總結

單資料中心Consul叢集的搭建就完成了!!!後續章節我會介紹如何使用Registrator進行服務註冊的標籤化。然後通過docker部署多例項Web容器來實現基於HTTPRESTful Service和基於TCPRPC Service服務註冊健康檢查定義,並演示如何以標籤標識一個服務的多個例項。


歡迎關注技術公眾號: 零壹技術棧

零壹技術棧

本帳號將持續分享後端技術乾貨,包括虛擬機器基礎,多執行緒程式設計,高效能框架,非同步、快取和訊息中介軟體,分散式和微服務,架構學習和進階等學習資料和文章。

相關文章