1.1、物料准备
服务器
centos7 192.168.50.68 # 主节点 centos7 192.168.50.251 # 从节点 deepin 192.168.50.112 # web 服务节点 VIP 192.168.50.10 # 负载均衡器上配置的域名都解析到这个 VIP 上
nginx
nginx.x86_64 1:1.16.1-3.el7
keepalived
keepalived.x86_64 0:1.3.5-19.el7
web 服务
这里使用 go 服务,go build 后服务为 web-test
,执行 ./web-test -p 8011
指定端口启动服务。
package main import ( "flag" "github.com/gin-gonic/gin" "log" "net/http" ) func main() { var port string flag.StringVar(&port, "p", "8011", "port") flag.Parse() r := gin.Default() r.GET("/hello", func(c *gin.Context) { // 打印来源地址 log.Println(c.Request.RemoteAddr) c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "success"}) }) if err := r.Run(":" + port); err != nil { log.Printf("server :8011 run failed, err: %v", err) } }
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
1.2、服务器准备
# 在主节点、从节点、web 服务器都要执行 # 1、关闭防火墙 systemctl stop firewalld.service # 关闭开机自启 systemctl disable firewalld.service # 2、关闭 SELinux setenforce 0 # 永久关闭 SELinux vim /etc/sysconfig/selinux SELINUX=disabled 1234567891011
二、主从架构
2.1、部署 web 服务
在 web 服务器(192.168.50.112)同时启动两个 web 服务,端口分别为 8011 和 8012。
./web-test -p 8011
./web-test -p 8012
2.2、部署 nginx
在主节点(192.168.50.68)执行 yum install nginx
安装 nginx。
修改 nginx 配置文件,将主节点 nginx 转发到 web 服务
vim /etc/nginx/nginx.conf
# 其余部分保持不变 # 增加 web_test,两个 web 服务权重不同 upstream web_test { server 192.168.50.112:8011 weight=20; server 192.168.50.112:8012 weight=10; } server { listen 80 default_server; listen [::]:80 default_server; server_name _; root /usr/share/nginx/html; # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location / { proxy_pass http://web_test; # 拦截请求,交由 web_test 处理 } error_page 404 /404.html; location = /404.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } }
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
启动 nginx,查看结果。
# 启动 nginx nginx # 访问主节点服务 curl 192.168.50.68/hello {"code":200,"msg":"success"}
我们可以看到 web 服务器位于 8011 的服务已经受到了这个请求。
在从节点(192.168.50.251)执行相同的操作来部署 nginx 服务。
注意:从节点 nginx 配置的 web 服务的权重与主节点不同。(没什么意义,就是为了区别一下)
upstream web_test { server 192.168.50.112:8011 weight=10; server 192.168.50.112:8012 weight=20; }
2.3、部署 keepalived
安装 openssl
# keepalived 需要依赖 openssl # 查看 openssl 是否安装 rpm -qa | grep openssl # 如果没有则进行安装 yum install openssl
在主节点(192.168.50.68)执行 yum install keepalived
安装 keepalived。
查看当前的网卡
执行 ifconfig
查看当前的网卡,之后 keepalived 的配置文件中会对此网卡进行绑定。
修改主节点 keepalived 配置文件,将文件原本的配置删除。
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived global_defs { notification_email { # 指定 keepalived 发生切换时发送给谁邮件 xxxx@xx.com } notification_email_from Alexandre.Cassen@firewall.loc # 指定发件人 smtp_server 192.168.200.1 # smtp 服务器地址 smtp_connect_timeout 30 # smtp 连接超时时间 router_id LVS_DEVEL # 负载均衡标识,在局域网内应该是唯一的。 vrrp_skip_check_adv_addr # 默认是不跳过检查。检查收到的VRRP通告中的所有地址可能会比较耗时,设置此命令的意思是,如果通告与接收的上一个通告来自相同的master路由器,则不执行检查(跳过检查)。 #vrrp_strict # 严格遵守VRRP协议。下列情况将会阻止启动Keepalived:1. 没有VIP地址。2. 单播邻居。3. 在VRRP版本2中有IPv6地址。这里需要注释掉,否则无法执行检测脚本 script_user root # script_user[groupname]: 设置运行脚本默认用户和组。如果没有指定,则默认用户为 keepalived_script(需要该用户存在),否则为root用户。默认 groupname 同 username。 enable_script_security # 如果脚本路径的任一部分对于非root用户来说,都具有可写权限,则不会以root身份运行脚本。 } vrrp_script chk_nginx_alive { script "/etc/keepalived/chk_nginx.sh" # 脚本位置 interval 5 # 每五秒执行一次 weight 10 # 运行成功权重+10 } vrrp_instance VI_1 { state MASTER # 主节点需要标识状态为 interface enp0s3 # 设置实例绑定的网卡,上一步获取的网卡 virtual_router_id 51 # 同一实例下的该值必须相同 priority 100 # MASTER 权重要高于 BACKUP advert_int 1 # MASTER 与 BACKUP 负载均衡器之间同步检查的时间间隔,单位为秒 authentication { # 设置认证 auth_type PASS # 主从服务器验证方式 auth_pass 1111 } track_script { chk_nginx_alive # 添加检测 nginx 存活脚本 } virtual_ipaddress { 192.168.50.10 # 可以设置多个虚拟 ip,这里尽量与节点服务器处在相同顺序 #192.168.200.11 #192.168.200.12 } }
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
在上面的配置文件中,我们定义了一个检查 nginx 的脚本(/etc/keepalived/chk_nginx.sh
),我们将这个脚本实现。
vim /etc/keepalived/chk_nginx.sh
#!/bin/bash A=`ps -C nginx --no-header | wc -l` # 判断nginx是否宕机,如果宕机尝试重新启动 if [ $A -eq 0 ];then nginx # 等待2秒检查nginx 如果没有启动成功 则停止keepalived 启动备用机 sleep 2s if [ `ps -C nginx --no-header | wc -l` -eq 0 ];then systemctl stop keepalived fi fi
赋予脚本执行权限
chmod a+x /etc/keepalived/chk_nginx.sh
启动 keepalived,查看日志
执行 systemctl start keepalived
启动 keepalived。
执行 systemctl status keepalived
查看服务状态。
执行 tail -f /var/log/messages
查看日志。
节点(192.168.50.251)执行相同的操作来部署 keepalived 服务。
注意:从节点的 keepalived 配置文件,与主节点不同,部分需要额外配置。
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived global_defs { notification_email { # 指定 keepalived 发生切换时发送给谁邮件 xxxx@xx.com } notification_email_from Alexandre.Cassen@firewall.loc # 指定发件人 smtp_server 192.168.200.1 # smtp 服务器地址 smtp_connect_timeout 30 # smtp 连接超时时间 router_id LVS_DEVEL # 负载均衡标识,在局域网内应该是唯一的。 vrrp_skip_check_adv_addr # 默认是不跳过检查。检查收到的VRRP通告中的所有地址可能会比较耗时,设置此命令的意思是,如果通告与接收的上一个通告来自相同的master路由器,则不执行检查(跳过检查)。 #vrrp_strict # 严格遵守VRRP协议。下列情况将会阻止启动Keepalived:1. 没有VIP地址。2. 单播邻居。3. 在VRRP版本2中有IPv6地址。这里需要注释掉,否则无法执行检测脚本 script_user root # script_user[groupname]: 设置运行脚本默认用户和组。如果没有指定,则默认用户为 keepalived_script(需要该用户存在),否则为root用户。默认 groupname 同 username。 enable_script_security # 如果脚本路径的任一部分对于非root用户来说,都具有可写权限,则不会以root身份运行脚本。 } vrrp_script chk_nginx_alive { script "/etc/keepalived/chk_nginx.sh" # 脚本位置 interval 5 # 每五秒执行一次 weight 10 # 运行成功权重+10 } vrrp_instance VI_1 { state BACKUP # 从节点标识状态为 BACKUP interface enp0s3 # 设置实例绑定的网卡 virtual_router_id 51 # 同一实例下的该值必须相同 priority 100 # BACKUP 权重要低于 MASTER advert_int 1 # MASTER 与 BACKUP 负载均衡器之间同步检查的时间间隔,单位为秒 authentication { # 设置认证 auth_type PASS # 主从服务器验证方式 auth_pass 1111 } track_script { chk_nginx_alive # 添加检测 nginx 存活脚本 } virtual_ipaddress { 192.168.50.10 # 可以设置多个虚拟 ip,这里尽量与节点服务器处在相同顺序 #192.168.200.11 #192.168.200.12 } }
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
2.4、测试
此时主从架构的 keepalived + nginx 的已经配置完成了,在这里我们进行测试。
主从节点都存活
执行 curl 192.168.50.10/hello
直接访问 VIP,我们可以发现 VIP 指向了主节点(192.168.10.68)并将请求发送到了 web 服务器的 8011 服务。
主节点死亡,从节点存活
执行 nginx -s quit
结束 nginx 服务。这里我们发现手动结束 nginx 服务后,keepalived 服务很快将 nginx 服务再次唤醒。
所以这里我们需要做一些特殊操作,修改 keepalived 的检测脚本,使其无法唤醒 nginx。
vim /etc/keepalived/chk_nginx.sh
#!/bin/bash A=`ps -C nginx --no-header | wc -l` # 判断nginx是否宕机,如果宕机尝试重新启动 if [ $A -eq 0 ];then # nginx # 注释掉唤醒 nginx 命令 # 等待2秒检查nginx 如果没有启动成功 则停止keepalived 启动备用机 sleep 2s if [ `ps -C nginx --no-header | wc -l` -eq 0 ];then systemctl stop keepalived fi fi
执行 systemctl restart keepalived
重启 keepalived 服务。
再次执行 nginx -s quit
停止 nginx 服务。我们可以发现,keepalived 在无法唤醒 nginx 的情况下将自己停止了。
再次执行 curl 192.168.50.10/hello
直接访问 VIP,我们可以发现 VIP 指向了从节点(192.168.10.251)并将请求发送到了 web 服务器的 8011 服务。
三、主主架构
3.1、搭建
主主结构指的是两个节点既是主节点又是从节点,两节点互为备份。具体为表现为有两个 VIP,VIP1(192.168.50.10) 和 VIP2(192.168.50.11)。
VIP1 的主节点为 192.168.50.68,从节点为 192.168.50.251,VIP2 的主节点为 192.168.50.251,从节点为 192.168.50.68。
在主从架构的情况下,如果主节点没有宕机,那么从节点将一直处于闲置的状态。尽管主主架构可以避免闲置的问题,但是又引入了一个 VIP,使得在域名解析的情况下需要额外提供一份负载均衡。
实现主主架构也很简单。只需要在 keepalived 增加一个实例即可。
节点1(192.168.50.68)
vim /etc/keepalived/keepalived.conf
# 原来的不变,在底部增加一个从实例 vrrp_instance VI_2 { state BACKUP # 标识状态为 MASTER 备份机为 BACKUP interface enp0s3 # 设置实例绑定的网卡 virtual_router_id 52 # 同一实例下的该值必须相同 priority 99 # MASTER 权重要高于 BACKUP advert_int 1 # MASTER 与 BACKUP 负载均衡器之间同步检查的时间间隔,单位为秒 authentication { # 设置认证 auth_type PASS # 主从服务器验证方式 auth_pass 1111 } track_script { chk_nginx_alive # 添加检测 nginx 存活脚本 } virtual_ipaddress { 192.168.50.11 # 可以设置多个虚拟 ip,这里尽量与节点服务器处在相同顺序 #192.168.200.11 #192.168.200.12 } } 123456789101112131415161718192021
节点2(192.168.50.251)
vim /etc/keepalived/keepalived.conf
# 原来的不变,在底部增加一个主实例 vrrp_instance VI_2 { state MASTER # 标识状态为 MASTER 备份机为 BACKUP interface enp0s3 # 设置实例绑定的网卡 virtual_router_id 52 # 同一实例下的该值必须相同 priority 100 # MASTER 权重要高于 BACKUP advert_int 1 # MASTER 与 BACKUP 负载均衡器之间同步检查的时间间隔,单位为秒 authentication { # 设置认证 auth_type PASS # 主从服务器验证方式 auth_pass 1111 } track_script { chk_nginx_alive # 添加检测 nginx 存活脚本 } virtual_ipaddress { 192.168.50.11 # 可以设置多个虚拟 ip,这里尽量与节点服务器处在相同顺序 #192.168.200.11 #192.168.200.12 } } 123456789101112131415161718192021
重启两个节点的 keepalived 服务。
systemctl restart keepalived
3.2、测试
执行 curl 192.168.50.10/hello
,查看 VIP1
执行 curl 192.168.50.10/hello
,查看 VIP1