0%

Centos7 安装nginx、平滑升级

官网 http://nginx.org/en/download.html

GCC编译器

1
yum install -y gcc

PCRE库

Nginx的HTTP模块要用它来解析正则表达式。
pcre-devel是使用PCRE做二次开发时所需要的开发库。

1
yum install -y pcre pcre-devel 

zlib库

1
yum install -y zlib zlib-devel 

OpenSSL库

1
yum install -y openssl openssl-devel 

安装nginx

1
2
3
4
wget http://nginx.org/download/nginx-1.18.0.tar.gz
tar -zxvf nginx-1.18.0.tar.gz && cd nginx-1.18.0/
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-http_stub_status_module --with-pcre --with-stream
make && make install

命令

1
2
3
4
5
6
7
/usr/local/nginx/sbin/nginx           #默认启动方式 start
/usr/local/nginx/sbin/nginx -t #测试配置信息
/usr/local/nginx/sbin/nginx -v #显示版本信息,-V(大V)显示编译时的参数
/usr/local/nginx/sbin/nginx -s stop #快速停止服务
/usr/local/nginx/sbin/nginx -s quit #正常停止服务
/usr/local/nginx/sbin/nginx -s reload #重新加载配置文件
/usr/local/nginx/sbin/nginx -s reopen #重新打开日志文件

启动命令脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
vi /etc/init.d/nginx 

#! /bin/bash
# chkconfig: - 85 15
PATH=/usr/local/nginx
DESC="nginx daemon"
NAME=nginx
DAEMON=$PATH/sbin/$NAME
CONFIGFILE=$PATH/conf/$NAME.conf
PIDFILE=$PATH/logs/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
set -e
[ -x "$DAEMON" ] || exit 0
do_start() {
$DAEMON -c $CONFIGFILE || echo -n "nginx already running"
}
do_stop() {
$DAEMON -s stop || echo -n "nginx not running"
}
do_reload() {
$DAEMON -s reload || echo -n "nginx can't reload"
}
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
do_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
do_stop
echo "."
;;
reload|graceful)
echo -n "Reloading $DESC configuration..."
do_reload
echo "."
;;
restart)
echo -n "Restarting $DESC: $NAME"
do_stop
do_start
echo "."
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|reload|restart}" >&2
exit 3
;;
esac
exit 0

#设置执行权限
chmod a+x /etc/init.d/nginx
#注册成服务
chkconfig --add nginx
#设置开机启动
chkconfig nginx on

平滑升级

解压高版本的nginx压缩包,如nginx1.16.1

1
2
wget http://nginx.org/download/nginx-1.16.1.tar.gz
tar zxf nginx-1.16.1.tar.gz && cd nginx-1.16.1

编译安装

注意:不要make install,会导致原先的主程失控

1
2
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-http_stub_status_module --with-pcre --with-stream
make

备份复制

将原来的二进制系统程序文件备份一下,并复制新的nginx文件,替换原来的nginx二进制文件

1
2
cd objs/
cp -f nginx /usr/local/nginx/sbin/nginx

进行平滑升级

  • -HUP 表示重新加载配置,也就是关闭原有的进程,并开启新的工作进程。此操作不会中断用户的访问请求,因此可以通过此信号平滑的重启Nginx。
  • -USR2 平滑升级可执行程序,主要用在版本升级
  • -WINCH 从容关闭工作进程
  • -USR1 重新打开日志文件,主要用在日志切割(相当于reopen)
  • -QUIT 表处理完当前请求后,关闭进程

kill -USR2 旧版本主进程号

执行新的主进程(新版本)和新的工作进程,依次启动新的主进程和新的工作进程,现在新,旧版本的nginx实例会同时运行,共同处理请求

kill -WINCH 旧版本主进程号

发送WINCH信号给旧版主进程,旧版主进程就开始从容关闭

如果在版本升级完成后,没有任何问题,需要关闭老的master进程的话,可以使用下面的命令

kill -QUIT 旧版本主进程号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
方法一:用这个方法更简单,执行这个即可很快升级完成
# make upgrade
/usr/local/nginx/sbin/nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
kill -USR2 `cat /var/run/nginx.pid`
sleep 1
test -f /var/run/nginx.pid.oldbin
kill -QUIT `cat /var/run/nginx.pid.oldbin`


方法二:步骤多一点
# 设定旧的服务不再接收用户请求(下线),新服务启动子进程接收用户请求(上线)
[root@localhost nginx]# ps aux | grep nginx
root 1207 0.0 0.1 46188 1156 ? Ss 08:33 0:00 nginx: master process sbin/nginx
nobody 1208 0.0 0.1 46632 1900 ? S 08:33 0:00 nginx: worker process
root 1212 0.0 0.0 112812 980 pts/0 R+ 08:33 0:00 grep --color=auto nginx

