通过python应用实现Nginx的参数替换
525 次浏览
发表于 2020-06-28 14:25

        apollo是我们常用的修改nginx配置工具,但是为达到自动更新的目标,还需要写个小程序,实现配置的修改和更新,通常会采用java写个小程序直接实现nginx配置修改.如下图:


        但是在实际应用过程中,我们的nginx配置信息需要调整,且配置信息不仅仅是一个人在维护,通过java小程序的方式在协同的上存在问题,同时java程序存在开发、测试、发布等繁琐过程.

        基于以上的考虑,推荐一个java+python语言相结合的方式,可以减少java开发、发布的工作,同时java应用只需要获取配置变更信息和调用python程序执行更新动作,逻辑简化,应用的稳定性有所提升,同时通过python可以实现更便捷的应用调整.如下图:


        本文重点不解释发布的全过程,重点分享下如何用python实现读模版模版参数修改、备份、覆盖、Reload以及状态判断的过程

# 全局变量定义和初始化

    此处省略

# 参数获取

# -----------------------------
def init_common_param():
    global dic_common_param
    try:
        dic_common_param = Properties(file_common_param).getProperties()
        log.info("init_common_param success")
    except Exception as e:
        has_error = True
        log.error("init_common_param:" + traceback.format_exc())

# -----------------------------
def init_cluster_info():
    global dic_cluster_info
    try:
        dic_cluster_info = Properties(file_cluster_info).getProperties()
        # 得到集群对应代理ip地址,配置文件中是以逗号分割的,转换为List
        for k,v in dic_cluster_info["cluster_proxy_ip"].items():
            dic_cluster_info["cluster_proxy_ip"][k] = dic_cluster_info["cluster_proxy_ip"][k].replace(' ','').replace(',',',').strip(',').split(',')

        log.info("init_cluster_info success")
    except Exception as e:
        has_error = True
        log.error("init_cluster_inf" + traceback.format_exc())
# -----------------------------
def init_app_param():
    global dic_app_param
    try:
        dic_app_param = Properties(file_app_param).getProperties()
        log.info("init_app_param success")
    except Exception as e:
        has_error = True
        log.error("init_app_param:" + traceback.format_exc())

# -----------------------------
def init_switch():
    global dic_switch
    try:
        dic_switch = Properties(file_switch).getProperties()
        log.info("init_switch success")
    except Exception as e:
        log.error("init_switch:" + traceback.format_exc())

# -----------------------------
def init_release():
    global dic_release
    try:
        dic_release = Properties(file_release).getProperties()
        log.info("init_release success")
    except Exception as e:
        log.error("init_release:" + traceback.format_exc())

# -----------------------------
# 临时存放应用灰度和所有环境的变量值
dic_app_param_temp = {}

# 生成应用在nginx中的配置
def create_app_nginx_config():
    # 生成nginx配置时临时存放应用模板变量值的字典
    # 注意该字段用于为nginx规则模板填充值,因为Nginx变量不允许包含-,所以此处将key包含的-字符自动替换为_
    dic_app_tmpl_param = {}

    # 生成应用配置文件输出路径,原有的先删除
    if os.path.exists(app_config_out_path):
        shutil.rmtree(app_config_out_path,True)
        os.mkdir(app_config_out_path)

    for app in dic_common_param["app_names"].values():
        init_gray_and_env_proxy_value(app)
        # 清空模板变量字段以便重新赋值
        dic_app_tmpl_param.clear()

        # 将当前服务名加入参数字典
        dic_app_tmpl_param["app_name"] = app

        dic_app_tmpl_param["app_port"] = dic_common_param["app_ports"][app]
        # location默认为/
        dic_app_tmpl_param["location"] = "/"

        # 将环境与域名地址对应关系字典整合到目标参数字典中
        for k,v in dic_app_param_temp.items():
            dic_app_tmpl_param[k.replace("-","_")] = v

        # 将common.param中灰度变量添加到参数字典
        for k,v in dic_common_param.items():
            dic_app_tmpl_param[k.replace("-","_")] = v

        rule_tmpl = DEFAULT_RULE + ".tmpl"
        stickySession = "false"

        if dic_app_param.has_key(app):
            # 允许自定义location
            dic_app_tmpl_param["location"] = dic_app_param[app].get("location", "/")

            # 将其他自定义参数加入参数字典
            list_default_params = ["location", "rule", "stickySession", "upstream"]
            for pmName, pmValue in dic_app_param[app].items():
                if pmName not in list_default_params:
                    dic_app_tmpl_param[pmName.replace("-","_")] = pmValue

            rule_tmpl = dic_app_param[app].get("rule", DEFAULT_RULE) + ".tmpl"

        else:
            # 全部采用默认配置
            log.info("应用:" + app + "没有配置参数,全部使用默认值")

        # 输出服务的nginx配置到临时目录
        with open(rule_template_path + rule_tmpl, 'r') as f:
            s = Template(f.read())

        with open(app_config_out_path + app + ".conf", 'w') as fw:
            fw.write(s.safe_substitute(dic_app_tmpl_param))
        log.info("生成应用:" + app + "配置到临时目录成功")

