Python 集成 Nacos

903 阅读5分钟

如果想在 Python 项目中利用 Nacos 动态配置服务该怎么做呢?

文章有什么不对的,请各位大佬热心指导,这个很重要

1、安装依赖

nacos-sdk-python 项目是 Nacos OpenAPI 的 Python 实现,可用于监听 Nacos 配置文件的数据变动

# 安装以来
pip3 install nacos-sdk-python

项目地址: github.com/nacos-group…

2、配置文件 app.conf

[Nacos]
serverAddr = 127.0.0.1:8848
namespace = dev
serverName = my-server
username = nacos
password = nacos

3、读取配置文件

import configparser
import os
#检测配置文件是否存在
if not os.path.isfile('app.conf'):
    print("配置文件 app.conf 不存在,程序退出。")
    input("按下任意键退出...")
    exit()

try:
    # 读取配置文件
    config = configparser.ConfigParser()
    config.read('app.conf')

    # 从配置文件获取配置参数
    serverAddr = config.get('Nacos', 'serverAddr')
    namespace = config.get('Nacos', 'namespace')
    serverName = config.get('Nacos', 'serverName')
    username = config.get('Nacos', 'username')
    password = config.get('Nacos', 'password')
    gPort = config.get('Nacos', 'gPort')
except:
    print("配置文件数据不正确,请检查配置文件!")
    input("按下任意键退出...")
    exit()

Properties与 YAML 配置文件的区别是

  • YAML 使用缩进和冒号来表示层次结构
  • Properties 使用等号连接键值对

4、构建nacos的客户端

client = NacosClient(server_addresses=serverAddr, namespace=namespace, username=username, password=password)

5、服务注册到nacos

import time
import threading
def __ref_nacos_listener():
    metadata = {"gRPC.port": 10253}
    while True:
        client.send_heartbeat(service_name=serverName, ip=HostIP, metadata=metadata, port=HostPort)
        time.sleep(3)

def register_init():
    t = threading.Thread(target=__ref_nacos_listener)
    t.start()

# 启动心跳保证服务存活注册
register_init()

img.png

6、获取服务调用

import random
import requests
def __get_server_info(servername):
    response = client.list_naming_instance(servername)
    hosts = response["hosts"]
    server_info = []

    for host in hosts:
        ip = host["ip"]
        port = host["port"]
        metadata = host["metadata"]

        server_details = {
            "ip": ip,
            "port": port,
            "metadata": metadata
        }
        server_info.append(server_details)

    return random.choice(server_info)


def get_server(servername, path, params):
    s1 = __get_server_info(servername)
    url = f"http://{s1['ip']}:{s1['port']}/{path}"
    response = requests.get(url, params)
    if response.status_code == 200:
        return response.text
    else:
        print("请求异常:", response.status_code)
        return 999

def post_server(servername, path, json):
    s1 = __get_server_info(servername)
    url = f"http://{s1['ip']}:{s1['port']}/{path}"
    # 参数里的 json 类似 以JSON 格式传递,data 以 form 表单的形式
    response = requests.post(url, json=json)
    # status_code 是个固定key
    if response.status_code == 200:
        data = response.text
        return data
    else:
        print("请求异常:", response.status_code)
        return 999

7、nacos 中 config 的配置加载

global nacos_data
nacos_data ={}

# 初始化,第一次获取
def config_init(data_id, group):
    global nacos_data
    config_list  = client.get_config(data_id, group).split("\n")
    properties = {}
    for config_item in config_list:
        # 过滤有用的键值对
        if config_item.find('=') > 0:
            strs = config_item.replace('\n', '').split('=')
            properties[strs[0].replace(' ', '')] = strs[1].replace(' ', '')
    nacos_data = properties

# Nacos数据变动时触发
def __nacos_data_change_callback(config):
    global nacos_data
    # 数据解析,
    config_list = config['content'].split("\n")
    properties = {}
    for config_item in config_list:
        # 过滤有用部分
        if config_item.find('=') > 0:
            strs = config_item.replace('\n', '').split('=')
            properties[strs[0].replace(' ', '')] = strs[1].replace(' ', '')
    nacos_data = properties

# 监听Nacos数据变动
def add_nacos_listener():
    group = "DEFAULT_GROUP"
    # 初始化
    config_init(serverName, group)
    client.add_config_watcher(data_id=serverName, group=group, cb=__nacos_data_change_callback)

def get_value(key,defValue=None):
    '''获得一个全局变量,不存在则返回默认值'''
    try:
        value = nacos_data[key]
        return value
    except KeyError:
        return defValue

针对拿到数据后如何处理,更新的逻辑,大家自行完善

8、完整代码

import configparser
import os
import socket
import time
import random
import threading
import requests
from nacos import NacosClient
#检测配置文件是否存在
if not os.path.isfile('app.conf'):
    print("配置文件 app.conf 不存在,程序退出。")
    input("按下任意键退出...")
    exit()

