Docker中建立Consul叢集

weixin_34393428發表於2018-12-06

一、Consul簡介

Consul 是一套開源的分散式服務發現和配置管理系統,由 HashiCorp 公司用 Go 語言開發。它具有很多優點。包括:基於 raft 協議,比較簡潔; 支援健康檢查, 同時支援 HTTP 和 DNS 協議 支援跨資料中心的 WAN(廣域網) 叢集 提供圖形介面 跨平臺,支援 Linux、Mac、Windows。

consul是使用go語言開發的服務發現、配置管理中心服務。內建了服務註冊與發現框 架、分佈一致性協議實現、健康檢查、Key/Value儲存、多資料中心方案,不再需要依賴其他工具(比如ZooKeeper等)。服務部署簡單,只有一個可執行的二進位制的包。每個節點都需要執行agent,他有兩種執行模式server和client。每個資料中心官方建議需要3或5個server節點以保證資料安全,同時保證server-leader的選舉能夠正確的進行。

@client

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

@server

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

@server-leader

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

@raft(分散式一致性協議)

server節點之間的資料一致性保證,一致性協議使用的是raft,而zookeeper用的paxos,etcd採用的也是raft。

@服務發現協議

consul採用http和dns協議,etcd只支援http

@服務註冊

consul支援兩種方式實現服務註冊,一種是通過consul的服務註冊http API,由服務自己呼叫API實現註冊,另一種方式是通過json個是的配置檔案實現註冊,將需要註冊的服務以json格式的配置檔案給出。consul官方建議使用第二種方式。

@服務發現

consul支援兩種方式實現服務發現,一種是通過http API來查詢有哪些服務,另外一種是通過consul agent 自帶的DNS(8600埠),域名是以NAME.service.consul的形式給出,NAME即在定義的服務配置檔案中,服務的名稱。DNS方式可以通過check的方式檢查服務。

@服務間的通訊協議

Consul使用gossip協議管理成員關係、廣播訊息到整個叢集,他有兩個gossip pool(LAN pool和WAN pool),LAN pool是同一個資料中心內部通訊的,WAN pool是多個資料中心通訊的,LAN pool有多個,WAN pool只有一個。

二、基本概念

在描述架構之前,這裡提供了一些術語來幫助宣告正在探討的東西:

  • Agent——agent是一直執行在Consul叢集中每個成員上的守護程式。通過執行 consul agent 來啟動。agent可以執行在client或者server模式。指定節點作為client或者server是非常簡單的,除非有其他agent例項。所有的agent都能執行DNS或者HTTP介面,並負責執行時檢查和保持服務同步。
  • Client——一個Client是一個轉發所有RPC到server的代理。這個client是相對無狀態的。client唯一執行的後臺活動是加入LAN gossip池。這有一個最低的資源開銷並且僅消耗少量的網路頻寬。
  • Server——一個server是一個有一組擴充套件功能的代理,這些功能包括參與Raft選舉,維護叢集狀態,響應RPC查詢,與其他資料中心互動WAN gossip和轉發查詢給leader或者遠端資料中心。
  • DataCenter——雖然資料中心的定義是顯而易見的,但是有一些細微的細節必須考慮。例如,在EC2中,多個可用區域被認為組成一個資料中心?我們定義資料中心為一個私有的,低延遲和高頻寬的一個網路環境。這不包括訪問公共網路,但是對於我們而言,同一個EC2中的多個可用區域可以被認為是一個資料中心的一部分。
  • Consensus——在我們的文件中,我們使用Consensus來表明就leader選舉和事務的順序達成一致。由於這些事務都被應用到有限狀態機上,Consensus暗示複製狀態機的一致性。
  • Gossip——Consul建立在Serf的基礎之上,它提供了一個用於多播目的的完整的gossip協議。Serf提供成員關係,故障檢測和事件廣播。更多的資訊在gossip文件中描述。這足以知道gossip使用基於UDP的隨機的點到點通訊。
  • LAN Gossip——它包含所有位於同一個區域網或者資料中心的所有節點。
  • WAN Gossip——它只包含Server。這些server主要分佈在不同的資料中心並且通常通過因特網或者廣域網通訊。
  • RPC——遠端過程呼叫。這是一個允許client請求server的請求/響應機制。

