Nginx平滑升级

Nginx平滑升级

平滑升级说明

有时候我们需要对Nginx版本进行升级以满足对其功能的需求,例如添加新模块,需要新功能,而此时 Nginx又在跑着业务无法停掉,这时我们就可能选择平滑升级

  • 平滑升级:即业务无感知的版本迭代
  • 数据安全:不会强制中断事务的运行,而是等待事务完成运行后,在结束进程
平滑升级步骤流程

在这里插入图片描述

  • 将旧Nginx二进制文件换成新Nginx程序文件(注意先备份)
  • 向master进程发送USR2信号
  • master进程修改pid文件名加上后缀.oldbin,成为nginx.pid.oldbin
  • master进程用新Nginx文件启动新master进程成为旧master的子进程,系统中将有新旧两个Nginx,主进程共同提供Web服务,当前新的请求仍然由旧Nginx的worker进程进行处理,将新生成的master 进程的PID存放至新生成的pid文件nginx.pid
  • 向旧的Nginx服务进程发送WINCH信号,使旧的Nginx worker进程平滑停止
  • 向旧master进程发送QUIT信号,关闭老master,并删除Nginx.pid.oldbin文件
  • 如果发现升级有问题,可以回滚∶向老master发送HUP,向新master发送QUIT
平滑升级步骤
#下载新软件包
wget -P /var/download  http://nginx.org/download/nginx-1.20.2.tar.gz
#获取编译参数(推荐用变量)
Edit=$(/usr/sbin/nginx -V |& awk -F"[:]" '/^configure/{print $2}')
/usr/sbin/nginx -V |& awk -F"[:]" '/^configure/{print $2}' > /apps/oldoptions.txt
#解压包
tar -xvf  /var/download/nginx-1.20.2.tar.gz  -C /apps/
#编译功能参数
cd /apps/nginx-1.20.2 && ./configure $Edit
#编译安装
make
#查看当前版本
objs/nginx -v
#备份旧版本nginx命令
mv /apps/nginx/sbin/nginx{,.old}
#复制新版本nginx命令过去
cp ./objs/nginx /apps/nginx/sbin/
#测试配置
/apps/nginx/sbin/nginx -t |& grep -q "successful"  || echo "失败"
#USR2 平滑升级可执行程序,将存储有旧版本主进程PID的文件重命名为nginx.pid.oldbin,并启动新的nginx
#此时两个master的进程都在运行,只是旧的master不在监听,由新的master监听80
#此时Nginx开启一个新的master进程,这个master进程会生成新的worker进程,这就是升级后的Nginx进程,此时老的进程不会自动退出,但是当接收到新的请求不作处理而是交给新的进程处理。
#发送信号USR2,即平滑升级信号,会开启新的master,但不会关闭旧的master进程
kill -USR2 `cat /apps/nginx/run/nginx.pid`
##先关闭旧nginx的worker进程,而不关闭nginx主进程方便回滚
#向原Nginx主进程发送WINCH信号,它会逐步关闭旗下的工作进程(主进程不退出),这时所有请求都会由新版Nginx处理
#如果旧版worker进程有用户的请求,会一直等待处理完后才会关闭
kill -WINCH `cat /apps/nginx/run/nginx.pid.oldbin`
#发出关闭信号,结束旧的master进程(推荐生成计划任务,等一周后执行)
date=$(date "+%u")
tee /etc/cron.d/nginx_cron <<EOF
* * * * $date root kill -QUIT `cat /apps/nginx/run/nginx.pid.oldbin`
EOF

#测试
#在nginx服务端,生成1GB大小的资源
dd if=/dev/zero of=test.img bs=1M count=1024
#在客户端限制下载速度,然后下载保持持续链接
wget --limit-rate=1k http://192.168.213.123/test.img