# 将原有中心文件夹名加上当前时间并移动到nginx配置下的bak文件夹
def backupCurNginxConf():
    bakPath = nginx_config_path + "bak/"
    if not os.path.exists(bakPath):
        os.mkdir(bakPath)
    if os.path.exists(nginx_config_path + center_name):
        shutil.move(nginx_config_path + center_name, bakPath + center_name + "." +                 datetime.datetime.now().strftime('%Y%m%d%H%M%S'))

#将新配置移动到nginx配置路径

def moveNewCenterConfigToNginx():
    shutil.move(app_config_out_path, nginx_config_path + center_name)

#reload nginx

def reload_nginx():

    ret = subprocess.Popen('sudo systemctl reload openresty',shell=True,stderr=subprocess.PIPE)
    ret.wait()
    if ret.returncode != 0:
        log.error("reload nginx失败,nginx使用原有配置.中心:" + center_name)
        exit(7)

#主程序

def main(argv = sys.argv[1:]):
    global root_path
    global center_name
    global nginx_config_path
    root_path = cur_file_dir().rstrip('/') + "/"
    center_name = argv[0].rstrip('/')
    nginx_config_path = nginx_config_path.rstrip('/') + "/"

    try:
        init()
        init_common_param()
        init_cluster_info()
        init_app_param()
        init_switch()
        init_release()
    except Exception as e:
        log.error("初始化配置异常,网关无法生成,nginx使用原有配置.中心:" + center_name + ", error:" +             traceback.format_exc())
        exit(1)

    try:
        create_app_nginx_config()
        log.info("生成nginx配置到临时目录成功")
    except Exception as e:
        log.error("生成nginx配置异常,网关无法生成,nginx使用原有配置.中心:" + center_name + ", error:" + traceback.format_exc())
        exit(2)

    try:
        backupCurNginxConf()
        log.info("备份nginx现有配置成功")
    except Exception as e:
        log.error("备份nginx现有配置失败,取消新配置应用,nginx使用原有配置中心:" + center_name + ", error:" +             traceback.format_exc())
        exit(3)

    try:
        moveNewCenterConfigToNginx()
        log.info("将新配置移动到nginx配置路径成功")
     except Exception as e:
        log.error("将新配置移动到nginx配置路径失败,网关无法生成,nginx使用原有配置.中心:" + center_name + ",         error:" + traceback.format_exc())
        exit(4)

    try:
        reload_nginx()
        log.info("reload nginx成功")
        # 发送reload成功通知
        send_alert(5, "网关reload配置成功. 版本号:" + dic_release["release"] + ", 中心:" + center_name)
    except Exception as e:
        log.error("reload nginx失败,nginx使用原有配置.中心:" + center_name + ", error:" + traceback.format_exc())
        exit(5)
if __name__ == '__main__':
main()
exit(0)

以上范例仅供参考,由于篇幅问题,省略参数初始化部分

如果您觉得不错,就打赏支持一下吧〜
已有 1 人进行打赏
  • 0学0
发表评论
  • 0学0

    满满的干货,很实用!!

    2020-06-28 19:56
    0
    回复
发表者

李志荣

暂无个人介绍

  • 2

    文章

  • 1

    关注

  • 6

    粉丝

活动推荐
版权所有©F5 Networks,Inc.保留所有权利。京ICP备16013763号-5