写点什么

微服务之 consul

作者:迷彩
  • 2022 年 6 月 25 日
  • 本文字数:6025 字

    阅读完需:约 20 分钟

今天,刚刚复习了一下,今天给大家分享下 consul 的搭建和相关使用!

首先,使用之前我们要知道 consul 是什么,干什么用的?

一、概述

consul 是 google 开源的一个使用 go 语言开发的服务发现、配置管理中心服务。内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其他工具(比如 ZooKeeper 等)。服务部署简单,只有一个可运行的二进制的包。每个节点都需要运行 agent,他有两种运行模式 server 和 client。每个数据中心官方建议需要 3 或 5 个 server 节点以保证数据安全,同时保证 server-leader 的选举能够正确的进行。

如果熟悉 zk 的同学应该对 consul 的相关的操作很快可以上手。


其实我们常用的就是用来做服务发现:

带着问题来学习,什么是服务发现?


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



图中,客户端的一个接口,需要调用服务 A-N。客户端必须要知道所有服务的网络位置的,以往的做法是配置是配置文件中,或者有些配置在数据库中。这里就带出几个问题:

  • 需要配置 N 个服务的网络位置,加大配置的复杂性

  • 服务的网络位置变化,都需要改变每个调用者的配置

  • 集群的情况下,难以做负载(反向代理的方式除外)

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

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



与之前一张不同的是,加了个服务发现模块。图比较简单,这边文字描述下。服务 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 官方文档抠出来的。

我们只看数据中心 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 基本使用

自己就一台机子,所以这里就演示下 docker 下部署使用 consul。容器与宿主机的端口映射忽略,正常生产环境每个宿主机一个 consul,端口需要映射到宿主机

二、consul 集群搭建

1)安装

首先去官网现在合适的 consul 包:https://www.consul.io/downloads.html

安装直接下载 zip 包,解压后只有一个可执行的文件 consul,将 consul 添加到系统的环境变量里面。

#unzip consul_1.2.3_linux_amd64.zip

#cp -a consul  /usr/bin

#consul

Usage: consul [--version] [--help] <command> [<args>]
Available commands are: agent Runs a Consul agent catalog Interact with the catalog connect Interact with Consul Connect event Fire a new event exec Executes a command on Consul nodes force-leave Forces a member of the cluster to enter the "left" state info Provides debugging information for operators. intention Interact with Connect service intentions join Tell Consul agent to join cluster keygen Generates a new encryption key keyring Manages gossip layer encryption keys kv Interact with the key-value store leave Gracefully leaves the Consul cluster and shuts down lock Execute a command holding a lock maint Controls node or service maintenance mode members Lists the members of a Consul cluster monitor Stream logs from a Consul agent operator Provides cluster-level tools for Consul operators reload Triggers the agent to reload configuration files rtt Estimates network round trip time between nodes snapshot Saves, restores and inspects snapshots of Consul server state validate Validate config files/directories version Prints the Consul version watch Watch for changes in Consul
复制代码

输入 consul,出现上面的内容证明安装成功。

 

2)启动

consul 必须启动 agent 才能使用,有两种启动模式 server 和 client,还有一个官方自带的 ui。server 用与持久化服务信息,集群官方建议 3 或 5 个节点。client 只用与于 server 交互。ui 可以查看集群情况的。

server:

cn1:

#consul agent  -bootstrap-expect 2  -server   -data-dir /data/consul0 -node=cn1 -bind=192.168.1.202 -config-dir /etc/consul.d -enable-script-checks=true  -datacenter=dc1 

cn2:

#consul agent    -server  -data-dir /data/consul0 -node=cn2 -bind=192.168.1.201 -config-dir /etc/consul.d -enable-script-checks=true  -datacenter=dc1  -join 192.168.1.202

cn3:

#consul agent  -server  -data-dir /data/consul0 -node=cn3 -bind=192.168.1.200 -config-dir /etc/consul.d -enable-script-checks=true  -datacenter=dc1  -join 192.168.1.202