#回滚,结束旧的master进程才可执行
#回滚判断点:判断旧的master进程是否还存在,若不存在则不允许回退,若存在,则允许回退,并拉起旧进程,关闭新进程(前提:关闭业务)
kill -HUP `cat /apps/nginx/run/nginx.pid.oldbin`
kill -WINCH `cat /apps/nginx/run/nginx.pid`
#关闭新版的master进程
kill -QUIT `cat /usr/nginx/run/nginx.pid`
平滑升级回滚步骤
#在关闭旧master进程之前均可以回滚
#如果升级的版本发现问题需要回滚,可以重新拉起旧版本的worker进程
kill -HUP `cat /apps/nginx/run/nginx.pid.old`
#关闭新版本master
kill -QUIT `cat /apps/nginx/run/nginx.pid`
平滑升级&回滚脚本

该脚本当前只支持CentOS 7.X,且未包含回滚部分

#!/bin/bash
Install_Url=/apps/nginx
Upgrade_PkName="nginx-1.20.2"
Grt_url="http://nginx.org/download"
Pack_url="/var/download"
Suffix=tar.gz
new_version=$(echo ${Upgrade_PkName}|awk -F"[.]" '{print $2}')
old_version=$(nginx -V |& sed -rn "s/.*\/.\.(.*)\../\1/p")



