Consul 架构

在一个数据中心工作的领事的体系结构图可以最好地描述如下所示 :

Consul 教程 - 图1

正如我们所看到的,有三种不同的服务器,由Consul管理.工作架构通过使用筏算法工作,这有助于我们从三个不同的服务器中选出一个领导者.然后根据追随者领导者等标签标记这些服务器.顾名思义,追随者有责任遵循领导者的决定.所有这三个服务器进一步相互连接以进行任何通信. 每个服务器使用RPC的概念与其自己的客户端进行交互.由于 **Gossip Protocol** ,客户之间的沟通是可能的,如下所述.可以使用TCP或八卦通信方法提供与互联网设施的通信.此通信与三台服务器中的任何一台直接联系.

Raft算法

Raft是用于管理复制日志的一致性算法.它依赖于 **CAP定理**的原理,该原理指出在存在网络分区时,必须在一致性和可用性之间进行选择.并非CAP定理的所有三个基本原理都可以在任何给定的时间点实现.必须在最好的情况下权衡其中任何两个. A Raft群集包含多个服务器,通常是奇数计数.例如,如果我们有五台服务器,它将允许系统容忍两个故障.在任何给定时间,每个服务器都处于以下三种状态之一:领导者,追随者候选人.在正常操作中,只有一个领导者,所有其他服务器都是粉丝.这些粉丝处于被动状态,即他们自己不发出请求,只是回应领导者和候选人的请求. 下图描述了使用筏子的工作流模型算法工作 :

Consul 教程 - 图2

键值数据

自领事版本0.7.1以来,已经引入了单独的键值数据. KV命令用于通过命令行与Consul的键值存储进行交互.它公开了商店中插入,更新,阅读删除的顶级命令.为了获得Key/Value对象存储,我们为consul客户端调用KV方法 :
  1. kv:= consul.KV()

KVPair结构用于表示单个键/值条目.我们可以在以下程序中查看Consul KV Pair的结构.

  1. type KVPair struct {
  2. Key string
  3. CreateIndex uint64
  4. ModifyIndex uint64
  5. LockIndex uint64
  6. Flags uint64
  7. Value []byte
  8. Session string
  9. }
这里,上面代码中提到的各种结构可以定义如下 :
  • : 它是一个斜杠URL名称.例如 - sites/1/domain.
  • CreateIndex** **: 首次创建密钥时分配的索引号.
  • ModifyIndex** **: 上次更新密钥时分配的索引号.
  • LockIndex** **: 在键/值条目上获得新锁时创建的索引号
  • 标志 : 应用程序可以使用它来设置自定义值.
  • : 它是一个最大512kb的字节数组.
  • 会话 : 它可以在创建会话对象后设置.

协议类型

有两个Consul中的协议类型,称为 :
  • 共识协议和
  • 八卦协议
现在让我们详细了解它们.

共识协议

Consul使用共识协议来提供CAP定理所描述的一致性.该协议基于Raft算法.在实施共识协议时,使用筏算法,其中筏节点始终处于以下三种状态中的任何一种:跟随者,候选者或领导者.

Gossip Protocol

八卦协议可用于管理成员资格,在群集中发送和接收消息.在领事中,八卦协议的使用以两种方式发生, **WAN** (无线区域网络)和 **LAN** (局域网).有三个已知的库,可以实现一个Gossip算法来发现对等网络中的节点 :
  • teknek-gossip** **: 它适用于UDP,用Java编写.
  • gossip-python** **: 它利用TCP堆栈,也可以通过构建的网络共享数据.
  • Smudge** **: 它是用Go编写的,并使用UDP来交换状态信息.
Gossip协议也被用于实现和维护分布式数据库的一致性或者处于一致状态的其他类型的数据,计算未知大小的网络中的节点数量,稳健地传播新闻,组织节点等.

远程过程调用

RPC可以表示为远程过程调用的简写形式.它是一个程序用来从另一个程序请求服务的协议.该协议可以位于网络上的另一台计算机上,而无需确认网络详细信息. 在Consul中使用RPC的真正好处在于,它可以帮助我们避免大多数延迟问题发现服务工具确实有一段时间了.在RPC之前,Consul过去只有 TCP 基于UDP 的连接,这对大多数系统都很好,但对于分布式系统则不行. RPC通过减少从一个地方到另一个地方的分组信息传输的时间段来解决这些问题.在这方面,谷歌的 GRPC 是一个很好的工具,如果有人希望观察基准并比较性能.

一、什么是服务发现

微服务的框架体系中,服务发现是不能不提的一个模块。我相信了解或者熟悉微服务的童鞋应该都知道它的重要性。这里我只是简单的提一下,毕竟这不是我们的重点。我们看下面的一幅图片:

Consul 教程 - 图3

图中,客户端的一个接口,需要调用服务A-N。客户端必须要知道所有服务的网络位置的,以往的做法是配置是配置文件中,或者有些配置在数据库中。这里就带出几个问题:
  • 需要配置N个服务的网络位置,加大配置的复杂性
  • 服务的网络位置变化,都需要改变每个调用者的配置
  • 集群的情况下,难以做负载(反向代理的方式除外)

总结起来一句话:服务多了,配置很麻烦,问题多多

既然有这些问题,那么服务发现就是解决这些问题的。话说,怎么解决呢?我们再看一张图

Consul 教程 - 图4

与之前一张不同的是,加了个服务发现模块。图比较简单,这边文字描述下。服务A-N把当前自己的网络位置注册到服务发现模块(这里注册的意思就是告诉),服务发现就以K-V的方式记录下,K一般是服务名,V就是IP:PORT。服务发现模块定时的轮询查看这些服务能不能访问的了(这就是健康检查)。客户端在调用服务A-N的时候,就跑去服务发现模块问下它们的网络位置,然后再调用它们的服务。这样的方式是不是就可以解决上面的问题了呢?客户端完全不需要记录这些服务网络位置,客户端和服务端完全解耦! 这个过程大体是这样,当然服务发现模块没这么简单。里面包含的东西还很多。这样表述只是方便理解。 图中的服务发现模块基本上就是微服务架构中服务发现的作用了。

二、consul 简介

做服务发现的框架常用的有 zookeeper eureka etcd consul 这里就不比较哪个好哪个差了,需要的童鞋自己谷歌百度。 那么consul是啥?consul就是提供服务发现的工具。然后下面是简单的介绍: consul是分布式的、高可用、横向扩展的。consul提供的一些关键特性: service discovery:consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册。 health checking:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。 key/value storage:一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。 multi-datacenter:无需复杂的配置,即可支持任意数量的区域。 我们这里会介绍服务发现,健康检查,还有一些基本KV存储。多数据中心有机会另一篇文章再说。 总结:只要知道它是解决我上一部分提出的问题就行,其它的东西慢慢理解