Consul Architecture 架構圖

14589598-9b7d1654ef016856.png
image.png

拆解開這個體系,從每一個元件開始瞭解。首先,可以看到有兩個資料中心,分別標記為“one”和“two”。Consul是支援多資料中心一流,並且是常用業務場景。

每個資料中心都是由Server和client組成。建議有3~5 Server——基於故障處理和效能的平衡之策。如果增加越多的機器,則Consensus會越來越慢。對client沒有限制,可以很容易地擴充套件到成千上萬或數萬。

同一個資料中心的所有節點都要加入Gossip協議。這意味著gossip pool包含給定資料中心的所有節點。有以下目的:首先,沒有必要為client配置伺服器地址引數;發現是自動完成的。第二,節點故障檢測的工作不是放置在伺服器上,而是分散式的。這使故障檢測比心跳機制更可擴充套件性。第三,可用來作為訊息層通知重要的事件,如leader選舉。

每個資料中心的伺服器都是屬於一個Raft peer。這意味著,他們一起工作,選出一個的Leader,Leader server是有額外的職責。負責處理所有的查詢和事務。事務也必須通過Consensus協議複製到所有的夥伴。由於這一要求,當非Leader Server接收到一個RPC請求,會轉發到叢集的leader。

Server節點也是作為WAN gossip pool的一部分。這個pool是與LAN gossip pool是不同的,它為具有更高延遲的網路響應做了優化,並且可能包括其他consul叢集的server節點。設計WANpool的目的是讓資料中心能夠以low-touch的方式發現彼此。將一個新的資料中心加入現有的WAN Gossip是很容易的。因為池中的所有Server都是可控制的,這也使跨資料中心的要求。當一個Serfer接收到不同的資料中心的要求時,它把這個請求轉發給相應資料中心的任一Server。然後,接收到請求的Server可能會轉發給Leader。

多個資料中心之間是低耦合,但由於故障檢測、連線快取複用、跨資料中心要求快速和可靠的響應。

三、Docker中建立Consul叢集

1 使用docker下載consul映象,預設下載最consul最新版本,目前版本號為1.4.0,如果需要其他版本請登入https://hub.docker.com/進行搜尋
2 下載完畢後分別建立/home/docker/consul、consul-server1-data、consul-server2-data、consul-server3-data、consul-client-data、consul-server1-conf、consul-server2-conf、consul-server3-conf、consul-client-conf這九個資料夾

[root@localhost ~]# cd /home

[root@localhost home]# mkdir docker

[root@localhost home]# cd docker

[root@localhost docker]# mkdir consul

[root@localhost docker]# cd consul

[root@localhost consul]# mkdir consul-server1-data consul-server2-data consul-server3-data  consul-client-data consul-server1-conf consul-server2-conf consul-server3-conf consul-client-conf

3 建立Consul配置檔案
3.1 在docker中每個Consul成員都是docker中的一個容器,docker會給每個容器分配容器的IP地址,容器IP地址只能用於容器之間內部通訊不能被宿主機直接訪問,每個Consul容器IP同時也是Consul成員的Agentd守護程式的IP地址,建立Consul叢集需要其他Consul容器加入同一個Consul容器的Agentd守護程式的IP地址,將該Consul容器作為Consul容器的leader,當該Consul容器掛掉時,Consul叢集會從所有Agentd守護程式的IP地址中再選舉出一個leader,但當宿主及重啟,docker中所有容器的IP地址都會發生變化,Consul叢集中的每個成員的IP地址也發生變化,原本是Consul容器的IP地址可能變成了Mysql容器的IP地址,這樣每個Consul成員無法自動加入原來Consul容器的Agentd守護程式的IP地址,Consul叢集就會報錯,解決方案是在所有Consul節點服務的配置檔案中,配置引數"retry_join",將docker中所有容器的IP都作為加入同一個Consul容器的Agentd守護程式的IP地址,任何一個Consul成員的Agent守護程式只需要知道叢集中任意一個節點即可,加入到叢集之後,叢集節點之間會根據GOSSIP協議互相發現彼此的關係
要先統計docker中所有容器已經被使用的IP地址,將沒有被使用的空閒的IP地址作為Consul容器Agentd守護程式的IP地址
3.1.1 查詢docker中所有容器IP地址

