点赞
评论
收藏
分享
举报
通过python应用实现Nginx的参数替换
发表于2020-06-28 14:25

浏览 1.5k

        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)

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

已修改于2023-03-09 02:07
创作不易,留下一份鼓励
李志荣

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(1)

按点赞数排序

按时间排序

满满的干货,很实用!!
赞同

0

回复举报

发表于2020-06-28 19:56



回复0学0
回复
关于作者
李志荣
这家伙很懒还未留下介绍~
2
文章
0
问答
6
粉丝
相关文章
1、现象:  某些服务请求响应时间有规律性波动,每分钟存在波动,在响应图上体现为明显的柱状。2、分析过程:  部署架构为两层nignx,nginx(接入层)->nginx(路由层),然后是服务层各应用集群:·    1)如下图所示,curl在服务器上调用也存在同样的问题,如下图所示,正常情况下3ms,但波动时>5s,因此调用存在nginx及后端。·    2)Curl单独调用服务层接口没有问题,因此确定问题出现在nginx。·    3)绕过接入层nginx,直接调用路由层nginx地址仍然出现,因此定位故障在路由层。·    4)路由层nginx,会在服务注册时候,定期进行relaod,从而影响性能,但通过检查linux的状态,没有发生过定期规律性的restart/reload。·    5)发现路由层ngin
点赞 5
浏览 1.9k
感谢您参加NGINX系列公开课,以下为本系列培训的课件和录像,希望您能通过此培训学有成果,祝学习进步!> 课程演讲稿下载:-8月26日: 使用NGINX/NGINXPlus构建API网关-9月23日: 使用NGINX/NGINXPlus构建CDN-10月21日: 使用NGINX/NGINXPlus构建K8SIngressController-11月25日: 使用ModSec/AppProtect模块构建NGINXWA> 视频回顾:-8月26日: 使用NGINX/NGINXPlus构建API网关-9月23日: 使用NGINX/NGINXPlus构建CDN-10月21日: 使用NGINX/NGINXPlus构建K8SIngressController-11月25日: 使用ModSec/AppProtect模块构建NGINXWA> 访问NGINX开源社区:nginx-cn.net>NGINX 官方微信群(扫码入群)> 后续活动推荐NG
点赞 8
浏览 4k
Nginx处理每一个用户请求时,都是按照若干个不同阶段(phase)依次处理的,而不是根据配置文件上的顺序。Nginx处理请求的过程一共划分为11个阶段,按照执行顺序依次是:post-read、server-rewrite、find-config、rewrite、post-rewrite、preaccess、access、post-access、try-files、content、log. Nginx处理请求的过程一共划分为11个阶段,按照执行顺序依次是post-read、server-rewrite、find-config、rewrite、post-rewrite、preaccess、access、post-access、try-files、content以及log。 1、post-read 最先执行的post-read阶段在Nginx读取并解析完请求头(requestheaders)之后就立即开始运行。例如:使用了ngx_realip模块提供的set_real_ip_from和real_ip_header这两条配置指令 2
点赞 0
浏览 1k