三、consul的几个概念

Consul 教程 - 图5

上图来自于consul官方文档 我们只看数据中心1,可以看出consul的集群是由N个SERVER,加上M个CLIENT组成的。而不管是SERVER还是CLIENT,都是consul的一个节点,所有的服务都可以注册到这些节点上,正是通过这些节点实现服务注册信息的共享。除了这两个,还有一些小细节,一一简单介绍。 CLIENT CLIENT表示consul的client模式,就是客户端模式。是consul节点的一种模式,这种模式下,所有注册到当前节点的服务会被转发到SERVER,本身是不持久化这些信息。 SERVER SERVER表示consul的server模式,表明这个consul是个server,这种模式下,功能和CLIENT都一样,唯一不同的是,它会把所有的信息持久化的本地,这样遇到故障,信息是可以被保留的。 SERVER-LEADER 中间那个SERVER下面有LEADER的字眼,表明这个SERVER是它们的老大,它和其它SERVER不一样的一点是,它需要负责同步注册的信息给其它的SERVER,同时也要负责各个节点的健康监测。 其它信息其它信息包括它们之间的通信方式,还有一些协议信息,算法。它们是用于保证节点之间的数据同步,实时性要求等等一系列集群问题的解决。这些有兴趣的自己看看官方文档

四、安装 Consul

Consul 下载地址:https://www.consul.io/downloads.html,下载后解压就是一个可执行的二进制文件consul,配置好环境变量,检查 consul 是否可用:
  1. [root@localhost ~]# consul
  2. Usage: consul [--version] [--help] <command> [<args>]
  3. Available commands are:
  4. agent Runs a Consul agent
  5. catalog Interact with the catalog
  6. event Fire a new event
  7. exec Executes a command on Consul nodes
  8. force-leave Forces a member of the cluster to enter the "left" state
  9. info Provides debugging information for operators.
  10. join Tell Consul agent to join cluster
  11. keygen Generates a new encryption key
  12. keyring Manages gossip layer encryption keys
  13. kv Interact with the key-value store
  14. leave Gracefully leaves the Consul cluster and shuts down
  15. lock Execute a command holding a lock
  16. maint Controls node or service maintenance mode
  17. members Lists the members of a Consul cluster
  18. monitor Stream logs from a Consul agent
  19. operator Provides cluster-level tools for Consul operators
  20. reload Triggers the agent to reload configuration files
  21. rtt Estimates network round trip time between nodes
  22. snapshot Saves, restores and inspects snapshots of Consul server state
  23. validate Validate config files/directories
  24. version Prints the Consul version
  25. watch Watch for changes in Consul
如果出现上面这样代表consul是没问题的。

五、运行 Consul Agent

Consul安装之后,代理必须运行。 代理可以在服务器或客户端模式下运行。 每个数据中心都必须至少有一台服务器,但推荐使用3台或5台服务器。 一个单一的服务器部署是非常不推荐的,因为在故障情况下数据丢失是不可避免的。 所有其他代理以客户端模式运行。 客户端是一个非常轻量级的进程,它注册服务,运行健康检查,并将查询转发给服务器。 代理程序必须在集群中的每个节点上运行。 为了简单起见,我们现在将以开发模式启动Consul代理。 这种模式对于快速简单地启动单节点Consul环境非常有用。 它并不打算在生产中使用,因为它不会持续任何状态。
  1. [root@localhost consul]# consul agent -dev
  2. ==> Starting Consul agent...
  3. ==> Consul agent running!
  4. Version: 'v1.0.1'
  5. Node ID: '590309a6-71f6-6145-fe40-d2c5e203687f'
  6. Node name: 'localhost.localdomain'
  7. Datacenter: 'dc1' (Segment: '<all>')
  8. Server: true (Bootstrap: false)
  9. Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, DNS: 8600)
  10. Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
  11. Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false
  12. ==> Log data will now stream in as it occurs:
  13. 2017/11/25 15:15:54 [DEBUG] Using random ID "590309a6-71f6-6145-fe40-d2c5e203687f" as node ID
  14. 2017/11/25 15:15:54 [INFO] raft: Initial configuration (index=1): [{Suffrage:Voter ID:590309a6-71f6-6145-fe40-d2c5e203687f Address:127.0.0.1:8300}]
  15. 2017/11/25 15:15:54 [INFO] serf: EventMemberJoin: localhost.localdomain.dc1 127.0.0.1
  16. 2017/11/25 15:15:54 [INFO] serf: EventMemberJoin: localhost.localdomain 127.0.0.1
  17. 2017/11/25 15:15:54 [INFO] agent: Started DNS server 127.0.0.1:8600 (udp)
  18. 2017/11/25 15:15:54 [INFO] raft: Node at 127.0.0.1:8300 [Follower] entering Follower state (Leader: "")
  19. 2017/11/25 15:15:54 [INFO] consul: Adding LAN server localhost.localdomain (Addr: tcp/127.0.0.1:8300) (DC: dc1)
  20. 2017/11/25 15:15:54 [INFO] consul: Handled member-join event for server "localhost.localdomain.dc1" in area "wan"
  21. 2017/11/25 15:15:54 [INFO] agent: Started DNS server 127.0.0.1:8600 (tcp)
  22. 2017/11/25 15:15:54 [INFO] agent: Started HTTP server on 127.0.0.1:8500 (tcp)
  23. 2017/11/25 15:15:54 [INFO] agent: started state syncer
  24. 2017/11/25 15:15:54 [WARN] raft: Heartbeat timeout from "" reached, starting election
  25. 2017/11/25 15:15:54 [INFO] raft: Node at 127.0.0.1:8300 [Candidate] entering Candidate state in term 2
  26. 2017/11/25 15:15:54 [DEBUG] raft: Votes needed: 1
  27. 2017/11/25 15:15:54 [DEBUG] raft: Vote granted from 590309a6-71f6-6145-fe40-d2c5e203687f in term 2. Tally: 1
  28. 2017/11/25 15:15:54 [INFO] raft: Election won. Tally: 1
  29. 2017/11/25 15:15:54 [INFO] raft: Node at 127.0.0.1:8300 [Leader] entering Leader state
  30. 2017/11/25 15:15:54 [INFO] consul: cluster leadership acquired
  31. 2017/11/25 15:15:54 [DEBUG] consul: Skipping self join check for "localhost.localdomain" since the cluster is too small
  32. 2017/11/25 15:15:54 [INFO] consul: member 'localhost.localdomain' joined, marking health alive
  33. 2017/11/25 15:15:54 [INFO] consul: New leader elected: localhost.localdomain
  34. 2017/11/25 15:15:54 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically
  35. 2017/11/25 15:15:54 [INFO] agent: Synced node info
  36. 2017/11/25 15:15:54 [DEBUG] agent: Node info in sync
  37. 2017/11/25 15:15:57 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically
  38. 2017/11/25 15:15:57 [DEBUG] agent: Node info in sync
  39. 2017/11/25 15:16:54 [DEBUG] consul: Skipping self join check for "localhost.localdomain" since the cluster is too small
  40. 2017/11/25 15:17:51 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically
  41. 2017/11/25 15:17:51 [DEBUG] agent: Node info in sync
  42. 2017/11/25 15:17:54 [DEBUG] manager: Rebalanced 1 servers, next active server is localhost.localdomain.dc1 (Addr: tcp/127.0.0.1:8300) (DC: dc1)
  43. 2017/11/25 15:17:54 [DEBUG] consul: Skipping self join check for "localhost.localdomain" since the cluster is too small