[root@bogon consul-server1-conf]# docker inspect -f '{{.NetworkSettings.IPAddress}}' $(docker ps -q)
172.17.0.2
172.17.0.5



172.17.0.8
172.17.0.7

3.1.2 統計出已經使用的IP地址後,將空閒的172.17.0.6、172.17.0.9、172.17.0.4、172.17.0.3這四個準備使用的IP地址,作為Consul容器的IP地址,並將所有docker容器中所有已經使用的IP地址和準備使用的IP地址寫入每個Consul節點服務的配置檔案的配置引數"retry_join"中, "retry_join": ["172.17.0.2","172.17.0.3","172.17.0.4","172.17.0.5","172.17.0.6","172.17.0.7","172.17.0.8","172.17.0.9"]
3.2 建立consul-server1節點服務配置檔案
3.2.1 進入consul-server1-conf資料夾建立consul-server1.json檔案

[root@localhost consul]# cd consul-server1-conf/
[root@localhost consul-server1-conf]# touch consul-server1.json 

3.2.2 vi編輯consul-server1.json配置檔案,複製下列程式碼

{
    "datacenter": "DC1",
    "data_dir": "/consul/data",
    "log_level": "INFO",
    "node_name": "consul-server1",
    "server": true,
    "bootstrap_expect": 1,
    "retry_join": ["172.17.0.2","172.17.0.3","172.17.0.4","172.17.0.5","172.17.0.6","172.17.0.7","172.17.0.8","172.17.0.9"],
    "retry_interval": "3s",
    "enable_debug": false,
    "rejoin_after_leave": true,
    "enable_syslog": false
}

3.3 建立consul-server2節點服務配置檔案
3.3.1 進入consul-server2-conf資料夾建立consul-server2.json檔案

[root@localhost consul]# cd consul-server2-conf/
[root@localhost consul-server2-conf]# touch consul-server2.json 

3.3.2 vi編輯consul-server2.json配置檔案,複製下列程式碼

{
    "datacenter": "DC1",
    "data_dir": "/consul/data",
    "log_level": "INFO",
    "node_name": "consul-server2",
    "server": true,
    "bootstrap_expect": 2,
    "retry_join": ["172.17.0.2","172.17.0.3","172.17.0.4","172.17.0.5","172.17.0.6","172.17.0.7","172.17.0.8","172.17.0.9"],
    "retry_interval": "3s",
    "enable_debug": false,
    "rejoin_after_leave": true,
    "enable_syslog": false
}

3.4 建立consul-server3節點服務配置檔案
3.4.1 進入consul-server3-conf資料夾建立consul-server3.json檔案

[root@localhost consul]# cd consul-server3-conf/
[root@localhost consul-server3-conf]# touch consul-server3.json 

3.4.2 vi編輯consul-server3.json配置檔案,複製下列程式碼

{
    "datacenter": "DC1",
    "data_dir": "/consul/data",
    "log_level": "INFO",
    "node_name": "consul-server3",
    "server": true,
    "bootstrap_expect": 2,
    "retry_join": ["172.17.0.2","172.17.0.3","172.17.0.4","172.17.0.5","172.17.0.6","172.17.0.7","172.17.0.8","172.17.0.9"],
    "retry_interval": "3s",
    "enable_debug": false,
    "rejoin_after_leave": true,
    "enable_syslog": false
}

3.4 建立consul-client節點服務配置檔案
3.4.1 進入consul-client-conf資料夾建立consul-client.json檔案

[root@localhost consul]# cd consul-client-conf/
[root@localhost consul-client-conf]# touch consul-client.json 

