博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
openstack 扩展开发最佳实践之计算节点高可用
阅读量:6139 次
发布时间:2019-06-21

本文共 6002 字,大约阅读时间需要 20 分钟。

前言:注意是扩展开发,这个词是我杜撰的,大概意思是指基于openstack的rest api做的一些开发,用于辅助相关功能,而不是直接改动openstack内的代码,怎么修改添加openstack各个组件的代码不在此文章内容内。

  

  首先,千万,千万,千万不要用Openstack提供的SDK,原因如下。

  一,SDK的相关文档并不健全。

  二,版本不够统一,即兼容的问题。

  

   所以不要使用openstack的SDK而是自己查阅openstack的API文档,通过requests库发http请求要比SDK灵活并便捷得多的方式。但是难过的地方在于开头,这也是本章的主要内容。为了使内容更加贴近现实,我们要做的需求是Openstack计算节点的高可用,主题内容如下:

    一:解决思路

    二:查询相关API

    三:组织代码

    四:总结

(一)解决思路

    其实openstack计算节点高可用的方案应该是不同的厂商有不同解决方案,这里不具体分析各个方案,二是针对笔者自己实现的一个方案的实现讲解。

    一,怎样确定计算节点挂了

    二,怎样将计算节点上的虚拟机迁移到现存可用的计算节点

    三,迁移之后是否应该采取相关措施

   

    笔者的对应的解决方案如下,

    一:通过openstack自身机制监控,即计算节点不可用时,不会上报状态,控制节点会将该计算节点的状态state设置为down,为down的就判定该计算节点不可用。

    二:通过evacuate API将不可用的计算节点上的虚拟机迁移到可用的计算节点,共享存储肯定是必须的。

    三:通过将该不可用计算节点status设置为disable,以达到隔离效果,即该计算节点即使又好了,也不会将新的虚拟机调度到该计算节点,除非人为干预。

    注:这里没有考虑网络环境。

(二)查询相关API

    一:所有计算节点可用状态:/os-services

    二:查询指定计算节点上的虚拟机:/servers/detail

    三:evacuate实例:/servers/<server-id>/action

    四:disable阶段节点:/os-services/disable

    主要就是上面这些API了。

(三)组织代码

    1.首先是认证获取token,获取各个endpoint。

    2.统一封装HTTP请求过程。

    3.然后为每个对应的API封装一个函数。

    4.将整个需求的逻辑独立与封装的函数及类。

    相对应的代码如下

    1.这里新建一个baseInfo的类作为基类,用于获取token及相应的endpoint

class baseInfo(object):    """init the info of all compute, and get the token for access the api"""    def __init__(self):        confFile = sys.argv[1]        headers = {}        headers["Content-Type"] = "application/json"        self.cf = ConfigParser()        self.cf.read(confFile)        self.conf = self.getConf()        self.headers = headers        self.catalog, self.token = self.getToken()        self.url = [url for url in self.catalog if url["name"] == "nova"]        self.url = self.url[0]["endpoints"][0]["publicURL"]    def getConf(self):        try:            conf = {                "url": self.cf.get("ser","OS_AUTH_URL"),                "uname" : self.cf.get("ser","OS_USERNAME"),                "passwd" : self.cf.get("ser","OS_PASSWORD"),                "tname" : self.cf.get("ser","OS_TENANT_NAME"),                "interval" : self.cf.get("ser","INTERVAL")}        except Exception as e:                logging.critical("加载配置文件失败")                logging.critical(e)                sys.exit(1)        return conf    def getToken(self):        headers = self.headers        url = self.conf["url"] + "/tokens"        data = '{"auth": {"tenantName": "%s", "passwordCredentials": {"username": "%s", "password": "%s"}}}'        data = data % (self.conf["tname"], self.conf["uname"], self.conf["passwd"])        try:            logging.debug("开始获取Token")            ret = requests.post(url, data=data, headers=headers)            logging.debug("request url:%s" % ret.url)            ret = ret.json()        except Exception as e:            msg = "获取Token失败 data:%s headers:%s" % (data, headers)            logging.critical(msg)            logging.critical(e)        catalog = ret["access"]["serviceCatalog"]        token = ret["access"]["token"]["id"]        return catalog, token

    2.将每个交互API的HTTP请求独立出来,所谓DRY吧,不要重复你自己,这样的好处自然是不用重复写代码,再者就是在一个统一的地方对所有调用了的,统一包装或修改。

    def getResp(self, suffix, method, data=None, headers=None, params=None, isjson=True):        """return the result of requests"""        url = self.url + suffix        if headers == None:            headers = self.headers.copy()        headers["X-Auth-Token"] = self.token        req = getattr(requests, method)        try:            ret = req(url, data=data, headers=headers, params=params, verify=False)            logging.debug("request url:%s" % ret.url)        except Exception as e:            msg = "%s访问%s失败 data:%s headers:%s" % (method, suffix, data, headers)            logging.critical(msg)            logging.critical(e)            sys.exit(1)        if ret.status_code == 401:            logging.warning("Token 过期,重新获取Token")            self.catalog, self.token = self.getToken()            headers["X-Auth-Token"] = self.token            logging.debug("request headers:%s" % ret.request.headers)            ret = req(url, data=data, headers=headers)        if isjson:            ret = ret.json()        return ret

    3.封装每个API作为函数,函数是第一公民嘛。