如您所见,Consul代理已经启动并输出了一些日志数据。 从日志数据中,您可以看到我们的代理正在服务器模式下运行,并声称拥有集群领导权。 此外,当地成员已被标记为该集群的健康成员。

六、集群成员

在另一个终端运行consul members,可以看到Consul集群的成员。 应该只看到一个成员(你自己):
  1. [root@localhost ~]# consul members
  2. Node Address Status Type Build Protocol DC Segment
  3. localhost.localdomain 127.0.0.1:8301 alive server 1.0.1 2 dc1 <all>
输出显示了我们自己的节点,它正在运行的地址,运行状况,在集群中的角色以及一些版本信息。 额外的元数据可以通过提供-detailed标志来查看。
  1. [root@localhost ~]# consul members -detailed
  2. Node Address Status Tags
  3. localhost.localdomain 127.0.0.1:8301 alive build=1.0.1:9564c29,dc=dc1,id=590309a6-71f6-6145-fe40-d2c5e203687f,port=8300,raft_vsn=3,role=consul,segment=<all>,vsn=2,vsn_max=3,vsn_min=2,wan_join_port=8302
members命令的输出基于gossip协议,并最终一致。 也就是说,在任何时候,当地代理所看到的可能与服务器上的状态不完全一致。 要获得完全一致,请使用HTTP API再将HTTP请求转发给Consul服务器:
  1. [root@localhost ~]# curl localhost:8500/v1/catalog/nodes
  2. [
  3. {
  4. "ID": "590309a6-71f6-6145-fe40-d2c5e203687f",
  5. "Node": "localhost.localdomain",
  6. "Address": "127.0.0.1",
  7. "Datacenter": "dc1",
  8. "TaggedAddresses": {
  9. "lan": "127.0.0.1",
  10. "wan": "127.0.0.1"
  11. },
  12. "Meta": {
  13. "consul-network-segment": ""
  14. },
  15. "CreateIndex": 5,
  16. "ModifyIndex": 6
  17. }
  18. ]
除了HTTP API之外,还可以使用DNS接口查询节点。 请注意,必须确保将DNS查找默认情况下指向在端口8600上运行的Consul代理的DNS服务器。 DNS条目的格式(如“Armons-MacBook-Air.node.consul”)将在后面详细介绍。
  1. [root@localhost ~]# dig @127.0.0.1 -p 8600 localhost.localdomain.node.consul
  2. '
  3. ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 localhost.localdomain.node.consul
  4. ; (1 server found)
  5. ;; global options: +cmd
  6. ;; Got answer:
  7. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43915
  8. ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
  9. ;; WARNING: recursion requested but not available
  10. ;; OPT PSEUDOSECTION:
  11. ; EDNS: version: 0, flags:; udp: 4096
  12. ;; QUESTION SECTION:
  13. ;localhost.localdomain.node.consul. IN A
  14. ;; ANSWER SECTION:
  15. localhost.localdomain.node.consul. 0 IN A 127.0.0.1
  16. ;; Query time: 0 msec
  17. ;; SERVER: 127.0.0.1#8600(127.0.0.1)
  18. ;; WHEN: 六 11月 25 15:39:49 CST 2017
  19. ;; MSG SIZE rcvd: 78

七、停止 Agent

可以使用Ctrl-C(中断信号)正常停止代理。 中断代理之后,您应该看到它离开集群并关闭。 通过优雅地离开,Consul通知其他集群成员该节点离开。 如果强行杀死了代理进程,则集群的其他成员将检测到该节点失败。 成员离开时,其服务和检查将从目录中删除。 当一个成员失败时,其健康被简单地标记为关键,但不会从目录中删除。 Consul将自动尝试重新连接到失败的节点,使其能够从特定的网络条件恢复,而不再联系离开的节点。 此外,如果代理正在作为服务器运行,那么优雅的离开对于避免造成影响一致协议的潜在可用性中断很重要。 有关如何安全地添加和删除服务器的详细信息,请参阅指南部分。

八、注册服务

1、服务定义 服务可以通过提供服务定义或通过对HTTP API进行适当的调用来注册。 服务定义是注册服务最常用的方式,所以我们将在这一步中使用这种方法。 我们将建立在上一步中介绍的代理配置。 首先,为Consul配置创建一个目录。 Consul将所有配置文件加载到配置目录中,因此Unix系统上的一个通用约定是将目录命名为/etc/consul.d(.d后缀意味着“该目录包含一组配置文件”)。
  1. [root@localhost etc]# sudo mkdir /etc/consul.d
接下来,我们将编写一个服务定义配置文件。 假设我们有一个名为“web”的服务在端口80上运行。另外,我们给它一个标签,我们可以使用它作为查询服务的附加方式:
  1. [root@localhost ~]# echo '{"service": {"name": "web", "tags": ["rails"], "port": 80}}' | sudo tee /etc/consul.d/web.json
