服务发现的概念简述

在以前使用的是,N台机器运行了N个服务,客户端必须要知道这N个服务各自的网络位置,以前的做法是配置在配置文件中,或者有些配置在数据库中。

问题:

  1. 需要配置N个服务的网络位置,加大配置的复杂性
  2. 每个服务如果改变网络位置,那么都需要改变每个调用者的配置,以便调用到该服务
  3. 集群的情况下,难以做负载(反向代理的方式除外)

服务发现就是解决这些问题的

服务发现明显的改变就是多了一个服务发现模块

服务A-N把当前自己的网络位置注册到服务发现模块(这里注册的意思就是告诉),服务发现就以K-V的方式记录下,K一般是服务名,V就是IP:PORT。服务发现模块定时的轮询查看这些服务能不能访问的了(这就是健康检查)。客户端在调用服务A-N的时候,就跑去服务发现模块问下它们的网络位置,然后再调用它们的服务。这样的方式是不是就可以解决上面的问题了呢?客户端完全不需要记录这些服务网络位置,客户端和服务端完全解耦!

consul简述

consul是个什么,我认为准确的来讲它是个服务发现框架,并且它就是提供服务发现的工具。另外常用的还有zookeeper、eureka、etcd,现在一般大多数应用于微服务场景

详细参考这篇文档

  • consul特性

service discovery:consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册。
health checking:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。
key/value storage:存储动态配置的系统。提供简单的HTTP接口,比如:存储各个服务的网络位置
multi-datacenter:无需复杂的配置,即可支持任意数量的区域。

  • 一般我们为了减少不必要的部署和维护代价,减少容错率。面对这些要求,可以有两种架构方案。
  1. docker+etcd+confd+Nginx
  2. docker+consul+Nginx

服务发现之consul理论整理_结合Docker+nginx+Tomcat简单部署案例

二、部署docker+consul+Nginx案例

部署此案例目的,在于对consul有个入门的了解

本案例中,使用Nginx做的web服务器,用到了处理动态页面的Tomcat,而Tomcat每次增加一个,减少一个,都要手动修改Nginx配置文件,并且发送信号给Nginx进行重载配置。本案例所有Tomcat都是运行在容器之内的,使用consul实现服务发现

环境

主机名 ip 角色信息
Nginx 192.168.111.3 consul server
docker1 192.168.111.4 consul client
docker2 192.168.111.5 consul client

自己组织语言简述下集群运行流程:首先,本案例Tomcat实在容器里头跑的,Tomcat连接到本机的registrator,该组件是向consul集群中在本机上的consul agent client注册并且存储自身服务的相关数据,agent client 会将服务注册的数据信息,发送给server,如果是有多台server的话,那么就会产生leader来负责同步各个server之间的信息,本案例由于环境限制只有一个server,而我们部署在server上的consul template软件监听相应的数据变化,然后加载到Nginx的主配置文件,Nginx主进程加载配置文件,省去了人工的很多精力,自动的添加/移除Tomcat的增减。

  • 安装

Consul 下载地址:https://www.consul.io/downloads.html ,下载后解压就是一个可执行的二进制文件consul,配置好环境变量,检查 consul 是否可用:



#unzip consul_1.5.1_linux_amd64.zip 
#mv consul /usr/local/bin/consul 
#consul --version
  • Consul agent
  1. 安装成功后,consul agent必须在每个consul节点上运行,所有运行consulagent节点构成consul集群。
  2. consul默认是client模式运行,提供服务注册、健康检查、转发查询给server leader。
    consul client 模式就是客户端模式,所有注册到这台client节点的服务会把相关数据转发到server,其本身并不支持持久化这些信息。

那么所谓的server模式,就是表明这个consul是个server,它的功能和client都一样,唯一不同的是,它会把所有的信息持久化到本地,这样即使故障发生,信息也是会被保留。

server-leader,意思是它是所有server的领导,和server所不一样的是,他需要负责互相给各个server同步各个server的注册信息;也负责各个节点的健康监测

  • Consul Template