3.4.2 vi編輯consul-client.json配置檔案,複製下列程式碼

{
  "datacenter": "DC1",             
  "data_dir": "/consul/data",
  "log_level": "INFO",
  "node_name": "consul-client",
  "server": false,
  "ui": true,
  "bootstrap_expect": 0,
  "bind_addr": "192.168.43.234",
  "client_addr": "192.168.43.234",
  "retry_join": ["172.17.0.2","172.17.0.3","172.17.0.4","172.17.0.5","172.17.0.6","172.17.0.7","172.17.0.8","172.17.0.9"],
  "retry_interval": "3s", 
  "enable_debug": false,
  "rejoin_after_leave": true,
  "enable_syslog": false
}

3.5 配置引數說明
datacenter: 資料中心名稱
data_di:ConsulServer模式節點的資料目錄
log_level: "INFO":日誌級別
node_name:當前節點名稱
server:是否為 Server 模式,true 為 Server 模式,false 為 Client 模式
ui:是否開啟 UI 訪問
bootstrap_expect:啟動時期望的就緒節點,1 代表啟動為 bootstrap 模式,等待其他節點加入
bind_addr:繫結的 IP,ConsulServer模式無需指定,ConsulClient模式必須繫結宿主機IP地址,否則報錯[Consul]Error starting agent: Failed to get advertise address: Multiple private IPs found.
client_addr:作為 Client 接受請求的繫結 IP地址,該IP地址必須為宿主機IP地址,否則訪問宿主機無法訪問到Client模式的Consul節點,埠使用了 HTTP: 8500, DNS: 8600
retry_join:嘗試加入的其他節點
retry_interval:每次嘗試間隔
raft_protocol:Raft 協議版本
enable_debug:是否開啟 Debug 模式
rejoin_after_leave:允許重新加入叢集
enable_syslog:是否開啟 syslog
4 啟動三個server模式的consul節點consul-server1、consul-server2、consul-server3,啟動一個client模式的consul節點consul-client

docker run -d --name consul-server1 --restart=always -v /home/docker/consul/consul-server1-data:/consul/data -v /home/docker/consul/consul-server1-conf:/consul/config consul agent -data-dir /consul/data -config-dir /consul/config

docker run -d --name consul-server2 --restart=always -v /home/docker/consul/consul-server2-data:/consul/data -v /home/docker/consul/consul-server2-conf:/consul/config consul agent -data-dir /consul/data -config-dir /consul/config

docker run -d --name consul-server3 --restart=always -v /home/docker/consul/consul-server3-data:/consul/data -v /home/docker/consul/consul-server3-conf:/consul/config consul agent -data-dir /consul/data -config-dir /consul/config

docker run -d --net=host --name consul-client --restart=always -p 8400:8400 -p 8500:8500 -p 8600:53/udp -v /home/docker/consul/consul-client-data:/consul/data -v /home/docker/consul/consul-client-conf:/consul/config consul agent  -data-dir /consul/data -config-dir /consul/config

5 檢視consul客戶端、consul容器是否啟動

