目录
- 什么是consul,有什么作用
- 1.Consul的作用
- 2.consul是如何做到做到服务的自动发现与更新呢?
- Docker consul自动发现服务架构的构建
- 1.底层环境
- 2.docker安装
- 3.配置consul服务器
- 4.配置容器服务器
- 5.安装consul-template
- 6.验证反向代理的轮询机制
- 7.验证自动发现与更新服务
- 8.consul添加多节点
什么是consul,有什么作用
consul是HashiCorp公司推出使用go语言编写的开源工具,用于实现分布式系统的服务发现与配置
具有如下特性:
- 1、consul支持健康检查,允许存储键值对
- 2、一致性协议采用Raft算法,用来保证服务的高可用
- 3、成员管理和消息广播采用GOSSIP协议,支持ACL访问控制
- 4、方便部署,与Docker等轻量级容器可无缝配合
1.Consul的作用
如上图所示,生产环境下,我们只需要前端的Nginx能够与后端的web服务器建立联系,反向代理功能能够完成就OK了
但是如果后端服务器要加节点了怎么办,可能第一时间想到的是去Nginx配置文件加上指向后端web地址就可以了,但是如果后端跑的是容器,少量节点还可以人工手动配置,如果这个时候后端节点增加的是1000台,10000台,靠人工添加是特别特别繁琐的
而且在日常维护中,后端节点突然down掉,容器down掉呢?任务量可想而知
consul:提供了自动发现与更新服务,不管你后端加容器还是减少容器,自动帮你完成配置文件的更新
2.consul是如何做到做到服务的自动发现与更新呢?
- 图解:
上方拓扑图是基于Docker完成的,然后将consul、consul template、registrator和nginx组装成一个值得信任且可扩展的服务框架,此架构可以灵活的、不需要重启任何服务、不需要重写任何配置的添加和移除服务
前端Nginx做反向代理,server_1,server_2是裸金属节点,节点中跑了多个容器
Nginx还跑了一个consul(服务的自动发现与更新)
|反向代理只需要指向后端的容器
如果容器down了,或者新加了容器,减少了容器,其中的地址,端口都会随着它发生改变
Nginx.conf文件也会变化,
变化的精髓就在consul template模板,它会将变化的东西写成变量,不变的则正常写入,有了这个模板之后,就放在这,有了变化之后就可以利用这个模板修改原有的nginx.conf
- 如何发现变化?
Consul agent负责监控下端节点反馈的信息,监控功能依赖于registrator,所以说对于跑业务的节点,需要安装registrator,registrator会定期的发送报告给Consul agent,告诉它我哪些东西改变了
Consul agent再将报告发送给consul server,consul server将请求信息发送给consul template,consul template根据请求修改nginx.conf
- 注意点:
后端业务节点需要安装registrator自动注册机制,监控的节点要装consul server,还需要consul template模板,consul server中自带agent,所以装了server就行了
Docker consul自动发现服务架构的构建
1.底层环境
服务器: | 20.0.0.21 | Docker-ce | Compose 3 | Consul | Consul-template |
服务器: | 20.0.0.22 | Docker-ce | registrator | ||
环境 | 防火墙与内核全关 |
2.docker安装
可以点击连接这里不再演示
3.配置consul服务器
[root@docker ~]# mkdir consul
[root@docker ~]# cd consul/
##将软件包拖进来##
unzip consul_0.9.2_linux_amd64.zip
###解压后会有一个执行命令###
[root@docker consul]# unzip consul_0.9.2_linux_amd64.zip
Archive: consul_0.9.2_linux_amd64.zip
inflating: consul
[root@docker consul]# ls
consul
consul-template_0.19.3_linux_amd64.zip
consul_0.9.2_linux_amd64.zip
##放到bin下交给系统管理与识别
[root@docker consul]# mv consul /usr/bin/
###配置consul####
[root@docker consul]# consul agent \
-server \
-bootstrap \
-ui \
-data-dir=/var/lib/consul-data \
-bind=20.0.0.21 \
-client=0.0.0.0 \
-node=consul-server01 &> /var/log/consul.log &
#########脚本解释###########
-server:里面会以前端的页面形式展现出来
-bootstrap:所以需要安装前端的脚本bootstrap
-ui:ui界面
-data-dir:数据的存放目录
-bind: 绑定本地地址
-client=0.0.0.0 监听任意客户端网段发来的通告信息(可以监控后面的容器发生了什么样的变化)
-node:声明node节点名称, &>表述混合输出,最后一个&,表示放到后台运行
########################脚本解释################3
####查看集群信息,这里出现一个报错,是因为我把server敲成了serber
[root@docker consul]# consul members
Error retrieving members: Get http://127.0.0.1:8500/v1/agent/members: dial tcp 127.0.0.1:8500: getsockopt: connection refused
解决:[root@docker consul]# pkill -9 consul 再将consul脚本再执行一遍
##查看集群信息
[root@docker consul]# consul members
Node Address Status Type Build Protocol DC
consul-server01 20.0.0.21:8301 alive server 0.9.2 2 dc1
##查看consul的领导者
###端口号8300的开放,是为了方便node节点的registrator(注册器)与它通讯
[root@docker consul]# consul info | grep leader
leader = true
leader_addr = 20.0.0.21:8300
####还可以通过httpd api 获取集群信息####
curl 127.0.0.1:8500/v1/status/peers ###查看集群成员
["20.0.0.21:8300"]
curl 127.0.0.1:8500/v1/status/leader ##查看集群的老大
"20.0.0.21:8300"
curl 127.0.0.1:8500/v1/catalog/services ##查看所有注册的服务
{"consul":[]}
curl 127.0.0.1:8500/v1/status/nginx ##查看nginx的服务信息,因为这个时候我还没有开服务所以显示为空
curl 127.0.0.1:8500/v1/catalog/nodes ##查看集群节点详细信息
[{"ID":"75c320a5-e04c-ca23-b8e5-b7439f6ad73c","Node":"consul-server01","Address":"20.0.0.21",
"Datacenter":"dc1","TaggedAddresses":{"lan":"20.0.0.21","wan":"20.0.0.21"},"Meta":{},"CreateIndex":5,"ModifyIndex":6}]
打开浏览器访问20.0.0.21:8500
4.配置容器服务器
1.安装Gliderlabs/Registrator Gliderlabs/Registrator
可检查容器运行状态自动注册,还可注销docker容器的服务到服务配置中心。
目前支持Consul、Etcd和SkyDNS2。
在20.0.0.22节点,执行以下操作:
###首先要安装docker-ce######安装完之后####
[root@node ~]# docker run -d \
--name=registrator \
--net=host \
-v /var/run/docker.sock:/tmp/docker.sock \
--restart=always \
gliderlabs/registrator:latest \
-ip=20.0.0.22 \
consul://20.0.0.21:8500
#########脚本解释##########
--name:指定容器的名称
--net=host : 指定里面的网络形式 host仅主机
-v 数据卷,前面是宿主机的,后面的是容器的,注意:里面联通的是sock,为了里外相互联通
--restart : always 重启策略,一旦容器发现down状态,会对容器始终进行重启(always)
镜像来自于gliderlabs仓库,名字为redistrator,标签为latest
-ip:本地的IP地址
Consul://指向master地址,服务端口8500
####################脚本注释########################
####查看镜像###########
[root@node ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gliderlabs/registrator latest 3b59190c6c80 4 years ago 23.8MB
####到20.0.0.21主机查看8500端口可以看到两个服务器都在#######
[root@docker consul]# netstat -anutp | grep 8500
tcp6 0 0 :::8500 :::* LISTEN 48701/consul
tcp6 0 0 20.0.0.21:8500 20.0.0.22:60366 ESTABLISHED 48701/consul
###http://20.0.0.21:8500/这个时候可以刷新浏览器########
###因为现在还没有容器,所以是空的#######
##创建容器,测试consul是否能够自动发现
20.0.0.22:
docker run -itd -p 83:80 --name test-01 nginx
docker run -itd -p 84:80 --name test-02 nginx
docker run -itd -p 88:80 --name test-03 httpd
docker run -itd -p 89:80 --name test-04 httpd
##端口号冲突报错,改成84:80######
[root@node ~]# docker run -itd -p 83:80 --name test-02 nginx
3d1842a261dfdd7faa70feffb2fe53f5890b6c635e6ca8265ac184149e358656
docker: Error response from daemon: driver failed programming external connectivity on
endpoint test-02 (760dca26264e173f84cc0230836b3275eaf652374cbcd1ed240856b747222b1e): Bind
for 0.0.0.0:83 failed: port is already allocated.
#########这个时候你再打开20.0.0.21:8500,点击NODES后会看到自动发现了20.0.0.22上的4个服务###
#####查看镜像状态#####
[root@node ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e9c21eeafbe httpd "httpd-foreground" 2 minutes ago Up About a minute 0.0.0.0:89->80/tcp test-04
e6ce7832e809 httpd "httpd-foreground" 2 minutes ago Up 2 minutes 0.0.0.0:88->80/tcp test-03
3fcbe2a4d7a1 nginx "/docker-entrypoint.…" 5 minutes ago Up 5 minutes 0.0.0.0:84->80/tcp test-02
5821bd0c9b49 nginx "/docker-entrypoint.…" 6 minutes ago Up 6 minutes 0.0.0.0:83->80/tcp test-01
67582691ae53 gliderlabs/registrator:latest "/bin/registrator -i…" 16 minutes ago Up 16 minutes registrator
##这个时候再次查看master上所有注册的服务#####,可以看到多了nginx与httpd服务###
[root@docker consul]# curl 127.0.0.1:8500/v1/catalog/services
{"consul":[],"httpd":[],"nginx":[]}
5.安装consul-template
- Consul-Template是一个守护进程,
用于实时查询Consul集群信息,并更新文件系统上任意数量的指定模板,生成配置文件。更新完成以后,可以选择运行shell命令执行更新操作,重新加载Nginx。Consul-Template可以查询Consul中的服务目录、Key、Key-values等。这种强大的抽象功能和查询语言模板可以使Consul-Template特别适合动态的创建配置文件。
例如:创建Apache/Nginx Proxy Balancers、Haproxy Backends
#####首先准备template nginx模板文件#######在consul主机:20.0.0.21
[root@docker consul]# cd ~
[root@docker ~]# cd consul/
###创建模板###########
[root@docker consul]# vim nginx.ctmpl ##模板固定后缀.ctmpl,consul-template的缩写
##consul-server发现变化后,将地址与端口写入参数中,转发给consul-template,consul-template直接调用API,将值写进nginx.conf
##range:范围,是遍历的手法,相当于for循环
upstream http_backend { ##upstream表示做的是4层转发,nginx可以同时做4层与7层转发,lvs只能做4层转发
{{range service "nginx"}} ##争对于于nginx,它把它转发的请求转发给了nginx,range
server {{.Address}}:{{.Port}}; ##这里定义了两个API(内置变量),Address地址,Port端口
{{end}} ##相当于for中的break,退出循环
}
##nginx中有多个功能模块,转发可以是从server中的local段进行###
server {
listen 83; ##添加的监听端口,以防端口冲突,随便定义,访问20.0.0.21:83/80都可以
server_name localhost 20.0.0.21; ##本地IP地址
access_log /var/log/nginx/ZZT.cn-access.log; ##日志文件存放位置
index index.html index.php; ##支持的首页类型
location / { ##location中可以实现跳转,依赖于proxy_pass(反向代理转发模块)
proxy_set_header HOST $host; ##开头要对请求转发头部做定义:HOST $host表示来访者的主机名,就是主机头信息
proxy_set_header X-Real-IP $remote_addr; ##$remote_addr是一个内置变量,表示的是请求者的地址,远端请求的地址
proxy_set_header Client-IP $remote_addr; ##含有同上,都表示请求者的地址,远端请求的地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ##X-Forwarded-For表示转发,转发的是$proxy_add_x_forwarded_for,它代表的是反向代理的所谓的路径
proxy_pass http://http_backend; ##重点!!!:proxy_pass(反向代理转发模块),proxy_pass启用的是http协议,加载的是http_backend这个函数模块
} ##http_backend这个是自己写的,它来自哪里?看第一行!!!!
}
######这个时候在本地(20.0.0.21)安装一个nginx,充当着反向代理#########
[root@docker consul]# yum -y install gcc gcc-c++ zlib-devel pcre-devel
将nginx包源拖进/opt
[root@docker nginx]# cd /opt/
[root@docker opt]# tar zxvf nginx-1.15.9.tar.gz
[root@docker opt]# cd nginx-1.15.9/
[root@docker nginx-1.15.9]# ./configure --prefix=/usr/local/nginx
[root@docker nginx-1.15.9]# make && make install
[root@docker nginx-1.15.9]# cd /usr/local/nginx/conf/
[root@docker conf]# vim nginx.conf
##19行添加###
19 include vhost/*.conf;
##include表示包含,包含的路径 vhost/下的任何.conf都能识别##
##所以等会更新的子配置文件要放到vhost/下###
###因为vhost还没有,所以我们需要创建
[root@docker conf]# mkdir /usr/local/nginx/conf/vhost
##还需要创建template模板中写的日志存放位置##
[root@docker conf]# mkdir /var/log/nginx
##做完这个时候就可以启动nginx了##
[root@docker conf]# /usr/local/nginx/sbin/nginx
[root@docker conf]# netstat -anutp | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 52639/nginx: master
###接下来让template模板起作用,####
##先解压consul-template,因为我这个时候还没安装consul-template###
将包源拖进/opt下面
[root@docker vhost]# cd /opt/
[root@docker opt]# unzip consul-template_0.19.3_linux_amd64.zip
[root@docker opt]# mv consul-template /usr/bin/
###接下来让template模板起作用###
[root@docker opt]# consul-template -consul-addr 20.0.0.21:8500 \
-template "/root/consul/nginx.ctmpl:/usr/local/nginx/conf/vhost/zzt.conf:/usr/local/nginx/sbin/nginx -s reload" \
--log-level=info
/root/consul/nginx.ctmpl模板位置
/usr/local/nginx/conf/vhost/zzt.conf 模板生成的配置文件放到的位置并起个名字叫zzt.conf
/usr/local/nginx/sbin/nginx -s reload 对nginx进行重载
--log-level=info 生成日志的级别:info(信息级别)
###执行后进入监听状态,你重新打开一个20.0.0.21的终端,看一下zzt.conf有没有生成到/usr/local/nginx/conf/vhost/下
#########如果出现报错###########
nginx: [emerg] unknown directive "server20.0.0.6:83}" in /usr/local/nginx/conf/vhost/zzt.conf:3
2020/11/16 12:00:26.042823 [ERR] (cli) 1 error occurred:
* failed to execute command "/usr/local/nginx/sbin/nginx -s reload" from "/root/consul/nginx.ctmpl" => "/usr/local/nginx/conf/vhost/zzt.conf": child: command exited with a non-zero exit status:
/usr/local/nginx/sbin/nginx -s reload
###################################
解决思路,删除vhost下面的模板配置文件,检查template模板语法问题与nginx.conf配置文件
最后发现是模板格式问题,重新编写就好了
###########################################
###生成就代表成功了#####
##使用另外一个终端查看#########
[root@docker ~]# cd /usr/local/nginx/conf/vhost/
[root@docker vhost]# ls
zzt.conf
[root@docker vhost]# vim zzt.conf
upstream http_backend {
server 20.0.0.22:83; ###地址自动被写入了
server 20.0.0.22:84;
}
server {
listen 83;
server_name localhost 20.0.0.21;
//...............................//
##查看端口是否
[root@docker vhost]# netstat -anutp | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 52639/nginx: master
tcp 0 0 0.0.0.0:83 0.0.0.0:* LISTEN 52639/nginx: master
[root@docker vhost]# netstat -anutp | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 52639/nginx: master
[root@docker vhost]# netstat -anutp | grep 83
tcp 0 0 20.0.0.21:8300 0.0.0.0:* LISTEN 48701/consul
tcp 0 0 20.0.0.21:8301 0.0.0.0:* LISTEN 48701/consul
tcp 0 0 20.0.0.21:8302 0.0.0.0:* LISTEN 48701/consul
tcp 0 0 0.0.0.0:83 0.0.0.0:* LISTEN 52639/nginx: master
tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN 1831/sshd: root@pts
tcp 0 0 20.0.0.21:44525 20.0.0.21:8300 TIME_WAIT -
tcp 0 0 20.0.0.21:22 20.0.0.1:58235 ESTABLISHED 1831/sshd: root@pts
tcp6 0 0 ::1:6010 :::* LISTEN 1831/sshd: root@pts
udp 0 0 20.0.0.21:8301 0.0.0.0:* 48701/consul
udp 0 0 20.0.0.21:8302 0.0.0.0:* 48701/consul
###打开笔记本访问浏览器,生成日志文件
###这个时候浏览器打开20.0.0.21:80 20.0.0.21:83 都能访问####
###查看访问日志###
[root@docker vhost]# cd /var/log/nginx/
[root@docker nginx]# ls
ZZT.cn-access.log
[root@docker nginx]# cat ZZT.cn-access.log
20.0.0.1 - - [15/Nov/2020:02:04:49 +0800] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36"
20.0.0.1 - - [15/Nov/2020:02:04:49 +0800] "GET /favicon.ico HTTP/1.1" 404 555 "http://20.0.0.21:83/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36"
6.验证反向代理的轮询机制
###为了验证Nginx是不是开启了反向代理,我们需要进入容器查看访问信息###
在20.0.0.22服务器操作:
###test-01和test-01是我们容器中的nginx##
[root@node ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e9c21eeafbe httpd "httpd-foreground" 2 hours ago Up 2 hours 0.0.0.0:89->80/tcp test-04
e6ce7832e809 httpd "httpd-foreground" 2 hours ago Up 2 hours 0.0.0.0:88->80/tcp test-03
3fcbe2a4d7a1 nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:84->80/tcp test-02
5821bd0c9b49 nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:83->80/tcp test-01
67582691ae53 gliderlabs/registrator:latest "/bin/registrator -i…" 2 hours ago Up 2 hours registrator
####可以看到后端是轮询访问###
[root@node ~]# docker logs -f test-01
20.0.0.21 - - [15/Nov/2020:02:04:53 +0000] "GET / HTTP/1.0" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36" "20.0.0.1"
[root@node ~]# docker logs -f test-02
2020/11/15 02:04:53 [error] 28#28: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 20.0.0.21, server: localhost, request: "GET /favicon.ico HTTP/1.0", host: "20.0.0.21", referrer: "http://20.0.0.21:83/"
20.0.0.21 - - [15/Nov/2020:02:04:53 +0000] "GET /favicon.ico HTTP/1.0" 404 555 "http://20.0.0.21:83/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36" "20.0.0.1"
7.验证自动发现与更新服务
###我再创建个nginx,创建完成后,刷新你的笔记本浏览器,在看新建的容器的访问日志###
[root@node ~]# docker run -itd -p 85:80 --name test-05 nginx
[root@node ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4dee7f087e9 nginx "/docker-entrypoint.…" 6 seconds ago Up 5 seconds 0.0.0.0:85->80/tcp test-05
4e9c21eeafbe httpd "httpd-foreground" 2 hours ago Up 2 hours 0.0.0.0:89->80/tcp test-04
e6ce7832e809 httpd "httpd-foreground" 2 hours ago Up 2 hours 0.0.0.0:88->80/tcp test-03
3fcbe2a4d7a1 nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:84->80/tcp test-02
5821bd0c9b49 nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:83->80/tcp test-01
67582691ae53 gliderlabs/registrator:latest "/bin/registrator -i…" 2 hours ago Up 2 hours registrator
##可以看到是轮询##
[root@node ~]# docker logs -f test-05
20.0.0.21 - - [15/Nov/2020:02:17:30 +0000] "GET / HTTP/1.0" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36" "20.0.0.1"
##########访问20.0.0.21:8500,可以看到consul也增加了#########
###打开20.0.0.21查看模板自动更新了###
[root@docker nginx]# cd /usr/local/nginx/conf/vhost/
[root@docker vhost]# ls
zzt.conf
[root@docker vhost]# cat zzt.conf
upstream http_backend {
server 20.0.0.22:83;
server 20.0.0.22:84;
server 20.0.0.22:85;
}
###再来验证一下容器down掉会不会自动减少####
[root@node ~]# docker stop test-01
test-01
[root@node ~]# docker rm test-01
test-01
[root@node ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f4dee7f087e9 nginx "/docker-entrypoint.…" 7 minutes ago Up 7 minutes 0.0.0.0:85->80/tcp test-05
4e9c21eeafbe httpd "httpd-foreground" 2 hours ago Up 2 hours 0.0.0.0:89->80/tcp test-04
e6ce7832e809 httpd "httpd-foreground" 2 hours ago Up 2 hours 0.0.0.0:88->80/tcp test-03
3fcbe2a4d7a1 nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 0.0.0.0:84->80/tcp test-02
67582691ae53 gliderlabs/registrator:latest "/bin/registrator -i…" 2 hours ago Up 2 hours registrator
###刷新consul页面,减少了!!!!###
###打开20.0.0.21查看模板自动更新了###
[root@docker vhost]# cat zzt.conf
upstream http_backend {
server 20.0.0.22:84;
server 20.0.0.22:85;
}
################实验完成#######################
8.consul添加多节点
//添加一台已有docker环境的服务器20.0.0.23加入到已有集群中
//将consul_0.9.1_linux_amd64.zip拖进/opt,解压完成之后,移到/usr/bin/下面
[root@docker consul]# consul agent \
-server \
-bootstrap \
-ui \
-data-dir=/var/lib/consul-data \
-bind=20.0.0.21 \
-client=0.0.0.0 \
-node=consul-server02 \
-enable-script-checks=true \
-datacenter=dc1 \
-join 20.0.0.21 &> /var/log/consul.log &
-enable-script-checks=true:设置检查服务为可用
-datacenter:已经有的数据中心名称
-join:加入到已有的群集中,所以IP要写20.0.0.21