现在,重新启动代理程序,提供配置目录:
  1. [root@localhost ~]# consul agent -dev -config-dir=/etc/consul.d
  2. ==> Starting Consul agent...
  3. ==> Consul agent running!
  4. Version: 'v1.0.1'
  5. Node ID: '94236f1c-2a29-85c5-b235-dd916485be5b'
  6. Node name: 'localhost.localdomain'
  7. Datacenter: 'dc1' (Segment: '<all>')
  8. Server: true (Bootstrap: false)
  9. Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, DNS: 8600)
  10. Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
  11. Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false
  12. ==> Log data will now stream in as it occurs:
  13. 2017/11/25 16:16:51 [DEBUG] Using random ID "94236f1c-2a29-85c5-b235-dd916485be5b" as node ID
  14. 2017/11/25 16:16:51 [INFO] raft: Initial configuration (index=1): [{Suffrage:Voter ID:94236f1c-2a29-85c5-b235-dd916485be5b Address:127.0.0.1:8300}]
  15. 2017/11/25 16:16:51 [INFO] serf: EventMemberJoin: localhost.localdomain.dc1 127.0.0.1
  16. 2017/11/25 16:16:51 [INFO] serf: EventMemberJoin: localhost.localdomain 127.0.0.1
  17. 2017/11/25 16:16:51 [INFO] agent: Started DNS server 127.0.0.1:8600 (udp)
  18. 2017/11/25 16:16:51 [INFO] raft: Node at 127.0.0.1:8300 [Follower] entering Follower state (Leader: "")
  19. 2017/11/25 16:16:51 [INFO] consul: Adding LAN server localhost.localdomain (Addr: tcp/127.0.0.1:8300) (DC: dc1)
  20. 2017/11/25 16:16:51 [INFO] consul: Handled member-join event for server "localhost.localdomain.dc1" in area "wan"
  21. 2017/11/25 16:16:51 [INFO] agent: Started DNS server 127.0.0.1:8600 (tcp)
  22. 2017/11/25 16:16:51 [INFO] agent: Started HTTP server on 127.0.0.1:8500 (tcp)
  23. 2017/11/25 16:16:51 [INFO] agent: started state syncer
  24. 2017/11/25 16:16:52 [WARN] raft: Heartbeat timeout from "" reached, starting election
  25. 2017/11/25 16:16:52 [INFO] raft: Node at 127.0.0.1:8300 [Candidate] entering Candidate state in term 2
  26. 2017/11/25 16:16:52 [DEBUG] raft: Votes needed: 1
  27. 2017/11/25 16:16:52 [DEBUG] raft: Vote granted from 94236f1c-2a29-85c5-b235-dd916485be5b in term 2. Tally: 1
  28. 2017/11/25 16:16:52 [INFO] raft: Election won. Tally: 1
  29. 2017/11/25 16:16:52 [INFO] raft: Node at 127.0.0.1:8300 [Leader] entering Leader state
  30. 2017/11/25 16:16:52 [INFO] consul: cluster leadership acquired
  31. 2017/11/25 16:16:52 [DEBUG] consul: Skipping self join check for "localhost.localdomain" since the cluster is too small
  32. 2017/11/25 16:16:52 [INFO] consul: member 'localhost.localdomain' joined, marking health alive
  33. 2017/11/25 16:16:52 [INFO] consul: New leader elected: localhost.localdomain
  34. 2017/11/25 16:16:52 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically
  35. 2017/11/25 16:16:52 [INFO] agent: Synced service "web"
  36. 2017/11/25 16:16:52 [DEBUG] agent: Node info in sync
  37. 2017/11/25 16:16:52 [DEBUG] agent: Service "web" in sync
  38. 2017/11/25 16:16:52 [DEBUG] agent: Node info in sync
  39. 2017/11/25 16:16:52 [DEBUG] Skipping remote check "serfHealth" since it is managed automatically
  40. 2017/11/25 16:16:52 [DEBUG] agent: Service "web" in sync
  41. 2017/11/25 16:16:52 [DEBUG] agent: Node info in sync
您会注意到它在输出中“同步”了Web服务。 这意味着代理程序从配置文件加载了服务定义,并已成功将其注册到服务目录中。 如果您想注册多个服务,您可以在Consul配置目录中创建多个服务定义文件。 2、查询服务 一旦代理启动并且服务同步,我们可以使用DNS或HTTP API来查询服务。 DNS API 我们首先使用DNS API来查询我们的服务。 对于DNS API,服务的DNS名称是NAME.service.consul。 默认情况下,所有DNS名称始终在consul命名空间中,尽管这是可配置的。 服务子域告诉Consul我们正在查询服务,NAME是服务的名称。 对于我们注册的Web服务,这些约定和设置会生成web.service.consul的完全限定的域名:
  1. [root@localhost ~]# dig @127.0.0.1 -p 8600 web.service.consul
  2. ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 web.service.consul
  3. ; (1 server found)
  4. ;; global options: +cmd
  5. ;; Got answer:
  6. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58483
  7. ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
  8. ;; WARNING: recursion requested but not available
  9. ;; OPT PSEUDOSECTION:
  10. ; EDNS: version: 0, flags:; udp: 4096
  11. ;; QUESTION SECTION:
  12. ;web.service.consul. IN A
  13. ;; ANSWER SECTION:
  14. web.service.consul. 0 IN A 127.0.0.1
  15. ;; Query time: 0 msec
  16. ;; SERVER: 127.0.0.1#8600(127.0.0.1)
  17. ;; WHEN: 11 25 16:22:29 CST 2017
  18. ;; MSG SIZE rcvd: 63
正如你所看到的,一个A记录返回了服务可用的节点的IP地址。 A记录只能保存IP地址。 您也可以使用DNS API来检索整个地址/端口对作为SRV记录:
  1. [root@localhost ~]# dig @127.0.0.1 -p 8600 web.service.consul SRV
  2. ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 web.service.consul SRV
  3. ; (1 server found)
  4. ;; global options: +cmd
  5. ;; Got answer:
  6. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65288
  7. ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 3
  8. ;; WARNING: recursion requested but not available
  9. ;; OPT PSEUDOSECTION:
  10. ; EDNS: version: 0, flags:; udp: 4096
  11. ;; QUESTION SECTION:
  12. ;web.service.consul. IN SRV
  13. ;; ANSWER SECTION:
  14. web.service.consul. 0 IN SRV 1 1 80 localhost.localdomain.node.dc1.consul.
  15. ;; ADDITIONAL SECTION:
  16. localhost.localdomain.node.dc1.consul. 0 IN A 127.0.0.1
  17. localhost.localdomain.node.dc1.consul. 0 IN TXT "consul-network-segment="
  18. ;; Query time: 0 msec
  19. ;; SERVER: 127.0.0.1#8600(127.0.0.1)
  20. ;; WHEN: 11 25 16:25:21 CST 2017
  21. ;; MSG SIZE rcvd: 156