#找到nginx父进程的pid号,现在对其发送USR2信号
[root@localhost nginx]# kill -USR2 1207

##设定新的子进程开始接收用户的访问请求,旧的不再接受用户的访问请求
[root@localhost nginx]# ps aux | grep nginx
root 1207 0.0 0.1 46188 1340 ? Ss 08:33 0:00 nginx: master process sbin/nginx
nobody 1208 0.0 0.2 46632 2140 ? S 08:33 0:00 nginx: worker process
root 1263 0.0 0.3 46176 3356 ? S 08:41 0:00 nginx: master process sbin/nginx
nobody 1264 0.0 0.2 46620 2148 ? S 08:41 0:00 nginx: worker process
root 1288 0.0 0.0 112812 980 pts/0 R+ 08:41 0:00 grep --color=auto nginx

#现在是nginx的新老版本的进程共存的一种情况。虽然现在旧版本的nginx进程还存在,但是已经不再接受用户的请求了。除此之外,旧版本的nginx进程也依然处于监听的状态,我们通过lsof命令可以看到,虽然在监听,但实际不会处理新连接,因为fd已经从epoll中移出了。另外,旧master是新master的父进程,所以新master才能共享打开的监听端口。保留旧版本的master是为了方便回滚

[root@localhost nginx]# lsof -p 1207 | grep LISTEN
nginx 1207 root 6u IPv4 20606 0t0 TCP *:http (LISTEN)


## 进行旧服务进程的关闭,该pid号是旧版本的nginx的master进程的pid号
[root@localhost nginx]# kill -WINCH 1207

[root@localhost nginx]# ps aux | grep nginx
root 1207 0.0 0.1 46188 1340 ? Ss 08:33 0:00 nginx: master process sbin/nginx
root 1263 0.0 0.3 46176 3356 ? S 08:41 0:00 nginx: master process sbin/nginx
nobody 1264 0.0 0.2 46620 2148 ? S 08:41 0:00 nginx: worker process
root 2681 0.0 0.0 112812 980 pts/0 R+ 08:53 0:00 grep --color=auto nginx

#可以看到现在的旧版本的nginx的worker进程已经全部被杀死了,只剩下的旧版本nginx的master进程
确定升级没有任何问题的话,那么现在我们可以把这个master进程给杀死掉。可以用kill -QUIT把旧master进程杀掉
[root@localhost nginx]# kill -QUIT 1207
[root@localhost nginx]# ps aux | grep nginx
root 1263 0.0 0.3 46176 3356 ? S 08:41 0:00 nginx: master process sbin/nginx
nobody 1264 0.0 0.2 46620 2148 ? S 08:41 0:00 nginx: worker process
root 3128 0.0 0.0 112812 976 pts/0 R+ 08:56 0:00 grep --color=auto nginx

回退版本

原来备份好旧版本的二进制文件的再复制回去

kill -HUP 旧版本的主进程号

nginx将在不重载配置文件的情况下启动旧版的worker进程

kill -USR2 新版本的主进程号

依次启动新的主进程(旧版本)和新的工作进程,现在两个版本的nginx实例会同时运行,共同处理请求

kill -WINCH 新版本主进程号

发送WINCH信号给新版主进程,新版主进程就开始从容关闭

配置案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# tcp loadbalance
stream {
server {
listen 8081 so_keepalive=on; #保持长连接
proxy_pass 10.0.2.48:3306;
}

备注:[so_keepalive=on|off|keepidle:keepintvl:keepcnt|proxy_protocol]
关于TCP探活机制的几个参数的说明:

keepcnt 关闭一个非活跃连接之前进行探测的最大次数t
keepidle 对一个连接进行有效性探测之前运行的最大非活跃时间间隔
keepintvl 两个探测的时间间隔
设置如下参数:

listen 1936 so_keepalive=5s:2:2;

# http loadbalance
upstream gateway{
server 10.168.4.5:31113;
}
server {
listen 16400;
server_name localhost;
location / {
proxy_pass http://gateway;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
}
location ~ (^/f/|^/mpmt-user/|^/mpmt-mytask/) {
proxy_pass http://gateway;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
}


# rewrite

# 访问域名带有/mpmt/webinfo/
location ^~ /mpmt/webinfo/ {
return 301 https://xxx.cn$request_uri;

}
# 访问具体页面进行rewrite
location ^~ /mpmt/app/index.html {
rewrite "(.*)$" https://xxx.com/mpmt/app/download/href.html;
}
# 访问具体页面进行rewrite
location /download.html {
rewrite ^/download.html$ https://xxx.com/mpmt/app/download/download.html;
}
# 访问带有apk后缀进行rewrite
location ~ .*\.(apk)$ {
rewrite "(.*)$" https://xxx.com/mpmt/webinfo/version/sz.apk;
}