参数解释:

-bootstrap-expect:集群期望的节点数,只有节点数量达到这个值才会选举 leader。

-server: 运行在 server 模式

-data-dir:指定数据目录,其他的节点对于这个目录必须有读的权限

-node:指定节点的名称

-bind:为该节点绑定一个地址

-config-dir:指定配置文件,定义服务的,默认所有一.json 结尾的文件都会读

-enable-script-checks=true:设置检查服务为可用

-datacenter: 数据中心没名称,

-join:加入到已有的集群中

 

client:

#consul agent   -data-dir /data/consul0 -node=cn4 -bind=192.168.1.199 -config-dir /etc/consul.d -enable-script-checks=true  -datacenter=dc1  -join 192.168.1.202

client 节点可以有多个,自己根据服务指定即可。

ui:

#consul agent  -ui  -data-dir /data/consul0 -node=cn4 -bind=192.168.1.198  -client 192.168.1.198   -config-dir /etc/consul.d -enable-script-checks=true  -datacenter=dc1  -join 192.168.1.202

 -ui:使用自带的 ui,

-ui-dir:指定 ui 的目录,使用自己定义的 ui

-client:指定 web  ui、的监听地址,默认 127.0.0.1 只能本机访问。

集群创建完成后:

使用一些常用的命令检查集群的状态:

#consul  info

可以在 raft:stat 看到此节点的状态是 Fllower 或者 leader

#consul membersNode Address Status Type Build Protocol DC Segmentcn1 192.168.1.202:8301 alive server 1.0.2 2 dc1 <all>cn2 192.168.1.201:8301 alive server 1.0.2 2 dc1 <all>cn3 192.168.1.200:8301 alive client 1.0.2 2 dc1 <default>
复制代码

新加入一个节点有几种方式;

1、这种方式,重启后不会自动加入集群

#consul  join  192.168.1.202
复制代码

2、#在启动的时候使用-join 指定一个集群

#consul agent  -ui  -data-dir /data/consul0 -node=cn4 -bind=192.168.1.198 -config-dir /etc/consul.d -enable-script-checks=true  -datacenter=dc1  -join 192.168.1.202
复制代码

3、使用-startjoin 或-rejoin

#consul agent  -ui  -data-dir /data/consul0 -node=cn4 -bind=192.168.1.198 -config-dir /etc/consul.d -enable-script-checks=true  -datacenter=dc1  -rejoin
复制代码

访问 ui:

http://192.168.1.198:8500/ui

端口:

8300:consul agent 服务 relplaction、rpc(client-server)

8301:lan gossip

8302:wan gossip

8500:http api 端口

8600:DNS 服务端口

 

3)服务注册

采用的是配置文件的方式,(官方推荐)首先创建一个目录用于存放定义服务的配置文件

#mkdir /etc/consul.d/

启动服务的时候要使用-config-dir 参数指定。

下面给出一个服务定义:

#cat web.json

{    "service":{        "name":"web",        "tags":[            "rails"        ],        "port":80,        "check":{            "name":"ping",            "script":"curl -s localhost:80",            "interval":"3s"        }    }}
复制代码

如果这样启动 consul 后,会发现 consul 的日志里面一直报错,因为我们没有启动 80 端口的服务,下面给出 go 写的一个程序:

package mainimport (    "io"    "log"    "net/http"    "strconv"    "fmt")var iCnt  int = 0;
func helloHandler(w http.ResponseWriter, r*http.request) { iCnt++; str :="Hell eorld ! friend("+ strconv.Itoa(iCnt)+")" io.WriteString(w,str) fmt.Println(str)}
func main(){ ht :=http.HanderFunc(helloHandler) if ht != nil { http.Handle("/hello",ht) } err := http.ListenAndServe(":80",nil) if err != nil{ log.Fatal("ListenAndserve:",err.Error()) }}
复制代码

#需要一个 goalong 的环境:

#go  build -o  web  web.go#./web
复制代码

此时就可以在没有运行 web 服务的机器上面执行 DNS 查询:


# dig @127.0.0.1 -p 8600 web.service.consul SRV;; ANSWER SECTION:web.service.consul. 0 IN SRV 1 1 80 cn2.node.dc1.consul.web.service.consul. 0 IN SRV 1 1 80 cn3.node.dc1.consul.;; ADDITIONAL SECTION:cn2.node.dc1.consul. 0 IN A 192.168.1.201cn2.node.dc1.consul. 0 IN TXT "consul-network-segment="cn3.node.dc1.consul. 0 IN A 192.168.1.200cn3.node.dc1.consul. 0 IN TXT "consul-network-segment=";; Query time: 17 msec;; SERVER: 127.0.0.1#8600(127.0.0.1);; WHEN: 四 1月 04 14:39:32 CST 2018;; MSG SIZE rcvd: 229
复制代码

可以看到服务已经注册到集群里面了。 

使用 dns 查询,默认域名格式 NAME.service.consul,NAME 就是 web.json 里面定义的 service 的 name。可以自己指定域和端口:-domain、-dns-port 53

为了方便使用 consul 集群的注册使用,所以写了一个三节点 client 的注册脚本,方便统一注册服务和管理。还利用到了 nfs,将服务文件共享到集群。

#!/usr/bin/env python#encoding: utf8#decription: registered a service to consulfrom subprocess import callimport sys
hosts = {"b1":"10.10.1.01:8500","b2":"10.10.7.1:8500","b3":"10.10.8.21:8500"}

def consul_relaod(): if (len(sys.argv) != 2) or sys.argv[1] == '-h': print(("Usage: {0} [option] :{1} ,if you wang update all of them,you must use 'all'").format(sys.argv[0],hosts.keys())) sys.exit()
elif(sys.argv[1] == 'all'): for i in hosts.keys(): call(("consul reload -http-addr {}").format(hosts[i]),shell=True) else: call(("consul reload -http-addr {}").format(hosts[sys.argv[1]]),shell=True)
if __name__ == '__main__': consul_relaod()
复制代码

hosts 是 client 节点列表。可以只注册其中的一个节点,输入 hosts 中对应的 key,也可以输入 all,注册到所有节点;nfs 共享的是/etc/consul.d 目录。

4)健康检查

check 使用来做服务的健康检查的,可以拥有多个,也可以不使用支持多种方式检查。check 必须是 script 或者 TTL 类型,如果是 TTL 类型则 ttl 变量必须被提供。script 是 consul 主动去检查服务的健康状况,ttl 是服务主动向 consul 报告自己的状况。新版本的 consul 不在使用 script 来表示,使用 args,如果是 https 服务的健康检查,可以使用 args 这种脚本的方式实现,因为 consul 默认不支持 https 的健康检查。

script check:"check": {    "args": ["/data/scripts/kubeadm-ha-0.sh",""],    "interval": "10s"} http check:{  "check": {       "id": "api",       "name": "HTTP API  500",       "http": "http://loclhost:500/health",        "interval": "10s",        "timeout": "1s"}} tcp  check:{  "check": {      "id": "ssh",      "name": "ssh TCP 26622",      "tcp": "localhost:26622",      "interval": "10s",      "timeout": "1s" }} ttl  check:{   "check": {       "id": "web-app",       "name": "Web APP status",       "notes": "Web APP does a curl  internally every 10 seconds",       "ttl": "30s"}}
复制代码

三、更新 consul 版本为最新版本 1.2.3.

版本更新特性:

https://github.com/hashicorp/consul/blob/v1.2.3/CHANGELOG.md

ui 较之前有很大改变:






文章有点长,大家慢慢看

发布于: 刚刚阅读数: 4
用户头像

迷彩

关注

我的工作是常年写bug|公众号:编程架构之美 2020.06.18 加入

修bug的菜鸟~公众号:“互联网有啥事”已改名为“编程架构之美”

评论

发布
暂无评论
微服务之consul_微服务_迷彩_InfoQ写作社区