[root@localhost ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                        NAMES
e46bf7bae81d        consul              "docker-entrypoint..."   About an hour ago   Up About an hour                                                                 consul-client
954f366b5a9a        consul              "docker-entrypoint..."   About an hour ago   Up About an hour    8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server3
54feb6ee26c4        consul              "docker-entrypoint..."   About an hour ago   Up About an hour    8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server2
5beadc6c1bec        consul              "docker-entrypoint..."   About an hour ago   Up About an hour    8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server1

6 檢視ConsulServer模式、Client模式節點是否啟動成功

[root@localhost ~]# docker exec -it consul-server1 /bin/sh
/ # consul members
Node            Address              Status  Type    Build  Protocol  DC   Segment
consul-server1  172.17.0.4:8301      alive   server  1.4.0  2         dc1  <all>
consul-server2  172.17.0.9:8301      alive   server  1.4.0  2         dc1  <all>
consul-server3  172.17.0.6:8301      alive   server  1.4.0  2         dc1  <all>
consul-client   192.168.43.234:8301  alive   client  1.4.0  2         dc1  <default>

7 檢視目前全部的consul節點的角色狀態

/ # consul operator raft list-peers
Node            ID                                    Address          State     Voter  RaftProtocol
consul-server3  bce5f51e-fada-8a13-7639-e205da35efe6  172.17.0.6:8300  follower  true   3
consul-server2  0b4cbb28-b03a-948f-c4f2-a6e00b6e0d06  172.17.0.9:8300  leader    true   3
consul-server1  952d468c-0391-2f98-4959-f62965401551  172.17.0.4:8300  follower  true   3

8 consult叢集容器啟動成功,開啟瀏覽器輸入http://192.168.43.234:8500,consul預設頁面ui埠號8500

14589598-fd2f3da5b4a9a9a6.png
image.png

可以看到Node Health為3,則說明consul叢集配置成功

9 錯誤處理

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                                                        NAMES
79032d57a304        consul              "docker-entrypoint..."   3 seconds ago       Exited (1) 2 seconds ago                                                                consul-client
53ef8a6fdb56        consul              "docker-entrypoint..."   11 minutes ago      Up 11 minutes              8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server3
d1f7c98d07f5        consul              "docker-entrypoint..."   12 minutes ago      Up 12 minutes              8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server2
86e45d805eb8        consul              "docker-entrypoint..."   12 minutes ago      Up 12 minutes              8300-8302/tcp, 8500/tcp, 8301-8302/udp, 8600/tcp, 8600/udp   consul-server1

8.1 如果consul客戶端、consul服務端容器是未能正常啟動,則檢視該consul容器日誌

docker logs consulclient

9 命令說明
--net=host:指定 docker網路模式為host模式共享宿主機的網路,若採用預設的bridge模式,則會存在容器跨主機間通訊失敗的問題
-v /data/consul_data/data:/consul/data:主機的資料目錄掛載到容器的/consul/data下,因為該容器預設的資料寫入位置即是/consul/data
-v /data/consul_data/conf:/consul/config:主機的配置目錄掛載到容器的/consul/conf下,因為該容器預設的資料寫入位置即是/consul/conf
consul agent -server:consul的server啟動模式
consul agent -client:consul的client啟動模式
consul agent -bind=192.168.43.234:consul繫結到主機的ip上
consul agent -bootstrap-expect=3:server要想啟動,需要至少3個server
consul agent -data-dir /consul/data:consul的資料目錄
consul agent -config-dir /consul/config:consul的配置目錄
consul agent -join:加入的consul-server1節點IP地址建立consul叢集,啟動之後,叢集就開始了Vote(投票選Leader)的過程
–net=host docker引數, 使得docker容器越過了netnamespace的隔離,免去手動指定埠對映的步驟
-e或--env 使用-e設定的環境變數,容器內部的程式可以直接拿到
-server consul支援以server或client的模式執行, server是服務發現模組的核心, client主要用於轉發請求
-client consul繫結在哪個client地址上,這個地址提供HTTP、DNS、RPC等服務,預設是127.0.0.1,0.0.0.0 表示任何地址可以訪問
-node - 群集中此節點的名稱。這在群集中必須是唯一的。預設情況下,這是計算機的主機名
-bootstrap-expect 指定consul叢集中有多少代理
-retry-join 指定要加入的consul節點地址,失敗會重試, 可多次指定不同的地址
-bind 繫結IP地址用來在叢集內部的通訊,叢集內的所有節點到地址都必須是可達的,預設是0.0.0.0,但當宿主機重啟後所有docker容器IP地址會發生變化,-bind 繫結IP作用就會失效,叢集無法找到leader報錯,如果將叢集單獨部署在一個宿主機內可以使用
-allow_stale 設定為true, 表明可以從consul叢集的任一server節點獲取dns資訊, false則表明每次請求都會經過consul server leader
--name DOCKER容器的名稱
-ui 提供圖形化的介面
其他命令請檢視consul官方文件:https://www.consul.io/docs/agent/options.html#ports

相關文章