try:
    # 读取配置文件
    config = configparser.ConfigParser()
    config.read('app.conf')

    # 从配置文件获取配置参数
    serverAddr = config.get('Nacos', 'serverAddr')
    namespace = config.get('Nacos', 'namespace')
    serverName = config.get('Nacos', 'serverName')
    username = config.get('Nacos', 'username')
    password = config.get('Nacos', 'password')
    gPort = config.get('Nacos', 'gPort')
except:
    print("配置文件数据不正确,请检查配置文件!")
    input("按下任意键退出...")
    exit()

def get_ip():
    hostname = socket.gethostname()
    ip = socket.gethostbyname(hostname)
    return ip

HostIP = get_ip()
HostPort = 8099

# 创建一个连接对象
client = NacosClient(server_addresses=serverAddr, namespace=namespace, username=username, password=password)

def __ref_nacos_listener():
    metadata = {"gRPC.port": f'{gPort}'}
    while True:
        client.send_heartbeat(service_name=serverName, ip=HostIP, metadata=metadata, port=HostPort)
        time.sleep(3)

def __register_server():
    data = {"serviceName": serverName, "ip": HostIP, "port": HostPort}
    client._inject_auth_info(data=data, headers=None, params={f'{gPort}'})


def __get_server_info(servername):
    response = client.list_naming_instance(servername)
    hosts = response["hosts"]
    server_info = []

    for host in hosts:
        ip = host["ip"]
        port = host["port"]
        metadata = host["metadata"]

        server_details = {
            "ip": ip,
            "port": port,
            "metadata": metadata
        }
        server_info.append(server_details)

    return server_info


def get_server(servername, path, params):
    server_info = __get_server_info(servername)
    s1 = random.choice(server_info)
    url = f"http://{s1['ip']}:{s1['port']}/{path}"
    response = requests.get(url, params)
    if response.status_code == 200:
        #data = response.json()
        return response.text
    else:
        print("请求异常:", response.status_code)
        return 999

def post_server(servername, path, json):
    server_info = __get_server_info(servername)
    s1 = random.choice(server_info)
    url = f"http://{s1['ip']}:{s1['port']}/{path}"
    # 参数里的 json 类似 以JSON 格式传递,data 以 form 表单的形式
    response = requests.post(url, json=json)
    # status_code 是个固定key
    if response.status_code == 200:
        data = response.text
        return data
    else:
        print("请求异常:", response.status_code)
        return 999



def register_init():
    t = threading.Thread(target=__ref_nacos_listener)
    t.start()


global nacos_data
nacos_data ={}

# 初始化
def config_init(data_id, group):
    global nacos_data
    config_list  = client.get_config(data_id, group).split("\n")
    properties = {}
    for config_item in config_list:
        # 过滤有用的键值对
        if config_item.find('=') > 0:
            strs = config_item.replace('\n', '').split('=')
            properties[strs[0].replace(' ', '')] = strs[1].replace(' ', '')
    nacos_data = properties
    # result = config_data['arg1']['arg2']
    # print(result)

# Nacos数据变动时触发
def __nacos_data_change_callback(config):
    global nacos_data
    # 数据解析,
    config_list = config['content'].split("\n")
    properties = {}
    for config_item in config_list:
        # 过滤有用部分
        if config_item.find('=') > 0:
            strs = config_item.replace('\n', '').split('=')
            properties[strs[0].replace(' ', '')] = strs[1].replace(' ', '')
    nacos_data = properties

# 监听Nacos数据变动
def add_nacos_listener():
    group = "DEFAULT_GROUP"
    # 初始化
    config_init(serverName, group)
    client.add_config_watcher(data_id=serverName, group=group, cb=__nacos_data_change_callback)



def get_value(key,defValue=None):
    '''获得一个全局变量,不存在则返回默认值'''
    try:
        value = nacos_data[key]
        return value
    except KeyError:
        return defValue

9、以Flask作为服务启动

from nacos_client import get_server,HostPort,config_init,get_value
from flask import Flask
app = Flask(__name__)

@app.route('/test/query/<int:a>', methods=['GET'])
def get_sum(a):
    params = {
        "index": a
    }
    # 通过服务名调用
    aa = get_server("server3", "userInfo/post", params)
    return aa


@app.route('/test/query', methods=['GET'])
def query():
    aa = get_value('aa')
    return aa


if __name__ == '__main__':
    # 获取配置
    config_init()
    # 服务被发现
#    nacos_init()
    app.run(host='0.0.0.0', port=HostPort)

注意 如 nacos-sdk-python 项目介绍,作者最高只对 Python3.7 及 Nacos 1.3.2做了兼容 在实际测试过程中,发现程序在 Windows 使用正常,放到 Mac 或 Linux 就报错,即 TypeE