function color_title()
{

    title_color="echo -en  \\033[01;34m"
    title_end="echo -en \E[0m"
    [ "$2" = 0 ] && ${title_color} 
    echo "$1"
    ${title_end}
}
function color_sign()
{
    RES_COL=60
    MOVE_TO_COL="echo -en \\033[${RES_COL}G"
    Clock_red="echo -en   \\033[01;31m"
    clock_green="echo -en  \\033[01;32m"
    Clock_yellow="echo -en  \\033[01;33m"
    Clock_end="echo -en \E[0m"
    echo -n "$1" && $MOVE_TO_COL
    echo -n "["
    if [ "$2" = "success" ] || [ "$2" = "0" ];then
        ${clock_green}
        echo -n $"OK "
    elif [ "$2" = "failure" ] || [ "$2" = "1"  ];then 
        ${Clock_red}#!/bin/bash
Install_Url=/apps/nginx
Upgrade_PkName="nginx-1.20.2"
Grt_url="http://nginx.org/download"
Pack_url="/var/download"
Suffix=tar.gz
new_version=$(echo ${Upgrade_PkName}|awk -F"[.]" '{print $2}')
old_version=$(nginx -V |& sed -rn "s/.*\/.\.(.*)\../\1/p")



function color_title()
{

    title_color="echo -en  \\033[01;34m"
    title_end="echo -en \E[0m"
    [ "$2" = 0 ] && ${title_color} 
    echo "$1"
    ${title_end}
}
function color_sign()
{
    RES_COL=60
    MOVE_TO_COL="echo -en \\033[${RES_COL}G"
    Clock_red="echo -en   \\033[01;31m"
    clock_green="echo -en  \\033[01;32m"
    Clock_yellow="echo -en  \\033[01;33m"
    Clock_end="echo -en \E[0m"
    echo -n "$1" && $MOVE_TO_COL
    echo -n "["
    if [ "$2" = "success" ] || [ "$2" = "0" ];then
        ${clock_green}
        echo -n $"OK "
    elif [ "$2" = "failure" ] || [ "$2" = "1"  ];then 
        ${Clock_red}
        echo -n $"FAILED"
    else
        ${Clock_yellow}
        echo -n $"WARNING"
    fi
    ${Clock_end}
    echo -n "]"
    echo 
}

function os_type()
{
    awk -F'[ "]' '/^NAME/{print $2}' /etc/os-release
}

function os_version()
{
    awk -F'"' '/^VERSION_ID/{print $2}' /etc/os-release
}

function check()
{
    #OS判断
    if [ ! "$(os_type)" == "CentOS" ] && [ ! "$(os_version)" == "7" ];then
        color_sign "当前版本不支持" 1
        exit 
    fi
    #判断版本大小,若new小于old则不升级
    if [ "$new_version" -le "$old_version" ];then        
            color_sign "升级失败,当前已安装版本比目标版本新" 1 
            exit
    fi
}

function Upgrade()
{
    color_title "###############Nginx版本平滑升级开始###############" 0
    
    color_title "----------获取编译参数----------" 0
    Edit=$(/usr/sbin/nginx -V |& awk -F"[:]" '/^configure/{print $2}')
    [ -n "$Edit"  ] && echo "当前参数为$Edit"

    color_title "----------软件包处理----------" 0
    if [ -f "$Pack_url/$Upgrade_PkName.$Suffix" ];then  
        color_sign "$Upgrade_PkName已存在,正常升级" 0
    else
        wget -P $Pack_url "$Grt_url/$Upgrade_PkName.$Suffix" || exit 1
        color_sign "下载$Upgrade_PkName完成" 0
        tar -xvf  /var/download/nginx-1.20.2.tar.gz  -C $Pack_url && color_sign"解压$Upgrade_PkName完成" 0
    fi
    
    color_title "----------编译软件包----------" 0
    cd ${Pack_url}/${Upgrade_PkName} || exit
    ./configure $Edit && make
    #备份旧的命令文件
    mv $Install_Url/sbin/nginx{,.old}
    #复制新版本nginx命令
    cp ./objs/nginx ${Install_Url}/sbin/
    #测试
    nginx -t |& grep -q "successful" && color_sign "编译完成" 0
}

function process_handling()
{
    #获取旧master进程下的所有worker进程
    old_subprocess=$(pstree -p  "$(cat $Install_Url/run/nginx.pid)" |sed -rn "s/.*\(([0-9]+)\)$/\1/p")
    #发送平滑升级信号
    kill -USR2 "$(cat $Install_Url/run/nginx.pid)"
    old_process=$(cat $Install_Url/run/nginx.pid.oldbin)
    read -r -p "是否马上关闭旧的nginx进程(y/n)" Options_2
    case $Options_2 in 
    Y|y)
        #等待事务结束后关闭旧的Nginx进程
        kill -WINCH "$(cat $Install_Url/run/nginx.pid.oldbin)"
        while :;do
            Count=$( echo "$old_subprocess"|wc -l )
            for i in ${old_subprocess};do
                pgrep nginx |grep "$i" || (( Count-- ))
            done
                [ "$Count" -eq 0 ] && break
                sleep 3
        #    old_subprocess=$(pstree -p  "$(cat $Install_Url/run/nginx.pid.oldbin)" |awk -F"[+|\`]" '{print $3}')
        #    [ -z "$old_subprocess" ]  && break
        done
        kill -QUIT "$old_process"
        sleep 10
        pgrep nginx |grep -q "$old_process" || color_sign "升级完成" 0
        #这里如果设置了server_tokens off这个参数,则无法获取
        echo "当前版本:$(curl -I 127.0.0.1 |& sed -rn "s/^Server: (.*)/\1/p")"
    ;;
    N|n)
        #等待事务结束后关闭旧的Nginx进程
        kill -WINCH "$(cat $Install_Url/run/nginx.pid.oldbin)"
        #生成脚本
        tee /apps/nginx_cron.sh <<EOF
        while :;do
            old_subprocess=$(pstree -p  "$(cat $Install_Url/run/nginx.pid.oldbin)" |awk -F"[+|\`]+" '{print \$3}')
            [ -z \"\$old_process\" ]  && break
        done
        kill -QUIT "$(cat $Install_Url/run/nginx.pid.oldbin)"
        echo \$\$ > /root/cron.pid
EOF
        tee /apps/if_nginx_cron.sh <<EOF
        while :;do
            if ! pgrep sh |grep -q "$(cat /root/cron.pid)" && ! pgrep nginx |grep -q "$old_process";then
                rm -f /etc/cron.d/nginx_cron
                rm -f /apps/nginx_cron.sh
                rm -f /root/cron.pid
                break
            fi
        done
EOF
        #一周后执行
        Week=$(date "+%u")
        Hour=$(date "+%H")
        tee /etc/cron.d/nginx_cron <<EOF
        0 $(( Hour-1 )) * * $Week  root  nohub sh /apps/nginx_cron.sh
        0 $(( Hour-1 )) * * $Week  root  nohub sh /apps/if_nginx_cron.sh

EOF

    ;;
    *)
        color_sign "选项输入"  1
    ;;
    esac 
}


color_title
color_sign
os_type
os_version
check
Upgrade
process_handling
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值