SRV记录表示Web服务正在端口80上运行,并且存在于节点localhost.localdomain.node.dc1.consul.上。DNS使用该记录的A记录返回附加部分。 最后,我们也可以使用DNS API来按标签过滤服务。 基于标记的服务查询的格式是TAG.NAME.service.consul。 在下面的例子中,我们向Consul询问所有带有“rails”标签的web服务。 自从我们使用该标签注册我们的服务后,我们得到了成功的回应:
  1. [root@localhost ~]# dig @127.0.0.1 -p 8600 rails.web.service.consul
  2. ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 rails.web.service.consul
  3. ; (1 server found)
  4. ;; global options: +cmd
  5. ;; Got answer:
  6. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41016
  7. ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
  8. ;; WARNING: recursion requested but not available
  9. ;; OPT PSEUDOSECTION:
  10. ; EDNS: version: 0, flags:; udp: 4096
  11. ;; QUESTION SECTION:
  12. ;rails.web.service.consul. IN A
  13. ;; ANSWER SECTION:
  14. rails.web.service.consul. 0 IN A 127.0.0.1
  15. ;; Query time: 0 msec
  16. ;; SERVER: 127.0.0.1#8600(127.0.0.1)
  17. ;; WHEN: 11 25 16:29:10 CST 2017
  18. ;; MSG SIZE rcvd: 69
HTTP API 除了DNS API之外,HTTP API还可以用来查询服务:
  1. [root@localhost ~]# curl http://localhost:8500/v1/catalog/service/web
  2. [
  3. {
  4. "ID": "94236f1c-2a29-85c5-b235-dd916485be5b",
  5. "Node": "localhost.localdomain",
  6. "Address": "127.0.0.1",
  7. "Datacenter": "dc1",
  8. "TaggedAddresses": {
  9. "lan": "127.0.0.1",
  10. "wan": "127.0.0.1"
  11. },
  12. "NodeMeta": {
  13. "consul-network-segment": ""
  14. },
  15. "ServiceID": "web",
  16. "ServiceName": "web",
  17. "ServiceTags": [
  18. "rails"
  19. ],
  20. "ServiceAddress": "",
  21. "ServicePort": 80,
  22. "ServiceEnableTagOverride": false,
  23. "CreateIndex": 6,
  24. "ModifyIndex": 6
  25. }
  26. ]
目录API提供了托管给定服务的所有节点。 正如我们稍后将看到的健康检查一样,您通常只需要查询检查通过的健康实例。 这是DNS正在做的事情。 这是一个查询只查找健康的实例:
  1. [root@localhost ~]# curl 'http://localhost:8500/v1/health/service/web?passing'
  2. [
  3. {
  4. "Node": {
  5. "ID": "94236f1c-2a29-85c5-b235-dd916485be5b",
  6. "Node": "localhost.localdomain",
  7. "Address": "127.0.0.1",
  8. "Datacenter": "dc1",
  9. "TaggedAddresses": {
  10. "lan": "127.0.0.1",
  11. "wan": "127.0.0.1"
  12. },
  13. "Meta": {
  14. "consul-network-segment": ""
  15. },
  16. "CreateIndex": 5,
  17. "ModifyIndex": 6
  18. },
  19. "Service": {
  20. "ID": "web",
  21. "Service": "web",
  22. "Tags": [
  23. "rails"
  24. ],
  25. "Address": "",
  26. "Port": 80,
  27. "EnableTagOverride": false,
  28. "CreateIndex": 6,
  29. "ModifyIndex": 6
  30. },
  31. "Checks": [
  32. {
  33. "Node": "localhost.localdomain",
  34. "CheckID": "serfHealth",
  35. "Name": "Serf Health Status",
  36. "Status": "passing",
  37. "Notes": "",
  38. "Output": "Agent alive and reachable",
  39. "ServiceID": "",
  40. "ServiceName": "",
  41. "ServiceTags": [],
  42. "Definition": {},
  43. "CreateIndex": 5,
  44. "ModifyIndex": 5
  45. }
  46. ]
  47. }
  48. ]
3、更新服务 服务定义可以通过更改配置文件并向代理发送SIGHUP来更新。 这使您可以更新服务,而不会出现任何停机或无法提供服务查询的情况。 或者,可以使用HTTP API动态地添加,删除和修改服务。

九、Consul 集群

我们已经开始了我们的第一个代理,并注册和查询该代理的服务。 这显示了使用Consul是多么的容易,但并没有表明如何将其扩展到可扩展的生产级服务发现基础设施。 在这一步中,我们将创建我们的第一个真正的集群与多个成员。 当一个Consul代理启动时,它不知道任何其他节点:它是一个孤立的集群。 要了解其他集群成员,代理必须加入现有集群。 要加入现有的集群,只需要知道一个现有的成员。 代理加入后,会与该成员通讯,并迅速发现集群中的其他成员。 Consul代理可以加入任何其他代理,而不仅仅是服务器模式下的代理。 1、启动代理 在我们之前的例子中,我们使用了-dev标志来快速设置一个开发服务器。 但是,这不足以在集群环境中使用。 我们将从这里省略-dev标志,而是指定我们的集群标志。 集群中的每个节点都必须具有唯一的名称。 默认情况下,Consul使用机器的主机名,但我们将使用-node命令行选项手动覆盖它。 我们还将指定一个-bind:这是Consul侦听的地址,它必须可以被集群中的所有其他节点访问。 虽然绑定地址不是绝对必要的,但最好提供一个。 Consul将默认尝试侦听系统上的所有IPv4接口,但如果找到多个私有IP,将无法启动错误。 由于生产服务器通常具有多个接口,因此指定一个绑定地址可确保您永远不会将Consul绑定到错误的接口。 第一个节点将作为我们在这个集群中唯一的服务器,我们用-server来指明这一点。 -bootstrap-expect选项向Consul服务器提示我们期望加入的其他服务器节点的数量。 此选项的用途是延迟复制日志的引导,直到预期数量的服务器成功加入。 我们已经将-enable_script_checks选项设置为true,以启用可以执行外部脚本的运行状况检查。 这将在后面的例子中使用。 对于生产用途,您希望将ACL配置为与此配合使用,以控制注册任意脚本的能力。 最后,我们添加-config-dir选项,标记可以找到服务和检查定义的位置。 总而言之,这些设置产生一个这样的consul代理命令:
  1. [root@localhost ~]# consul agent -server -bootstrap-expect=1 -data-dir=/tmp/consul -node=agent-one -bind=192.168.100.101 -enable-script-checks=true -config-dir=/etc/consul.d