...    def chkNode(self):        """get the compute list service down"""        suffix = "/os-services"        ret  = self.getResp(suffix, "get")        ret = ret["services"]        cmpAll = [host["host"] for host in ret if host["binary"] == "nova-compute"]        cmpDown = [host["host"] for host in ret if host["state"] != "up" and host["binary"] == "nova-compute"]        return cmpDown, cmpAll    def chkSerFromNode(self):        """get the server list from failed node"""        suffix = "/servers/detail"        params = {"all_tenants":1}        ret = self.getResp(suffix, "get", params=params)        ret = ret["servers"]        serDown = [ser["id"] for ser in ret if ser["OS-EXT-SRV-ATTR:host"] in self.cmpDown]        self.serDown.extend(serDown)            def evacuate(self, serID):        """evacuate the server"""        suffix = "/servers/%s/action" % serID        data = '{"evacuate": {"onSharedStorage": "True"}}'        ret = self.getResp(suffix, "post", data=data, isjson=False)        return ret.ok...

    4.逻辑独立出来,不要做太多事情。

def main():    if len(sys.argv) > 1 and os.path.isfile(sys.argv[1]):        ch = check()        fen = fence()        recov = recover()        while True:            interval = ch.conf["interval"]            try:                interval = int(interval)            except Exception as e:                msg = "时间间隔设置有误 interval:%s" % interval                logging.critical(msg)                logging.critical(e)                sys.exit(1)            cmd = "pcs status|grep 'Current DC'|grep `hostname`"            p = sp.Popen(cmd, shell=True, stdout=DEVNULL, stderr=sp.STDOUT)            vip = p.wait()            if not vip:                ch.check()                logging.info("失败的计算节点%s" %ch.cmpDown)                fen.fence(ch.cmpDown)                logging.info("失败的计算节点下面的server %s" %ch.serDown)                recov.recover(ch.serDown)            time.sleep(interval)    else:        print "配置文件不存在"

(四)总结

    不要用SDK,rest API的文档足够健全。

    

    至于完整项目可参考我的Github。

    

相关链接:

Openstack API:

转载地址:http://vbkya.baihongyu.com/

你可能感兴趣的文章
聊聊flink的BlobStoreService
查看>>
洗牌算法具体指的是什么?
查看>>
HBuilder打包手机app的方法
查看>>
解决Mac下SSH闲时自动中断的问题
查看>>
在JavaScript中理解策略模式
查看>>
ArchSummit 深圳 2017 成功举办,探索未来互联网架构
查看>>
不知道如何提升深度学习性能?我们为你整理了这份速查清单
查看>>
Go 2提上日程,官方团队呼吁社区给新特性提案提交反馈
查看>>
技术绩效考量:你们可能都做错了
查看>>
“亲切照料”下的领域驱动设计
查看>>
除了输入法,移动端AI还有哪些想象空间?
查看>>
回家路上想起来关于Js一个有趣的东西
查看>>
B端大数据应用的架构实践与思考
查看>>
2019 SRE 调查报告:事故处理是主要工作,SRE 压力山大
查看>>
React创建组件的三种方式及其区别
查看>>
大中型企业的天网:Apache Geode
查看>>
Windows Server已可安装Docker,Azure开始支持Mesosphere
查看>>
本地部署比SaaS更容易满足GDPR要求吗?
查看>>
业内预测:2017中国光通信设备规模将达近千亿元
查看>>
网页开发从业者仍更重视桌面程序及网页应用
查看>>