python使用服务注册和发现的说明,本人对python理解有限,不好封装sdk,熟悉的人自行封装,下面简单说一下接入的步骤
1.下载py-consul
pip3 install py-consul
以flask web框架为例
# import imp
import consul
import uuid
from flask import Flask
import random
import socket
class Consul(object):
ip_list = ["172.x.x.x", "172.x.x.x", "172.x.x.x"]
port = 8506
service_id = ""
name = ""
def __init__(self):
'''初始化,连接consul服务器'''
ip = random.choice(self.ip_list)
'''宿主机ip转int,然后取模len(ip_list)当下标,从ip_list取一个consul client的地址。
这样是每台机器固定往一个client上注册
'''
self._consul = consul.Consul(ip, self.port)
def RegisterService(self, name, host, port, tags=None):
tags = tags or []
# 注册服务
self.service_id = name + "-" + ip + "-" + str(port)
self.name = name
self._consul.agent.service.register(
name,
self.service_id,
host,
port,
tags,
check=consul.Check.http("http://{0}:{1}/health".format(host, port), "5s", "3s", "20s"),
)
def UnregisterService(self):
self._consul.agent.service.deregister(self.service_id)
# 获取要访问的服务的url
def GetServiceUrl(name, path):
return "http://x.com/" + name + path
app = Flask(__name__)
#健康检查,必须
@app.route("/health")
def check_health():
return "ok!"
#容器环境内该方法不一定有效
def get_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
consul_client=Consul()
if __name__ == '__main__':
name="test-py-1" #服务名字,要唯一,建议算法除了-之外,别加别的特殊符号
host=get_ip() # 本地ip,如果是docker部署,主要是宿主机的ip
print(host)
port=9001 #服务的端口
consul_client.RegisterService(name,host,port)
app.run(host="0.0.0.0",port="9001")
consul_client.UnregisterService()
1.初始化consul client
consul_client=Consul()
2.注册自己的服务,name,ip,port
name="test-py-1" #服务名字,要唯一,除了-之外,别用其他的特殊符号
host=get_ip() # 本地ip,如果是docker部署,主要是宿主机的ip
port=9001 #服务的端口
consul_client.RegisterService(name,host,port)
#健康检查,必须有
@app.route("/health")
def check_health():
return "ok!"
注:name需要保证唯一,不同项目不同的name。
3.取消服务注册, 放到web服务器停止后。比如flask,放到app.run()下面
consul_client.UnregisterService()
想要访问其他人的服务该怎么办
# name = service-a , path="/v1/api"
def GetServiceUrl(name, path):
return "http://x.com/" + name + path
#比如说 想要访问服务a的某个录音
#拼接url
url = GetServiceUrl("service-a", "/v1/api")
#发送请求
requests.post(url, body)
1.注册服务
Method | Path | Produces |
PUT | /agent/service/register | application/json |
{
"ID": "redis1", //id, 建议服务名字+uuid test-py-1-568b06ae-8562-4193-86b3-7fdee5521a62
"Name": "redis", //必填,服务名字
"Tags": ["primary", "v1"], //非必填 tag区分
"Address": "ip", //必填 服务所在的宿主机的内网ip
"Port": 8000, //必填
"Meta": {//非必填
"redis_version": "4.0"
},
"EnableTagOverride": false,
"Check": { //必填
"DeregisterCriticalServiceAfter": "20s",//
"Http": "http://ip:port/health", //你的服务注册健康检查路由
"Interval": "5s", //健康检查间隔,参考sdk中给出的时间
"Timeout": "3s" //检查超时时间
},
"Weights": { //非必填,为空
"Passing": 10,
"Warning": 1
}
}
2.取消注册
Method | Path | Produces |
PUT | /agent/service/deregister/:service_id | application/json |
curl \ --request PUT \ http://127.0.0.1:8500/v1/agent/service/deregister/my-service-id
3.代码示例
import uuid
from flask import Flask
import random
import socket
import requests
import json
app = Flask(__name__)
ip_list = ["172.x.x.x", "172.x.x.x", "172.x.x.x"]
#健康检查,必须
@app.route("/health")
def check_health():
return "ok!"
#容器环境内该方法不一定有效
def get_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
def consul_http(url, interval, timeout=None, deregister=None, header=None):
ret = {'http': url, 'interval': interval}
if timeout:
ret['timeout'] = timeout
if deregister:
ret['DeregisterCriticalServiceAfter'] = deregister
if header:
ret['header'] = header
return ret
def ip_int(ip):
res = 0
for j, i in enumerate(ip.split('.')[::-1]):
res += 256**j*int(i)
return int(res)
def getConsulAgentAddress(num):
return ip_list[num % len(ip_list)]
consulAddress = ""
def UnRegisterService(service_id):
url = 'http://'+ consulAddress +':8506/v1/agent/service/deregister/%s' % service_id
r=requests.put(url, timeout=3)
print(url,r.status_code, r.text)
# 获取要访问的服务的url
def GetServiceUrl("intent-staging", "/v1/get"):
return "http://x.com/" + name + path
def RegisterService(name, ip, port, tags=None):
tags = tags or []
# 注册服务
service_id = name + "-" + ip + "-" + str(port)
# name = name
check = consul_http("http://{0}:{1}/health".format(ip, port), "5s", "3s", "20s")
payload = {}
payload['name'] = name
if service_id:
payload['id'] = service_id
if ip:
payload['address'] = ip
if port:
payload['port'] = port
if tags:
payload['tags'] = tags
if check:
payload['check'] = check
url = 'http://'+ consulAddress +":8506/v1/agent/service/register"
r = requests.put(url, json.dumps(payload), timeout=3)
print(url, r.status_code, r.text)
return service_id
# consul_client=Consul()
if __name__ == '__main__':
name="test-py-2" #服务名字,要唯一,建议算法除了-之外,别加别的特殊符号
host=get_ip() # 本地ip,如果是docker部署,主要是宿主机的ip
'''宿主机ip转int,然后取模len(ip_list)当下标,从ip_list取一个consul client的地址。
这样是每台机器固定往一个client上注册
'''
consulAddress = getConsulAgentAddress(ip_int(host))
print(host)
port=9001 #服务的端口
serviceId = RegisterService(name,host,port)
app.run(host="0.0.0.0",port="9001")
UnRegisterService(serviceId)
http://xxxxx:8500/ui/rct-pegasus/services
1.虚拟/物理机
代码里获取内网ip注册即可。
2.如果是docker
建议把宿主机的ip当成环境变量打到docker内部,然后代码获取环境变量ip
3.k8s
目前k8s通过consul调外部的服务是正常的。
但是外部的服务通过consul调k8s内的服务暂时不行
Todo: sdk