现在,在另一个终端中,我们将连接到第二个节点。 这次,我们将-bind设置为第二个节点的IP,并将-node设置为agent-two。 由于这个节点不会是Consul服务器,所以我们不提供-server。 总而言之,这些设置产生一个这样的consul代理命令:
  1. [root@localhost ~]# consul agent -data-dir=/tmp/consul -node=agent-two -bind=192.168.100.102 -enable-script-checks=true -config-dir=/etc/consul.d
此时,您有两个Consul代理正在运行:一个服务器和一个客户端。 两个Consul代理人对彼此还是一无所知,都是他们自己的单节点集群的一部分。 您可以通过对每个代理运行consul members来验证这一点,并注意到每个代理只能看到一个成员。 2、加入集群 现在,我们将通过在新终端中运行以下命令来告诉第一个代理加入第二个代理:
  1. [root@localhost ~]# consul join 192.168.100.101
  2. Successfully joined cluster by contacting 1 nodes.
如果在虚拟机里面运行上面的命令提示下面的失败的话,在每台虚拟机上执行下这个命令:
  1. [root@localhost ~]# consul join 192.168.100.101
  2. Error joining address '192.168.100.101': Unexpected response code: 500 (1 error(s) occurred:
  3. * Failed to join 192.168.100.101: dial tcp 192.168.100.101:8301: getsockopt: no route to host)
  4. Failed to join any nodes.
  5. [root@localhost ~]# sudo iptables -F
您应该在每个代理日志中看到一些日志输出。 如果仔细阅读,您会看到他们收到了加入信息。 如果你对每个代理执行consul members,你会看到两个代理人现在彼此了解:
  1. [root@localhost ~]# consul members
  2. Node Address Status Type Build Protocol DC Segment
  3. agent-one 192.168.100.101:8301 alive server 1.0.1 2 dc1 <all>
  4. agent-two 192.168.100.102:8301 alive client 1.0.1 2 dc1 <default>
记住:要加入集群,Consul代理只需要了解一个现有的成员。 加入集群后,代理人互相传播完整的会员信息。 3、在启动时自动加入集群 理想情况下,每当新节点出现在您的数据中心时,它就会自动加入Consul集群,无需人工干预。 Consul通过启用AWS,Google Cloud或Azure中的实例的自动发现功能,使用给定的标签 key/value来促进自动加入。 要使用集成,请将retry_join_ec2retry_join_gceretry_join_azure嵌套对象添加到您的Consul配置文件。 这将允许新的节点加入集群,而不需要任何硬编码的配置。 或者,您可以在启动时使用-join选项或start_join设置以及其他已知Consul代理的硬编码地址加入集群。 4、查询节点 就像查询服务一样,Consul也有查询节点的API。 您可以通过DNS或HTTP API执行此操作。 对于DNS API,名称的结构是NAME.node.consul或NAME.node.DATACENTER.consul。 如果数据中心被省略,Consul将仅搜索本地数据中心。 例如,从“agent-one”中,我们可以查询节点“agent-two”的地址:
  1. [root@localhost etc]# dig @127.0.0.1 -p 8600 agent-two.node.consul
  2. ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 agent-two.node.consul
  3. ; (1 server found)
  4. ;; global options: +cmd
  5. ;; Got answer:
  6. ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57127
  7. ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
  8. ;; WARNING: recursion requested but not available
  9. ;; OPT PSEUDOSECTION:
  10. ; EDNS: version: 0, flags:; udp: 4096
  11. ;; QUESTION SECTION:
  12. ;agent-two.node.consul. IN A
  13. ;; ANSWER SECTION:
  14. agent-two.node.consul. 0 IN A 192.168.100.102
  15. ;; Query time: 0 msec
  16. ;; SERVER: 127.0.0.1#8600(127.0.0.1)
  17. ;; WHEN: 11 25 17:31:29 CST 2017
  18. ;; MSG SIZE rcvd: 66
除了服务之外,查找节点的能力对于系统管理任务来说是非常有用的。 例如,知道要通过SSH连接的节点的地址与将节点作为Consul集群的一部分并查询它一样简单。 5、离开集群 要离开集群,可以正常退出代理(使用Ctrl-C)或强制终止其中一个代理。 优雅地离开允许节点转换到离开状态; 否则,其他节点将检测到它失败。

十、健康检查

现在我们已经看到了运行Consul,添加节点和服务以及查询这些节点和服务的简单性。 在本节中,我们将介绍为节点和服务添加健康检查。 健康检查是服务发现的关键组件,可以防止使用不健康的服务。 此步骤建立在之前创建的Consul集群上。 此时,您应该运行一个双节点集群。 1、检查定义 与服务类似,可以通过提供检查定义或通过对HTTP API进行适当的调用来注册检查。 我们将使用检查定义方法,因为就像服务一样,定义是设置检查最常用的方法。 在第二个节点的Consul配置目录中创建两个定义文件:
  1. [root@localhost ~]# echo '{"check": {"name": "ping", "script": "ping -c1 google.com >/dev/null", "interval": "30s"}}' >/etc/consul.d/ping.json
  2. [root@localhost ~]# echo '{"service": {"name": "web", "tags": ["rails"], "port": 80, "check": {"script": "curl localhost >/dev/null 2>&1", "interval": "10s"}}}' >/etc/consul.d/web.json
