用NginX+keepalived实现高可用的负载均衡

目录
  1. 1. 一、规划和准备
  2. 2. 二、安装
  3. 3. 三、 配置
    1. 3.1. 3.1 配置NginX
    2. 3.2. 3.2 配置keepalived
    3. 3.3. 3.3 让keepalived监控NginX的状态
  4. 4. 四、还可以做什么
  5. 5. 五、SSL配置

前面的《统一接入层方案》中就目的、目标和整体方案进行了讨论,本文讨论具体的实施。简单来说就是在两台服务器上分别部署NginX,并通过keepalived实现高可用。

一、规划和准备

需要统一接入的应用系统

应用系统 域名/虚拟目录 应用服务器及URL
svn dev.mycompany.com/svn http://50.1.1.21/svn
svn web管理 dev.mycompany.com/submin http://50.1.1.21/submin
网站 www.mycompany.com http://50.1.1.10; http://50.1.1.11; http://50.1.1.12
OA oa.mycompany.com http://50.1.1.13:8080; http://50.1.1.14:8080

接入服务器

用途 IP
MASTER 50.1.1.3
BACKUP 50.1.1.4

操作系统: RHEL5.6x64,配置了yum 私服

两台接入服务器公用一个虚拟IP(VIP):50.1.1.2

二、安装

两台接入服务器分别安装NginX和keepalived:

准备依赖包:
yum -y install gcc pcre-devel zlib-devel openssl-devel

下载
wget http://nginx.org/download/nginx-1.2.4.tar.gz
wget http://www.keepalived.org/software/keepalived-1.2.7.tar.gz

安装NginX

1
2
3
4
tar zxvf nginx-1.2.4.tar.gz
cd nginx-1.2.4
./configure --with-http_stub_status_module
make && make install

安装keepalived

1
2
3
4
5
6
7
8
9
10
11
tar zxvf keepalived-1.2.7.tar.gz
cd keepalived-1.2.7
./configure
make
make install

cp /usr/local/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig/
mkdir /etc/keepalived
cp /usr/local/etc/keepalived/keepalived.conf /etc/keepalived/
cp /usr/local/sbin/keepalived /usr/sbin/

加入启动服务

1
2
echo "/usr/local/nginx/sbin/nginx" >> /etc/rc.local
echo "/etc/init.d/keepalived start" >> /etc/rc.local

三、 配置

3.1 配置NginX

两台接入服务器的NginX的配置完全一样,主要是配置/usr/local/nginx/conf/nginx.conf的http。其中多域名指向是通过虚拟主机(配置http下面的server)实现;同一域名的不同虚拟目录通过每个server下面的不同location实现;到后端的服务器在http下面配置upstream,然后在server或location中通过proxypass引用。要实现前面规划的接入方式,http的配置如下:

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
http {
include mime.types;
default_type application/octet-stream;

sendfile on;

upstream dev.hysec.com {
server 50.1.1.21:80;
}


upstream www.hysec.com {
ip_hash;
server 50.1.1.10:80;
server 50.1.1.11:80;
server 50.1.1.12:80;
}

upstream oa.hysec.com {
ip_hash;
server 50.1.1.13:8080;
server 50.1.1.14:8080;

server {
listen 80;
server_name dev.hysec.com;
location /svn {
proxy_pass http://dev.hysec.com;
}

location /submin {
proxy_pass http://dev.hysec.com;
}
}

server {
listen 80;
server_name www.hysec.com;
location / {
proxy_pass http://www.hysec.com;
}
}

server {
listen 80;
server_name oa.hysec.com;
location / {
proxy_pass http://oa.hysec.com;
}
}
}
}

验证方法:
1.首先用IP访问前表中各个应用服务器的url
2.再用域名和路径访问前表中各个应用系统的域名/虚拟路径

3.2 配置keepalived

按照上面的安装方法,keepalived的配置文件在/etc/keepalived/keepalived.conf。主、从服务器的配置相关联但有所不同。如下:

Master:

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
! Configuration File for keepalived

global_defs {
notification_email {
wanghaikuo@hysec.com
wanghaikuo@gmail.com
}

notification_email_from wanghaikuo@hysec.com
smtp_server smtp.hysec.com
smtp_connect_timeout 30
router_id nginx_master

}

vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 101
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
50.1.1.2
}
}

Backup:

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
! Configuration File for keepalived

