前文《Consul实践之Consul是什么》讲述了consul是什么,这篇文档是一个Consul实际应用的一个例子,用Consul结合nginx构建高可用可扩展的Web服务。Consul还能作许多其余的事情,能够根据实际须要构思和使用。
html
nginx提供的负载均衡服务一样支持高可用、可扩展的Web服务,但缺点是较依赖于人工。例如传统的nginx负载均衡的配置方式是,在nginx某个include的某个配置文件中配置一个upstream,upstream中配置多个服务节点,每个服务节点就是一个web应用服务。nginx虽然能够作到对服务节点的健康检查,可是当服务节点增长、减小或者发生状态改变(如负载较大、网络故障、其余故障)时,nginx配置文件是固定写死的,不能动态的感知后端服务节点的服务状态信息,所以须要有一种解决方案可以帮助ngnix动态的感知后端服务节点的服务信息。要想实现这种需求,毫不仅Consul一家,但此例中使用Consul来实现,关于Consul其余的使用案例能够继续学习和研究。前端
此方案用到的组件:Consul、Consul-template、nginx、docker engine、docker-enter、git等,若是构建docker环境以及如何编译安装nginx能够参考《Ubuntu安装Docker引擎和支持HTTPS的docker-registry服务》也能够参考其余网站上的文档或教程。java
部署环境:本例子用阿里云的虚拟主机做为测试主机,该测试主机内建有Docker环境,Consul Cluster用docker搭建而成,nginx搭建在测试主机上,consul-template安装在测试主机上,服务应用以容器的形式运行在docker中。注释:consul支持多种部署环境,具体的如何部署能够参考已有的知识库、经验,也能够参考文本本身构思。node
下图是整理过的consul应用场景模拟图。用户访问前端的Application也就是UI,前端Application经过App Configuration File从后端Application上获取提供的服务,再返回给用户。后端Application上均安装consul,并以agent的形式运行在服务器上,并将Consul Agent加入到Consul Cluster中。Consul-template与Consul Cluster的Server链接,动态的从Consul的服务信息库汇中拉取后端Application的服务信息,这些服务信息写入到前端Application的配置文件中,在完成一次写入后(即后台服务发生变动时),Consul-template将自动经过命令告知前端应用从新加载,实现前端Application动态发现后端服务以及应用新配置文件的目的。linux
下图是根据上图延伸来的一个实际的方案,利用Consul结合nginx构建高可用可扩展的Web服务。nginx前端做为负载均衡器使用,它代理了三台能提供web服务的服务器,每一台服务器上均安装consul,并以agent的形式运行在服务器上,并将Consul Agent加入到Consul Cluster中。Consul-template与Consul Cluster的Server链接,动态的从Consul的服务信息库汇中拉取nginx代理的三台服务器的IP、端口号等信息,并将IP地址以及端口号写入到nginx的配置文件中,在完成一次写入后(即后台服务发生变动时),Consul-template将自动将nginx重启加载,实现nginx应用新配置文件的目的。nginx
本文假设系统中已经安装好nginx和docker engine以及docker-enter以及git等工具。其操做步骤归纳以下:git
构建consul Cluster(Consul 集群)github
构建Web应用服务web
每个服务应用安装和配置Consul Agent算法
安装并配置consul-template使consul-template与nginx联动
验证与测试
具体地操做步骤以下文所示。
构建consul Cluster(Consul 集群)能够部署在docker中,也能够部署在多个物理机中,也能够部署在多个虚拟机中,也能够部署在这些混合环境中。此例最初是为了快速学习Consul而用docker搭建的Consul集群,用其余方式部署也大同小异,能够根据docker的部署步骤反推,具体的能够参考下文分割线中间的部分。
关于docker p_w_picpaths的选用。能够经过搜索docker hub,输入consul关键词,搜索全部与consul有关的关键词,根据使用人数(pull次数)或星数(Stars)以及点开details(细节)按钮查看Repo info选项卡中关于该p_w_picpath的详细描述以及使用方法,再根据已有的知识库、经验判断使用哪个p_w_picpath。此方案中使用progrium/consul做为docker p_w_picpaths。
progrium/consul的p_w_picpath地址:https://hub.docker.com/r/progrium/consul/
选用理由以下:
已有方案中有使用progrium/consul的案例,能够供参考;
此镜像的星数和pull次数是最多的,pull次数高达9百万次;
在它的Repo info中详细的介绍了该镜像如何使用以及如何部署consul集群;
此外,该p_w_picpath大小合适,仅有五六十MB,虽然基于busybox,但一样适用于有Linux经验的技术人员。
在progrium提供的方案中提供了三种部署方式:1,试用consul;2.单机环境部署;3.生产环境部署。
Consul官方推荐部署方式能够参考:BOOTSTRAPPING A DATACENTER 以及 Deployment Table。
下表中列出了不一样集群规模下的群体大小以及容错率,推荐使用3-5台服务器用于部署Consul。为防止在故障发生时形成必不可免的数据损失,单个服务器的部署方案是极不推荐的。
Servers | Quorum Size | Failure Tolerance |
---|---|---|
1 | 1 | 0 |
2 | 2 | 0 |
3 | 2 | 1 |
4 | 3 | 1 |
5 | 3 | 2 |
6 | 4 | 2 |
7 | 4 | 3 |
因为环境有限,可用测试的主机的数量低于3,所以只能解决单机环境用docker知足consul的配置要求(尽管此要求并非强制的,也就是说可使用一个服务器、两个服务器)。
操做步骤能够参考https://hub.docker.com/r/progrium/consul/网站提供的Testing a Consul cluster on a single host,也能够参考下文。
# Refer: https://hub.docker.com/r/progrium/consul/ docker pull progrium/consul docker run -d --name node1 -h node1 progrium/consul -server -bootstrap-expect 3 JOIN_IP="$(docker inspect -f '``.`NetworkSettings`.`IPAddress`' node1)" docker run -d --name node2 -h node2 progrium/consul -server -join $JOIN_IP docker run -d --name node3 -h node3 progrium/consul -server -join $JOIN_IP docker run -d -p 8400:8400 -p 8500:8500 -p 8600:53/udp --name node4 -h node4 progrium/consul -join $JOIN_IP
通过上述命令,测试主机上的8400、8500以及8600端口就可使用了,端口做用分别是8400 (RPC), 8500 (HTTP), and 8600 (DNS) ,后面会用到8500。注意,此处的RPC与dubbo定义的RPC有所不一样,在Dubbo中RPC用于“远程通信: 提供对多种基于长链接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。”,而在这里的RPC是是Consul Agent与Consul Server通讯用的端口。除了以上端口还有其余一些端口,好比8300、830一、8302,这三个是用于Consul内部通讯使用的,单个主机环境中这三个端口用不到,因此不须要将这几个端口暴露给测试主机。
以上命令会在docker环境中建立4个容器(node一、node二、node3和node4),其中node1由于-server参数被显式的设置为server,其余的容器被设置成client,并加入到以node1为server的集群中,他们每一个节点都回监听接口,但只有node4将其端口与测试主机链接到了一块儿,这样能够经过访问测试主机上的端口就能获取到consul中存储的已注册服务的服务信息。
通过上述步骤consul集群就算搭建完成了,能够用浏览器访问http://ipaddress:8500/ui/#/dc1/services访问consul的ui控制台界面(说是控制台,但控制管理的功能比较少,目前仅供查看consul集群信息以及k/v数据库的功能)
=========================分割线======================================
非docker环境如何搭建consul?
根据docker容器中运行的命令以及配置文件可以轻松的发如今非docker环境中运行consul的方法,摘录以下:
# node1
/bin/consul agent -config-dir=/config -server -bootstrap-expect 3
#192.168.0.7是node1的内网IP
# node2
/bin/consul agent -config-dir=/config -server -join 192.168.0.7
# node3
/bin/consul agent -config-dir=/config -server -join 192.168.0.7
# node4
/bin/consul agent -config-dir=/config -join 192.168.0.7
# cat /config/consul.json
{
"data_dir": "/data",
"ui_dir": "/ui",
"client_addr": "0.0.0.0",
"ports": {
"dns": 53
},
"recursor": "8.8.8.8",
"disable_update_check": true
}
根据上面的consul的json数据,根目录下还有个ui目录,其内容能够经过以下得到:
# for consul web ui wget -c https://releases.hashicorp.com/consul/0.6.0/consul_0.6.0_web_ui.zip mkdir consul_web_ui unzip -d consul_web_ui consul_0.6.0_web_ui.zip
除了ui之外还有一个/data目录,此目录能够本身建,根据consul命令的提示本身建立。
=========================分割线======================================
构建Web应用服务能够经过多种方式,根据本身的实际状况搭建。好比能够用java语言写一个简单的serverlet也能够nginx作一个Web测试页出来,还能够直接用docker hub上现有的Web程序作测试。
此处可使用以下的方法快速构建一个Web应用。
#docker commit jdk8-firstvert jdk8-firstvert_with_consul #docker p_w_picpaths docker run -idt --name firstvertnode1 -h firstvertnode1 jdk8-firstvert_with_consul /bin/bash docker run -idt --name firstvertnode2 -h firstvertnode2 jdk8-firstvert_with_consul /bin/bash docker run -idt --name firstvertnode3 -h firstvertnode2 jdk8-firstvert_with_consul /bin/bash
通过上述命令后,就会生成3个新的容器,每一个容器运行着一个java serverlet,能够监听某个端口来提供Web服务。
经过docker-enter命令进入每个容器下载并配置consul
# for test [ -x /bin/consul ] || ( wget -c https://releases.hashicorp.com/consul/0.6.0/consul_0.6.0_linux_amd64.zip && unzip -d /bin consul_0.6.0_linux_amd64.zip ) [ -d /config ] || mkdir /config [ -d /data ] || mkdir /data # JOIN_IP is 192.168.0.7 nohup /bin/consul agent -config-dir=/config -join 192.168.0.7 -data-dir /data 2>&1 >/tmp/consul.log & nohup java -Dfile.encoding=utf-8 -jar FirstVert.x3-1.0-SNAPSHOT-fat.jar 2>&1 >/dev/null & # echo '{"service": {"name": "web", "tags": ["FirstVert"], "port": 8081}}' > /config/FirstVert.json
#下面这个命令是能够经过ping检查与百度网站链接的网络状态,能够加也能够不加
echo '{"check": {"name": "ping", "script": "ping -c1 www.baidu.com 2>&1 >/dev/null", "interval": "30s"}}' >/config/ping.json
# 下面的service中name为web是自定义的,能够本身取名字,tags后的FirstVert也是本身取的,脚本是用来检测此服务是否正常的,根据语义应该是根据函数返回值判断的
echo '{"service": {"name": "web", "tags": ["FirstVert"], "port": 8081, "check": {"script": "curl localhost:8081 >/dev/null 2>&1", "interval": "10s"}}}' >/config/FirstVert.json
#更新consul数据文件(至关于向consul注册服务)后,须要从新运行consul agent
killall consul nohup /bin/consul agent -config-dir=/config -join 192.168.0.7 -data-dir /data 2>&1 >/tmp/consul.log &
若是想简单的测试一下是否好用,能够用如下命令进行测试,
while : ; do curl http://ipaddress:port -w %{http_code} -s -o /dev/null; sleep 1; done
# Refer: https://github.com/hashicorp/consul-template
# Refer: https://releases.hashicorp.com/consul-template/0.12.0/
# https://github.com/hashicorp/consul-template/releases
wget -c https://releases.hashicorp.com/consul-template/0.12.0/consul-template_0.12.0_linux_amd64.zip unzip -d . consul-template_0.12.0_linux_amd64.zip cp consul-template '/bin' rm -rf consul*
# ready for test
# 把下面的{{range service "web"}}改为上面修改的service的名称,把server_name改为要监听的主机名或IP地址
# 负载均衡算法由nginx控制,具体的能够查阅nginx相关手册和网上的其余资料
# Refer: nohup /bin/consul agent -config-dir=/config -join 192.168.0.7 -data-dir /data 2>&1 >/tmp/consul.log &
# Refer: https://github.com/DingGuodong/consul-template#examples
vim /root/nginx_web.ctmpl
编辑内容以下
upstream web {
ip_hash;
# Refer: http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream
# least_conn;
# least_time;
{{range service "web"}}
server ``.`Address`:``.`Port` fail_timeout=0;
`end`
keepalive 64;
}
server {
listen 80;
server_name ipaddress;
location / {
client_max_body_size 0;
proxy_connect_timeout 300s;
proxy_send_timeout 900;
proxy_read_timeout 900;
proxy_buffer_size 32k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_redirect off;
proxy_hide_header Vary;
proxy_set_header Accept-Encoding '';
proxy_set_header Host $host;
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_headers_hash_max_size 51200;
proxy_headers_hash_bucket_size 6400;
proxy_pass http://web/;
}
}
# -dry表示仅运行此命令,但不实际执行写入文件的命令,此处是指不根据模版修改文件,不执行nginx -s reload命令
consul-template -consul 127.0.0.1:8500 -template /root/nginx_web.ctmpl:/usr/local/nginx/conf/vhost/http_temp_port_80.conf:"/usr/local/nginx/sbin/nginx -s reload" -dry
#经过此命令能够将consul-template 放到后台执行
nohup consul-template -consul 127.0.0.1:8500 -template nginx_web.ctmpl:/usr/local/nginx/conf/vhost/http_temp_port_80.conf:"/usr/local/nginx/sbin/nginx -s reload" 2>&1 >/tmp/consul-template.log &
上述命令执行后能够经过ps -ef | grep consul和查看/tmp/consul-template.log日志文件,查看consul-template的运行状况,也能够直接经过测试的手段来检测consul-template的运行状况。
通过以上步骤搭建完成后,能够访问nginx上配置好的server_name,以及consul的ui即http://ipaddress:8500/ui/#/dc1/services来查看效果。
能够尝试分别测试以下内容:
容器中止后,nginx的配置文件的内容,nginx的访问状况;
容器建立并启动consul agent后,nginx的配置文件的内容,nginx的访问状况;
发现容器出现任何非passing的状况,都会致使从nginx配置文件中移除;容器启动并配置正常后,nginx配置文件更新,容器能够被访问。这说明是很是符合预期需求的。
在初读consul的文档和查阅相关资料后,还还没有发现依赖于consul自身就能实现,提供根据服务节点的负载或健康情况而增长、移除服务节点的功能。这个有待于进一步查看和研究。
tag:consul测试方案,consul配置,consul RPC,consul搭建,consul实例
--end--