第一个定义添加了一个名为“ping”的主机级别的检查。 此检查运行间隔30秒,调用ping -c1 google.com。 在基于脚本的运行状况检查上,检查以与启动Consul进程相同的用户身份运行。 如果该命令以非零退出码退出,则该节点将被标记为不健康。 这是任何基于脚本的健康检查的约定。 第二个命令修改名为web的服务,添加一个检查,每隔10秒通过curl发送一个请求,以验证Web服务器是否可访问。 与主机级运行状况检查一样,如果脚本以非零退出代码退出,服务将被标记为不健康。 现在,重新启动第二个代理,用consul reload加载它,或者发送一个SIGHUP信号。 您应该看到以下日志行:
  1. [root@localhost ~]# consul reload
  2. Configuration reload triggered
  3. 2017/11/26 10:47:41 [INFO] Reloading configuration...
  4. 2017/11/26 10:47:41 [WARN] agent: check "service:web" has the 'script' field, which has been deprecated and replaced with the 'args' field. See https://www.consul.io/docs/agent/checks.html
  5. 2017/11/26 10:47:41 [WARN] agent: check "service:web" has the 'script' field, which has been deprecated and replaced with the 'args' field. See https://www.consul.io/docs/agent/checks.html
  6. 2017/11/26 10:47:41 [WARN] agent: check "ping" has the 'script' field, which has been deprecated and replaced with the 'args' field. See https://www.consul.io/docs/agent/checks.html
  7. 2017/11/26 10:47:41 [WARN] agent: check "ping" has the 'script' field, which has been deprecated and replaced with the 'args' field. See https://www.consul.io/docs/agent/checks.html
  8. 2017/11/26 10:47:41 [INFO] agent: Synced service "web"
  9. 2017/11/26 10:47:41 [INFO] agent: Synced check "ping"
  10. 2017/11/26 10:47:47 [WARN] agent: Check "service:web" is now critical
  11. 2017/11/26 10:47:57 [WARN] agent: Check "service:web" is now critical
  12. 2017/11/26 10:48:04 [WARN] agent: Check "ping" is now warning
  13. 2017/11/26 10:48:04 [INFO] agent: Synced check "ping"
  14. 2017/11/26 10:48:07 [WARN] agent: Check "service:web" is now critical
  15. 2017/11/26 10:48:17 [WARN] agent: Check "service:web" is now critical
  16. 2017/11/26 10:48:27 [WARN] agent: Check "service:web" is now critical
前几行表示代理已经同步了新的定义。 最后一行表明我们为Web服务添加的检查是至关重要的。 这是因为我们实际上没有运行Web服务器,所以curl测试失败了! 2、检查健康状态 现在我们已经添加了一些简单的检查,我们可以使用HTTP API来检查它们。 首先,我们可以使用这个命令查找任何失败的检查(注意,这可以在任一节点上运行):
  1. [root@localhost etc]# curl http://localhost:8500/v1/health/state/critical
  2. [{"Node":"agent-two","CheckID":"service:web","Name":"Service 'web' check","Status":"critical","Notes":"","Output":"","ServiceID":"web","ServiceName":"web","ServiceTags":["rails"],"Definition":{},"CreateIndex":230,"ModifyIndex":262}]
我们可以看到,只有一个检查,我们的Web服务检查,在危险(critical)状态。 另外,我们可以尝试使用DNS查询Web服务。 由于服务不健康,Consul不会返回任何结果:
  1. [root@localhost ~]# dig @127.0.0.1 -p 8600 web.service.consul
  2. ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 -p 8600 web.service.consul
  3. ; (1 server found)
  4. ;; global options: +cmd
  5. ;; Got answer:
  6. ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 38998
  7. ;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
  8. ;; WARNING: recursion requested but not available
  9. ;; OPT PSEUDOSECTION:
  10. ; EDNS: version: 0, flags:; udp: 4096
  11. ;; QUESTION SECTION:
  12. ;web.service.consul. IN A
  13. ;; AUTHORITY SECTION:
  14. consul. 0 IN SOA ns.consul. hostmaster.consul. 1511666146 3600 600 86400 0
  15. ;; Query time: 1 msec
  16. ;; SERVER: 127.0.0.1#8600(127.0.0.1)
  17. ;; WHEN: 11 26 11:15:46 CST 2017
  18. ;; MSG SIZE rcvd: 97

十一、KV Data

Consul除了提供服务发现和综合健康检查之外,还提供一个易于使用的KV存储。 这可以用来保存动态配置,协助服务协调,建立leader选举,并使开发人员可以考虑构建的任何东西。 1、简单使用 为了演示有多简单,我们将操作K / V存储中的几个键。 有两种方式与Consul KV存储进行交互:通过HTTP API和Consul KV CLI。 以下示例显示使用Consul KV CLI,因为它是最容易入门的。 对于更高级的集成,您可能需要使用Consul KV HTTP API。 首先让我们探索KV存储。 我们可以向Consul询问名为redis / config / minconns的路径上的key的值:
  1. [root@localhost ~]# consul kv get redis/config/minconns
  2. Error! No key exists at: redis/config/minconns
正如你所看到的,我们没有得到任何结果,这是合理的,因为KV存储没有数据。 接下来,我们可以insert或put 值到 KV 存储中。
  1. [root@localhost ~]# consul kv put redis/config/minconns 1
  2. Success! Data written to: redis/config/minconns
  3. [root@localhost ~]# consul kv put redis/config/maxconns 25
  4. Success! Data written to: redis/config/maxconns
  5. [root@localhost ~]# consul kv put -flags=42 redis/config/users/admin abcd1234
  6. Success! Data written to: redis/config/users/admin
现在我们在存储中有key,我们可以查询单个 key 的 value:
  1. [root@localhost ~]# consul kv get redis/config/minconns 1
Consul保留有关使用-detailed标志检索的字段的其他元数据:
  1. [root@localhost ~]# consul kv get -detailed redis/config/minconns
  2. CreateIndex 517
  3. Flags 0
  4. Key redis/config/minconns
  5. LockIndex 0
  6. ModifyIndex 517
  7. Session -
  8. Value 1
对于“redis / config / users / admin”这个键,我们设置了一个标志值42。所有的键都支持设置一个64位的整数标志值。 这不是Consul在内部使用的,但客户可以使用它为任何KV添加有意义的元数据。 可以使用递归选项列出存储的所有 key和 value。 结果将以字典顺序返回:
  1. [root@localhost ~]# consul kv get -recurse
  2. redis/config/maxconns:25
  3. redis/config/minconns:1
  4. redis/config/users/admin:abcd1234
要从Consul KV中删除一个 key,发出“删除” 命令:
  1. [root@localhost ~]# consul kv delete redis/config/minconns Success! Deleted key: redis/config/minconns
也可以使用递归选项删除整个前缀:
  1. [root@localhost ~]# consul kv delete -recurse redis Success! Deleted keys with prefix: redis
要更新现有key的值,请在相同路径上put一个值:
  1. [root@localhost ~]# consul kv put foo bar
  2. Success! Data written to: foo
  3. [root@localhost ~]# consul kv get foo
  4. bar
  5. [root@localhost ~]# consul kv put foo zip
  6. Success! Data written to: foo
  7. [root@localhost ~]# consul kv get foo
  8. zip
