consul python sdk

1 python

python使用服务注册和发现的说明,本人对python理解有限,不好封装sdk,熟悉的人自行封装,下面简单说一下接入的步骤

1.1 环境准备

1.下载py-consul

 
  

pip3 install py-consul

1.2 示例代码

以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.3 服务注册与取消注册

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()

1.4 服务发现

想要访问其他人的服务该怎么办

# 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.5 http api接入方式

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)

1.6 服务在线查看地址

http://xxxxx:8500/ui/rct-pegasus/services

1.7 部署环境

1.虚拟/物理机

代码里获取内网ip注册即可。

2.如果是docker

建议把宿主机的ip当成环境变量打到docker内部,然后代码获取环境变量ip

3.k8s

目前k8s通过consul调外部的服务是正常的。

但是外部的服务通过consul调k8s内的服务暂时不行

2.golang

Todo: sdk

你可能感兴趣的:(consul,python,consul,flask)