Consul Template是Consul官方提供的一个工具,严格的来说不是标准的服务发现方式。这个工具会通过Consul监听数据变化然后替换模板中使用的标签,并发布替换后的文件到指定的目录。在nginx等web服务器做反向代理和负载均衡时特别有用。

  • registrator

程序会检查容器运行状态自动注册和注销docker容器的服务到服务配置中心,支持consul、etcd和skyDNS2.

部署

  • 启动consul
[root@nginx ~]# nohup consul agent -server -bootstrap -ui -data-dir=/var/lib/consul-data -bind=192.168.111.3 -client=0.0.0.0 -node=consul-server01 &>/var/log/consul.log &[1] 101674
[root@nginx ~]# ps aux | grep consul
root     101674  2.5  2.6 180012 26736 pts/1    Sl   19:45   0:00 consul agent -server -bootstrap -ui -data-dir=/var/lib/consul-data -bind=192.168.111.3 -client=0.0.0.0 -node=consul-server01

#nohup:后台运行
#-server:agent 以 server 模式启动的节点。一个数据中心中至少包含 1 个 server 节点。
#-bootstrap:用来控制一个server是否在bootstrap模式,在一个datacenter中只能有一个server处于bootstrap模式,当一个server处于bootstrap模式时,可以自己选举为raft leader
#-bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0
#-client:consul绑定在哪个client地址上,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1
#-node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名
#-ui:使用自带的web UI 页面。

参数参考

[root@nginx ~]# consul members
Node             Address             Status  Type    Build  Protocol  DC   Segment
consul-server01  192.168.111.3:8301  alive   server  1.5.1  2         dc1  <all>
#consul 集群信息
[root@nginx ~]# netstat -lnpt | grep consul
tcp        0      0 192.168.111.3:8300      0.0.0.0:*               LISTEN      101674/consul       
tcp        0      0 192.168.111.3:8301      0.0.0.0:*               LISTEN      101674/consul       
tcp        0      0 192.168.111.3:8302      0.0.0.0:*               LISTEN      101674/consul       
tcp6       0      0 :::8500                 :::*                    LISTEN      101674/consul       
tcp6       0      0 :::8600                 :::*                    LISTEN      101674/consul 

端口解释

端口号 协议 功能
8300 TCP agent server使用的,用于处理其他agent发来的请求
8301 TCP 、UDP agent使用此端口处理LAN中的gossip
8302 TCP 、UDP agent server使用此端口处理WAN中的与其他server的gossip
8400 TCP agent用于处理从CLI来的RPC请求
8500 TCP agent用于处理HTTP API
8600 TCP 、UDP agent用于处理 DNS 查询
  • 部署registrator

  • 两个client部署社区版docker

[root@localhost ~]# yum -y install yum-utils device-mapper-persistent-data lvm2
#安装依赖

[root@localhost ~]# wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
#下载docker的repo

[root@localhost ~]# yum -y install docker-ce

[root@localhost ~]# mkdir /etc/docker
[root@localhost ~]# vim /etc/docker/daemon.json

{
        "registry-mirrors":["https://*******.mirror.aliyuncs.com"]
}
#阿里云镜像加速

#systemctl start docker

地址需要个人前往阿里云获得,参考这篇文档

  • 以下两个client同样操作
[root@docker2 ~]# docker run -d --name=registrator --net=host -v /var/run/docker.sock:/tmp/docker.sock --restart=always gliderlabs/registrator:latest -ip=192.168.111.4 consul://192.168.111.3:8500

#下载一个registrator镜像运行一个容器,指定consulserver地址111.3,本机consul地址111.4

[root@docker1 ~]# docker run -itd -p 8081:8080 --name tomcat-01 -h tom01 tomcat
#--name 是容器名称,-h是该容器的主机名称,然后会从镜像仓库下载Tomcat镜像
[root@docker1 ~]# docker run -itd -p 8082:8080 --name tomcat-02 -h tom02 tomcat
61e165ac125b394d61e8e356a4f172a1533c1bc552edbf4cace7e6e5de3b43d3
[root@docker1 ~]# docker run -itd -p 8083:8080 --name tomcat-03 -h tom03 tomcat
fd7f9246b2d6e754b011dda136d74b9f61f10a7d401165e1ee1cb36d0f2383f8
[root@docker1 ~]# docker run -itd -p 8084:8080 --name tomcat-04 -h tom04 tomcat
0e6d3dc673a61c63729f3715179efd26b481bdc94edd56ea46ed2e3aa1af8a91
#两个容器主机相同操作
  • consul-template安装:

只需要下载可执行文件:https://releases.hashicorp.com/consul-template/
将执行文件解压放到/usr/local/bin/下即可

consul-template是基于consul自动替换配置文件的应用。作为守护进程运行,实时查询consul集群信息,更新文件系统上的任意数量的指定模板,生成配置文件,更新完成以后可以选择运行shell命令执行更新操作重加载服务。

该程序可以查询consul的服务目录、key、key-values等,特别适合动态的创安金配置文件,例如Nginx,Apache,haproxy等。

[root@nginx ~]# mkdir consul
[root@nginx ~]# cd consul/
[root@nginx consul]# ls
[root@nginx consul]# 
[root@nginx consul]# vim nginx.ctmpl
#配置一个模板

upstream tomcatback {
  {{range service "tomcat"}}
        server {{.Address}}:{{.Port}};
        {{end}}
}
server {
        listen 80;
        server_name localhost 192.168.111.3;
        access_log /usr/local/nginx/logs/joinbest-access.log;
        index index.html index.jsp;
        location / {
        root /usr/share/nginx/html/;
        index index.html;
  }

        location /stub_status {
          stub_status;
  }
        location ~ \.jsp$ {
          proxy_pass http://tomcatback;
  }
}

随后安装Nginx


[root@nginx consul]# vim /usr/local/nginx/conf/nginx.conf
http{
    ...
include vhost/*.conf;
}
#引用其他的文件

[root@nginx consul]# mkdir /usr/local/nginx/conf/vhost
#nginx 
#启动服务
  • 配置template并启动
[root@nginx consul]# unzip consul-template_0.20.0_linux_amd64.zip 
Archive:  consul-template_0.20.0_linux_amd64.zip
  inflating: consul-template     
  
[root@nginx consul]# mv consul-template /usr/local/bin/

[root@nginx consul]# consul-template -consul-addr 192.168.111.3:8500 -template "/root/consul/nginx.ctmpl:/usr/local/nginx/conf/vhost/nginx_tomcat.conf:/usr/local/nginx/sbin/nginx -s reload" --log-level=info 

#-consul-addr:指定server(leader)所在的主机和端口,程序要从这里获取服务的信息来进行下去
#-template:模板文件位置:根据模板结合服务配置生成的文件放置的位置及名称:改动之后重载文件的命令
#--log-level:表示输出信息的级别,这里为info

紧接着,因为是守护进程,会占用终端,所以平时都是用nohup命令使其后台运行

在开启一个终端,查看刚生成配置文件

[root@nginx ~]# cat /usr/local/nginx/conf/vhost/nginx_tomcat.conf 
upstream tomcatback {
  
	server 192.168.111.4:8081;
	
	server 192.168.111.4:8082;
	
	server 192.168.111.4:8083;
	
	server 192.168.111.4:8084;
	
	server 192.168.111.4:8081;
	
	server 192.168.111.4:8082;
	
	server 192.168.111.4:8083;
	
	server 192.168.111.4:8084;
	
}
server {
	listen 80;
	server_name localhost 192.168.111.3;
	access_log /usr/local/nginx/logs/joinbest-access.log;
	index index.html index.jsp;
	location / {
	root /usr/share/nginx/html/;
	index index.html;
  }

	location /stub_status {
  	  stub_status;
  }
	location ~ \.jsp$ {
	  proxy_pass http://tomcatback;
  }
}

虽然看起来没毛病,但是容器地址怎么能是一样的呢,应该有111.5的啊

想起来了,上面运行 registrator镜像时候,我将自身在集群中显示的ip还是111.4,疏忽了

解决

[root@docker2 ~]# docker stop `docker ps | awk 'NR!=1 {print $1}'`
[root@docker2 ~]# docker rm `docker ps -a | awk 'NR!=1 {print $1}'`
#之前容器都删除掉

[root@docker2 ~]# docker run -d --name=registrator --net=host -v /var/run/docker.sock:/tmp/docker.sock --restart=always gliderlabs/registrator:latest -ip=192.168.111.5 consul://192.168.111.3:8500
#重新运行,这下改过来ip了,注意

[root@docker2 ~]# docker run -itd -p 8081:8080 --name tomcat-01 -h tom01 tomcat
daec6a29f6399adbc167a13b383cb850f0db130097145b8479e12778834b82a3
[root@docker2 ~]# docker run -itd -p 8082:8080 --name tomcat-02 -h tom02 tomcat
83fff3139abe98522924eb5d53a1b1c3ee01fcabab593c92afb06b1b1a11a5b3
[root@docker2 ~]# docker run -itd -p 8083:8080 --name tomcat-03 -h tom03 tomcat
4d7b56307f8c5fdf9907182c7870bceaedff7686ee0fbe8c04233879009c9a6c
[root@docker2 ~]# docker run -itd -p 8084:8080 --name tomcat-04 -h tom04 tomcat
1c79ffcc488723f5f75835d19efabf79bc13bcb8bdd7ee8d52e13b58666c8623
#重新启动容器

那么,正好测试下,consul template 实用不

图2
服务发现之consul理论整理_结合Docker+nginx+Tomcat简单部署案例

[root@nginx ~]# cat /usr/local/nginx/conf/vhost/nginx_tomcat.conf 
upstream tomcatback {
  
	server 192.168.111.4:8081;
	
	server 192.168.111.4:8082;
	
	server 192.168.111.4:8083;
	
	server 192.168.111.4:8084;
	
	server 192.168.111.5:8081;
	
	server 192.168.111.5:8082;
	
	server 192.168.111.5:8083;
	
	server 192.168.111.5:8084;
	
}
server {
	listen 80;
	server_name localhost 192.168.111.3;
	access_log /usr/local/nginx/logs/joinbest-access.log;
	index index.html index.jsp;
	location / {
	root /usr/share/nginx/html/;
	index index.html;
  }

	location /stub_status {
  	  stub_status;
  }
	location ~ \.jsp$ {
	  proxy_pass http://tomcatback;
  }
}

很好

三、测试

[root@docker1 ~]# docker exec -it tomcat-01 /bin/bash -c 'echo www.tomcat1.com > /usr/local/tomcat/webapps/ROOT/index.jsp'
[root@docker1 ~]# docker exec -it tomcat-02 /bin/bash -c 'echo www.tomcat2.com > /usr/local/tomcat/webapps/ROOT/index.jsp'
[root@docker1 ~]# docker exec -it tomcat-03 /bin/bash -c 'echo www.tomcat3.com > /usr/local/tomcat/webapps/ROOT/index.jsp'
[root@docker1 ~]# docker exec -it tomcat-04 /bin/bash -c 'echo www.tomcat4.com > /usr/local/tomcat/webapps/ROOT/index.jsp'

[root@docker2 ~]# docker exec -it tomcat-01 /bin/bash -c 'echo www.tomcat5.com > /usr/local/tomcat/webapps/ROOT/index.jsp'
[root@docker2 ~]# docker exec -it tomcat-02 /bin/bash -c 'echo www.tomcat6.com > /usr/local/tomcat/webapps/ROOT/index.jsp'
[root@docker2 ~]# docker exec -it tomcat-03 /bin/bash -c 'echo www.tomcat7.com > /usr/local/tomcat/webapps/ROOT/index.jsp'
[root@docker2 ~]# docker exec -it tomcat-04 /bin/bash -c 'echo www.tomcat8.com > /usr/local/tomcat/webapps/ROOT/index.jsp'

测试浏览器,访问192.168.111.3/index.jsp看到页面不断更换

四、总结

  1. 讲真,实验很简单,原理很深厚,服务发现以前没接触过,到现在也只能说能勉强理解点
  2. 这些工具适用于需要大量容器环境,并且服务性质是一样的,要不然还不如手动改改配置得了
  3. 不过挺有成就感的呢,嘻嘻