global_defs {
notification_email {
wanghaikuo@hysec.com
wanghaikuo@gmail.com
}

notification_email_from wanghaikuo@hysec.com
smtp_server smtp.hysec.com
smtp_connect_timeout 30
router_id nginx_backup

}

vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 99
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
50.1.1.2
}
}

验证:
1.先后在主、从服务器上启动keepalived: /etc/init.d/keepalived start
2.在主服务器上查看是否已经绑定了虚拟IP:ip addr
3.停止主服务器上的keepalived: /etc/init.d/keepalived stop,然后在从服务器上查看是否已经绑定了虚拟IP
4.启动主服务器上的keepalived,看看主服务器能否重新接管虚拟IP

3.3 让keepalived监控NginX的状态

经过前面的配置,如果主服务器的keepalived停止服务,从服务器会自动接管VIP对外服务;一旦主服务器的keepalived恢复,会重新接管VIP。 但这并不是我们需要的,我们需要的是当NginX停止服务的时候能够自动切换。

keepalived支持配置监控脚本,我们可以通过脚本监控NginX的状态,如果状态不正常则进行一系列的操作,最终仍不能恢复NginX则杀掉keepalived,使得从服务器能够接管服务。

如何监控NginX的状态

最简单的做法是监控NginX进程,更靠谱的做法是检查NginX端口,最靠谱的做法是检查多个url能否获取到页面。

如何尝试恢复服务

如果发现NginX不正常,重启之。等待3秒再次校验,仍然失败则不再尝试。

根据上述策略很容易写出监控脚本。这里使用nmap检查nginx端口来判断nginx的状态,记得要首先安装nmap。监控脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh
# check nginx server status
NGINX=/usr/local/nginx/sbin/nginx
PORT=80

nmap localhost -p $PORT | grep "$PORT/tcp open"
#echo $?
if [ $? -ne 0 ];then
$NGINX -s stop
$NGINX
sleep 3
nmap localhost -p $PORT | grep "$PORT/tcp open"
[ $? -ne 0 ] && /etc/init.d/keepalived stop
fi

不要忘了设置脚本的执行权限,否则不起作用。

假设上述脚本放在/opt/chk_nginx.sh,则keepalived.conf中增加如下配置:

1
2
3
4
5
6
7
8
9
10
vrrp_script chk_http_port {
script "/opt/chk_nginx.sh"
interval 2
weight 2
}

track_script {
chk_http_port
}

更进一步,为了避免启动keepalived之前没有启动nginx , 可以在/etc/init.d/keepalived的start中首先启动nginx:

1
2
3
4
5
6
7
8
9
10
start() {
/usr/local/nginx/sbin/nginx
sleep 3
echo -n $"Starting $prog: "
daemon keepalived ${KEEPALIVED_OPTIONS}
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
}

四、还可以做什么

对于简单重复性劳动,人总是容易犯错,这种事情最好交给机器去做。 比如,在这个案例中,作为统一接入服务器,可能经常要修改nginx的配置、nginx下面的html文件等。而且,一定要保证集群中的每台服务器的配置相同。 最好的做法是由配置管理服务器来管理,如果没有,也可以使用简单的linux文件同步来解决。

五、SSL配置

nginx/conf下生成秘钥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#生成RSA密钥
openssl dsaparam -rand -genkey -out myRSA.key 1024

#生成CA密钥:(要输入一个自己记得的密码)
openssl gendsa -des3 -out cert.key myRSA.key

#用这个CA密钥来创建证书,需要上一步创建的密码
openssl req -new -x509 -days 365 -key cert.key -out cert.pem

#把证书设置为root专用
chmod 700 cert.*

#生成免密码文件
openssl rsa -in cert.key -out cert.key.unsecure

如果要启用SSL,在nginx中进行如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 这里是SSL的相关配置
server {
listen 443;
server_name www.example.com; # 你自己的域名
root /home/www;
ssl on;
ssl_certificate cert.perm;
#使用.unsecure文件可以在nginx启动时不输入密码
ssl_certificate_key cert.key.unsecure;
location / {
#...
}
}

Date: 2012-10-25 11:16:14 CST

Author: Holbrook

Org version 7.8.11 with Emacs version 24

Validate XHTML 1.0

转自:http://www.cnblogs.com/holbrook/archive/2012/10/25/2738475.html