Consul系列:实战演练
实战演练
可以解决什么样的线上问题?
-
问题A:在线服迁移、需要修改配置文件并重启服务生效。
-
方案A:可直接使用consul服务自动注册+域名发现功能,使用内部域名替代ip,dns解析动态实时生效,维护不需要做任何变更。
-
问题B:HA等服务在rs地址增删改后需要修改配置文件并重启服务,增加操作环节,生效时间长。
-
方案B: 使用consul的服务自动注册发现+配置文件动态化管理,实现配置文件根据注册的服务自行调整,并进行例如重启服务等可执行操作,动态实时自动化 的运维管理。
-
问题C:业务故障,需要手动处理。
-
方案C: consul自带健康检查(check)及信息监控(watch)功能,可实现服务异常时做故障自愈及更多的自动化流程。
总结:consul除了上面列出的几个以外,例如监控、故障自愈、服务自动切换等等运维自动化都是可以实现的方向。
注册服务
域名服务相关依赖及部署
consul的DNS功能只支持了其内部的注册及解析,要想其他外部服务也可使用,需要将其作为一个本地dns代理使用,这样既可以不影响正常的dns解析,也可以访问 consul的dns解析。
Dnsmasq Setup
- /etc/dnsmasq.d/10-consul
# Enable forward lookup of the 'consul' domain:
server=/consul/127.0.0.1#8600
#这里根据实际情况设置为你的本地consul DNS地址.
/# Uncomment and modify as appropriate to enable reverse DNS lookups for
# common netblocks found in RFC 1918, 5735, and 6598:
#rev-server=0.0.0.0/8,127.0.0.1#8600
#rev-server=10.0.0.0/8,127.0.0.1#8600
#rev-server=100.64.0.0/10,127.0.0.1#8600
#rev-server=127.0.0.1/8,127.0.0.1#8600
#rev-server=169.254.0.0/16,127.0.0.1#8600
#rev-server=172.16.0.0/12,127.0.0.1#8600
#rev-server=192.168.0.0/16,127.0.0.1#8600
#rev-server=224.0.0.0/4,127.0.0.1#8600
#rev-server=240.0.0.0/4,127.0.0.1#8600
- /etc/resolv.conf
# THIS FILE IS AUTOMATICALLY GENERATED BY PUPPET.
# DO NOT EDIT THIS FILE.
domain i.example.net
nameserver 127.0.0.1
nameserver 42.186.69.116
nameserver 42.186.72.87
Testing
- 直接向consul查询其中的一个服务域名是否已经存在。
root@localhost:~/consul/conf$ dig @localhost -p 8600 web.service.consul. A
; <<>> DiG 9.9.5-9+deb8u14-Debian <<>> @localhost -p 8600 web.service.consul. A ; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41515
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION: ;web.service.consul. INA
;; ANSWER SECTION:
web.service.consul. 0 IN A 10.120.184.243
web.service.consul. 0 IN A 10.120.184.216
;; Query time: 1 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Tue Aug 07 14:47:14 CST 2018
;; MSG SIZE rcvd: 79
- 使用默认的dns接口查询该服务域名,是否可以正常解析。
root@localhost:~/consul/conf$ dig @localhost -p 53 web.service.consul. A
; <<>> DiG 9.9.5-9+deb8u14-Debian <<>> @localhost -p 53 web.service.consul. A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58951
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;web.service.consul. INA
;; ANSWER SECTION:
web.service.consul. 0 IN A 10.120.184.243
web.service.consul. 0 IN A 10.120.184.216
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Tue Aug 07 14:48:29 CST 2018
;; MSG SIZE rcvd: 79
其他平台域名相关部署访问详见官网
域名服务自动注册测试
自定义check
root@localhost:~/consul/conf$ cat http.json
{
"service": {
"name": "web",
"tags": ["test web site"],
"port": 8099,
"check": {
"id": "web",
"name": "web on port 8099",
"tcp": "localhost:8099",
"interval": "10s",
"timeout": "1s"
}
}
}
重载
consul reload
域名切换服务测试访问情况
多台agent节点开启一个web端口,并注册服务(有端口健康检查)。
模拟其中一个服务变更为另外一个域名并更新注册服务后,全部请求都到了其他可用节点。
root@localhost:~# watch "curl -s web.service.consul:8099/a"
模拟其中一个服务挂掉,会立即被server踢掉故障节点,请求到了另外一个可用节点。
配置文件动态管理
服务注册
#刷新注册服务信息
consul reload --http-addr=10.120.169.72:8500
/#服务注册json简单样例
root@localhost:~/consul/conf$ cat test.json
{
"service": {
"name": "test",
"tags": ["test service"],
"port": 31030,
"address": "10.120.169.723",
"id": "test",
"check": {
"id": "api",
"http": "http://123.58.169.72:31030",
"interval": "3s"
}
}
}
watch 监控项配置
- 方法一:命令行后台执行
consul watch -type=service -service=g10 -http-addr=10.120.169.72:8500 /home/push/consulbin/test.py
- 方法二:配置文件加载。
root@localhost:~/consul/conf$ cat watch.json
{
"watches": [{
"type": "service",
"service": "g10",
"handler_type": "script",
"args": ["python", "/home/push/consul/bin/watch.py"]
}]
}
telmplate配置文件动态管理
- 方法一:命令行操作
consul-template -consul-addr 127.0.0.1:8500 -template "/home/test/ha_test.ctmpl:/home/test/ha_test.conf:echo 'test'>a.lo g" -once
- 方法二:嵌入watch结合使用.
#监控服务,自动生成ctmpl模版,并触发consul-template实现动态模版管理.
root@localhost:~/consul/bin$ cat watch.py
#!/usr/bin/python
#coding:utf8
import sys
import json
import os
a=json.loads(raw_input())
for k in a:
for key in k:
print key
print k[key]
if key == "Service":
print k[key]["Service"]
print k[key]["Port"]
print k[key]["Address"]
log_format="log-format %si:%sp/ %ci/ %ft/ %hrl/ %r/ %ST/ %B/ %Tt"
ctmpl_content = """
global
daemon
maxconn 30000
pidfile /home/push/var/run/haproxy/pid/%s_uq.pid
stats socket /home/push/var/run/haproxy/sock/%s_uq.sock mode 644
log /dev/log local7 info
defaults
mode http
log global
option httpclose
maxconn 30000
timeout connect 300s
timeout client 300s
timeout server 300s
balance roundrobin
listen {{.Name}}
option httplog
fullconn 30000
bind *:30010
%s
{{range service /"%s/"}}
server {{.Name}}-uniqush {{.Address}}:{{.Port}} maxconn 30000 check inter 2000 addr {{.Address}} port {{.Port}}{{end}}"""%(k[k ey]["Service"], k[key]["Service"], log_format, k[key]["Service"])
os.system("echo '''%s'''>>/home/push/consul/conf/%s.ctmpl"% (ctmpl_content, k[key]["Service"]))
cmd = "/"/home/push/consul/conf/" + k[key]["Service"] + ".ctmpl:/home/push/consul/conf/" + k[key]["Service"] + ".conf" + ":echo test>a.log/"" + "-once"
os.system("/usr/local/bin/consul-template -consul-addr 127.0.0.1:8500 -template %s &" % cmd)
template样例
{{range service "test"}}
{{.ID}}
server {{.Name}}-uniqush {{.Address}}:{{.Port}} maxconn 30000 check inter 2000 addr {{.Address}} port {{.Port}}{{end}}
template语法
datacenters:在consul目录中查询所有的datacenters,{{datacenters}}
file:读取并输出本地磁盘上的文件,如果无法读取,则报错,{{file "/path/to/local/file"}} key:查询consul中该key的值,如果无法转换成一个类字符串的值,则会报错,{{key "service/redis/maxconns@east-aws"}} east-aws指定的是数据中心,{{key "service/redis/maxconns"}}
key_or_default:查询consul中该key的值,如果key不存在,则使用指定的值代替,{{key_or_default "service/redis/maxconns@east-aws" "5"}}
ls:在consul中查询给定前缀的key的顶级域值,{{range ls "service/redis@east-aws"}} {{.Key}} {{.Value}}{{end}}
node:查询consul目录中的单个node,如果不指定node,则是当前agent的,{{node "node1"}}
nodes:查询consul目录中的所有nodes,你也可以指定datacenter,{{nodes "@east-aws"}}
service:查询consul中匹配的service组,{{service "release.web@east-aws"}}或者{{service "web"}},也可以返回一组HealthService服务{{range ser vice "web@datacenter"}} server {{.Name}} {{.Address}}:{{.Port}}{{end}},默认值返回健康的服务,如果你想返回所有服务,则{{service "web" "any "}}
services:查询consul目录中的所有services,{{services}},也可以指定datacenter:{{services "@east-aws"}}
tree:查询consul中给定前缀的所有K/V值,{{range tree "service/redis@east-aws"}} {{.Key}} {{.Value}}{{end}}
精细化的权限控制(ACL)
首先我们需要在leader节点上去请求获取一个Bootstrap Token,用这个token为基础生成management token配置给给其他节点,开启ACl功能。
请求:curl --request PUT http://127.0.0.1:8500/v1/acl/bootstrap
返回:{"ID":"5616a0e6-19df-0d47-8250-fe6d1d58c8fc"}
ACL配置
- 首先在所有的server节点增加acl配置(需要注意的是,所有的server都需要配置并重启consule生效。例如只配置单个server,会无效)
#server节点增加一个json结尾的acl文件
root@localhost:~/consul/conf$ cat acl_consul.json
{
"acl_master_token": "5616a0e6-19df-0d47-8250-fe6d1d58c8fc",#自定义一个token, 无太多要求
"acl_datacenter": "dc1", #需要做acl的数据中心
"acl_default_policy": "deny", #开启acl, 默认都被deny
"acl_down_policy": "deny"# 在无法从acl_datacenter 或 leader 节点读取 token 的策略的情况下, 应用向下策略, deny 限制所有操作。
}
-
重启所有的consul server将配置生效。
-
查看,会发现所有的server节点的ui等权限都已经被deny。
- 获取一个初始的agent token(这里我基本给了所有权限)
请求: curl -H "X-Consul-Token: secret" -X PUT -d '{"Name": "dc1", "Type": "management"}' http://127.0.0.1:8500/v1/acl/create?token =5616a0e6-19df-0d47-8250-fe6d1d58c8fc
返回(不同节点返回的会不一样):{"ID":"df9aec62-96c3-4cb6-3f38-899d79e24112"}
获取agent token后进行acl权限(acl_token对应不同权限)配置,并重启所有配置过的consule服务,将修改生效。
root@localhost:~/consul/conf$ cat acl_consul.json
{
"acl_master_token":"d9f1928e-1f84-407c-ab50-9579de563df5", "acl_datacenter":"dc1",
"acl_default_policy":"deny",
"acl_down_policy":"deny", "acl_token":"df9aec62-96c3-4cb6-3f38-899d79e24112"
}
- 查看,初始的acl策略,通过配置文件配置生成获取。
- 通过bootstrap获取的acl token。
ACL策略控制
- 创建一个新的acl控制,期望完成自己期望的一些权限控制。
- 新建后会提供一个对应权限的token值,将该值配置到对应的consul节点的acl token参数,重启consul服务,即可实现自定义的权限控制。
#更新配置文件token参数值,如下client角色其中一个节点配置
root@localhost:~/consul/conf$ cat /home/test/consul/conf/acl_consul.json
{
"acl_datacenter":"dc1",
"acl_token":"ab351531-84d5-7286-515e-2731ee4a66f5"
}
测试
- 测试1:根据之前的acl权限设置,符合acl的控制,只允许读,不允许写入。
root@localhost:~/consul/conf$ curl -X PUT -d 'test' http://10.170.17.28:8500/v1/kv/web
rpc error making call: rpc error making call: Permission denied
root@localhost:~/consul/conf$ curl -X GET -d 'test' http://10.170.17.28:8500/v1/kv/web
[{"LockIndex":0,"Key":"web","Flags":0,"Value":"dGVzdA==","CreateIndex":96048,"ModifyIndex":96234}]
- 测试2:修改权限允许读写,立即生效。
#立即生效。
root@localhost:~/consul/conf$ curl -X PUT -d 'test' http://10.170.17.28:8500/v1/kv/web
true
- 测试3:限定某个token的权限的某个service不可访问,DNS都无法解析。
ACL权限恢复
发现UI等因为token无法访问时,可以通过acl默认token设置来恢复访问。
多数据中心实现
- 加入其他数据中心。
#可命令行等指定另外数据中心的一个server节点。
consul join -wan 其他数据中心的server节点
#也可以配置文件
retry_join_wan":[ "dc2-server-1", ... "dc2-server-N" ]
- 命令行参数
脏数据数据清理
根据service状态查询
判断servicesf是否是passing状态。返回[],则是failing,非空即为passing状态。
#service
cur http://127.0.0.1:8500/v1/health/service/服务名?passing
#node
cur http://127.0.0.1:8500/v1/health/node/节点名?passing
Removing Servers
- 服务实例只能在注册的Agent上进行注销!
curl -X PUT http://server_ip:8500/v1/agent/service/deregister/服务名
- 删除的方式可以是如上的api方式,也可以是删除json文件,并重载的方式即可。
Removing Nodes
-
In general, if you are ever adding and removing nodes simultaneously, it is better to first add the new nodes and then remove the old nodes.
-
尝试过api删除无效、但是在新的节点进行替换node名是可行的,需要重启consul服务重新注册到servers生效。
auto removing servies
- crontab + shell
#/usr/bin/python
#coding:utf-8
import requests
import json
import sys
import time
import gpost
check_url = "http://127.0.0.1:8500/v1/agent/services"
result = json.loads(requests.get(check_url).content)
def msg_send(msg):
msg = msg
gpost.blackhole(data={'type':'push_consul_check'},msg=msg)
def check_galaxy(groupCode):
.......
for ServerName in result.keys():
try:
#查询本节点上点所有service,如果是failing状态,则值为[]。
services_info = requests.get("http://127.0.0.1:8500/v1/health/service/%s?passing"%ServerName).content
if services_info == "[]":
msg = "Service %s will be delete after 8h."%ServerName
#从galaxy查询该服务是否真的已下线,否者进行delete操作
check_galaxy(ServerName)
msg_send(msg)
time.sleep(28800)
delete_url = "http://127.0.0.1:8500/v1/agent/service/deregister/%s"%ServerName
delete_cmd=requests.put(delete_url)
if delete_cmd.status_code == 200:
msg = " %s deletc ok."%ServerName
msg_send(msg)
else:
msg = "Service %s delete fail,please check!"
msg_send(msg)
sys.exit(1)
except Exception, e:
gpost.blackhole(data={'type':'push_consul_check'},msg=e)
更多文章:
Consul系列:让服务Running in anywhere
Consul系列:业务系统微服务化实践
Consul系列:基于Consul的自动化应用实践
Consul系列:实战演练
Consul系列:什么是Consul?
Consul系列:Consul实现详解
Consul系列:Consul Server部署及用法介绍
Consul系列:Consul Agent部署
Consul系列:Consul Agent用法介绍(一)
Consul系列:Consul Agent用法介绍(二)
Consul系列:Consul Agent用法介绍(三)
Consul系列:Consul Agent用法介绍(四)
Consul系列:Consul Agent用法介绍(五)
Consul系列:Consul API用法介绍
Consul系列:Consul Registrator介绍
Consul系列:Consul Connect介绍
Consul系列:Consul集群运维指引
Consul系列:Consul监控介绍
Consul系列:模版渲染与ACL控制
共有 0 条评论