Consul可以使用Check-And-Set操作提供原子键更新。 要执行CAS操作,请指定-cas选项:
  1. [root@localhost ~]# consul kv get -detailed foo
  2. CreateIndex 710
  3. Flags 0
  4. Key foo
  5. LockIndex 0
  6. ModifyIndex 716
  7. Session -
  8. Value bar
  9. [root@localhost ~]# consul kv put -cas -modify-index=716 foo bar
  10. Success! Data written to: foo
  11. [root@localhost ~]# consul kv put -cas -modify-index=716 foo bar
  12. Error! Did not write to foo: CAS failed
在这种情况下,第一个CAS更新成功,因为索引是716。第二个操作失败,因为索引不再是716。

十二、Consul Web UI

Consul支持web ui界面。UI可用于查看所有服务和节点,查看所有运行状况检查及其当前状态,以及读取和设置键/值数据。 用户界面自动支持多数据中心。 要设置自带的UI,请使用-ui参数启动Consul代理:
  1. consul agent -ui
UI可以在与HTTP API相同的端口上的/ui路径中使用。 默认情况下,这是http://localhost:8500/ui。 您可以在这里查看Consul Web UI的现场演示。

十三、Docker下安装consul

1、拉取镜像
  1. docker search consul
2、启动consul
  • 启动节点1(server模式)
  1. docker run -d -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' --name=node1 consul agent -server -bind=172.17.0.2 -bootstrap-expect=3 -node=node1
-node:节点的名称 -bind:绑定的一个地址,用于节点之间通信的地址,可以是内外网,必须是可以访问到的地址 -server:这个就是表示这个节点是个SERVER -bootstrap-expect:这个就是表示期望提供的SERVER节点数目,数目一达到,它就会被激活,然后就是LEADER了
  • 启动节点2-3(server模式)
  1. docker run -d -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' --name=node2 consul agent -server -bind=172.17.0.3 -join=172.17.0.2 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=node2 docker run -d -e 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}' --name=node3 consul agent -server -bind=172.17.0.4 -join=172.17.0.2 -node-id=$(uuidgen | awk '{print tolower($0)}') -node=node3 -client=172.17.0.4

-join:这个表示启动的时候,要加入到哪个集群内,这里就是说要加入到节点1的集群

-node-id:这个貌似版本8才加入的,这里用这个来指定唯一的节点ID,可以查看这个issue -client:这个表示注册或者查询等一系列客户端对它操作的IP,如果不指定这个IP,默认是127.0.0.1。
  • 启动节点4(client模式) docker run -d -e ‘CONSUL_LOCAL_CONFIG={“leave_on_terminate”: true}’ —name=node4 consul agent -bind=172.17.0.5 -retry-join=172.17.0.2 -node-id=$(uuidgen | awk ‘{print tolower($0)}’) -node=node4 除了没有-server,其它都是一样的,没有这个就说明这个节点是CLIENT
  • 查看下集群的状态
  1. docker exec -t node1 consul members

Consul 教程 - 图6

4个节点都列出来了。Status表示它们的状态,都是alive。Type表示它们的类型,三个SERVER一个CLIENT,和我们之前启动的一样。DC表示数据中心,都是dc1。
  • 节点异常consul的处理 Consul 教程 - 图7日志打印,心跳检查node1的ip超时,接着开始选举。node2被选举为新的leader。我们查看下现在的leader: curl http://172.17.0.4:8500/v1/status/leader 返回的内容: “172.17.0.3:8300” 172.17.0.3 就是 node2节点的IP - LEADER 挂了 leader挂了,consul会重新选取出新的leader,只要超过一半的SERVER还活着,集群是可以正常工作的。node1是leader,所以把这个容器停了。 docker stop node1 看看其他节点的日志(node2):
3、注册个服务 使用HTTP API 注册个服务,使用接口API API)调用 调用 http://consul:8500/v1/agent/service/register PUT 注册一个服务。request body:
  1. {
  2. "ID": "userServiceId", //服务id
  3. "Name": "userService", //服务名
  4. "Tags": [ //服务的tag,自定义,可以根据这个tag来区分同一个服务名的服务
  5. "primary",
  6. "v1"
  7. ],
  8. "Address": "127.0.0.1",//服务注册到consul的IP,服务发现,发现的就是这个IP
  9. "Port": 8000, //服务注册consul的PORT,发现的就是这个PORT
  10. "EnableTagOverride": false,
  11. "Check": { //健康检查部分
  12. "DeregisterCriticalServiceAfter": "90m",
  13. "HTTP": "http://www.baidu.com", //指定健康检查的URL,调用后只要返回20X,consul都认为是健康的
  14. "Interval": "10s" //健康检查间隔时间,每隔10s,调用一次上面的URL
  15. }
  16. }
使用curl调用
  1. curl http://172.17.0.4:8500/v1/agent/service/register -X PUT -i -H "Content-Type:application/json" -d '{
  2. "ID": "userServiceId",
  3. "Name": "userService",
  4. "Tags": [
  5. "primary",
  6. "v1"
  7. ],
  8. "Address": "127.0.0.1",
  9. "Port": 8000,
  10. "EnableTagOverride": false,
  11. "Check": {
  12. "DeregisterCriticalServiceAfter": "90m",
  13. "HTTP": "http://www.baidu.com",
  14. "Interval": "10s"
  15. }
  16. }'
4、发现个服务 刚刚注册了名为userService的服务,我们现在发现(查询)下这个服务
  1. curl http://172.17.0.4:8500/v1/catalog/service/userService
返回的响应:
  1. [
  2. {
  3. "Address": "172.17.0.4",
  4. "CreateIndex": 880,
  5. "ID": "e6e9a8cb-c47e-4be9-b13e-a24a1582e825",
  6. "ModifyIndex": 880,
  7. "Node": "node3",
  8. "NodeMeta": {},
  9. "ServiceAddress": "127.0.0.1",
  10. "ServiceEnableTagOverride": false,
  11. "ServiceID": "userServiceId",
  12. "ServiceName": "userService",
  13. "ServicePort": 8000,
  14. "ServiceTags": [
  15. "primary",
  16. "v1"
  17. ],
  18. "TaggedAddresses": {
  19. "lan": "172.17.0.4",
  20. "wan": "172.17.0.4"
  21. }
  22. }
  23. ]
内容有了吧,这个就是我们刚刚注册的服务的信息,就可以获取到 服务的名称是“userService” 服务地址是“127.0.0.1” 服务的端口是“8000” 5、存储个K/V 设置一个值到user/config/connections 内容为5
  1. docker exec -t node1 consul kv put user/config/connections 5
6、获取特定的值
  1. docker exec -t node1 consul kv get -detailed user/config/connections

Consul 教程 - 图8

值的内容为5,还有key等相关的值。