文章目录
- Nginx系列-Nginx高可用(主从、主主模式)
- 1. 引言
- 2. 高可用架构设计
- 3. 基础环境准备
- 4. Nginx安装
- 5. keepalived安装
- 4. 配置主备模式
- 5. 配置主主(双主)模式
- 6. 注意事项
Nginx系列-Nginx高可用(主从、主主模式)
1. 引言
在单机部署的Nginx环境中,一旦Nginx服务器出现故障,整个系统服务将受到影响,导致服务中断。为了解决这个问题,我们需要引入Nginx的高可用性(HA)架构。本文将详细探讨Nginx高可用性的两种主要解决方案:主从架构和主主架构。
2. 高可用架构设计
- KeepAlived是什么?
KeepAlived是一款基于VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议)的开源软件,主要用于解决网络服务的单点故障问题,特别是在集群环境中提供VIP(Virtual IP,虚拟IP地址)共享和故障切换功能
- Nginx+keepalived 双机主从模式(也叫双机热备):
即前端使用两台服务器,一台主服务器和一台热备服务器,正常情况下,主服务器绑定一个虚拟IP,提供负载均衡服务,热备服务器处于空闲状态;当主服务器发生故障时,热备服务器接管主服务器的虚拟IP,提供负载均衡服务;但是热备服务器在主机器不出现故障的时候,永远处于浪费状态,对于服务器不多的网站,该方案不经济实惠。
- Nginx+keepalived 双机主主模式(也叫双机互备):
即前端使用两台负载均衡服务器,互为主备,且都处于活动状态,同时各自绑定一个虚拟IP,提供负载均衡服务;当其中一台发生故障时,另一台接管发生故障服务器的虚拟IP(这时由非故障机器一台负担所有的请求)
3. 基础环境准备
本片采用 nginx容器部署+keepalived宿主机部署、nginx容器部署+keepalived容器部署两种方案
- 准备两台服务器
- 分别安装docker
- 分别安装nginx
① Nginx两个端口要保持一致 - 分别安装keepalive
4. Nginx安装
- 创建nginx目录
mkdir -p /home/xmc/nginx1/conf.d /home/xmc/nginx1/html /home/xmc/nginx1/logs
- 临时构建nginx容器(目的是获取配置文件)
docker run -d --name=nginx1 nginx:latest
- 从临时nginx容器获取配置文件
docker cp nginx1:/etc/nginx/nginx.conf /home/xmc/nginx1
docker cp nginx1:/etc/nginx/conf.d /home/xmc/nginx1
docker cp nginx1:/usr/share/nginx/html /home/xmc/nginx1
- 删除临时nginx容器
docker stop nginx1
docker rm nginx1
- 重新构建nginx容器
docker run \
-d -p 8081:80 \
--name nginx1 \
--privileged=true \
--restart=always \
-v /home/xmc/nginx1/nginx.conf:/etc/nginx/nginx.conf \
-v /home/xmc/nginx1/logs:/var/log/nginx \
-v /home/xmc/nginx1/conf.d:/etc/nginx/conf.d \
-v /home/xmc/nginx1/html:/usr/share/nginx/html \
nginx:latest
5. keepalived安装
keepalived安装包下载地址
- 安装目录准备
# 进入一下目录,解压的时候会自动创建keepalived文件夹
cd /opt/module
- 解压
tar -zxvf keepalived-2.2.7.tar.gz
- 安装
./configure --prefix=/usr/local/keepalived make && make install
- 启停
# 启动
systemctl start keepalived
# 状态
systemctl status keepalived
# 停止
systemctl stop keepalived
- 设置开机自启动
sudo systemctl enable keepalived
- 日志查看
Keepalived默认所有的日志都是写入到/var/log/message,
你可以使用命令 tail -f /var/log/messages|grep Keepalived 进行查看
4. 配置主备模式
- 主机:keepalived的配置
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.10.200
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_http_port {
script "/etc/keepalived/nginx_check.sh" # 脚本路径
interval 2 #(检测脚本执行的间隔)
weight 2
}
vrrp_instance VI_1 {
state MASTER # 主机使用: MASTER 备机使用: BACKUP
interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
virtual_router_id 51 # 虚拟路由标识,主、备服务器ID必须一样
priority 100 # 优先级,备份服务上将100改为小于100,可配置成90
advert_int 1 # 主备之间同步检查的时间间隔单位秒
authentication { # 验证类型和密码
auth_type PASS # 验证类型有两种 PASS和HA
auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
}
virtual_ipaddress {
192.168.10.50 # 虚拟IP地址,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
}
track_script { # 调用上边的脚本
chk_http_port
}
}
- 备机:keepalived的配置
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.10.200
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_http_port {
script "/etc/keepalived/nginx_check.sh" # 脚本路径
interval 2 #(检测脚本执行的间隔)
weight 2
}
vrrp_instance VI_1 {
state BACKUP # 主机使用: MASTER 备机使用: BACKUP
interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
virtual_router_id 51 # 虚拟路由标识,主、备服务器ID必须一样
priority 90 # 优先级,备份服务上将100改为小于100,可配置成90
advert_int 1 # 主备之间同步检查的时间间隔单位秒
authentication { # 验证类型和密码
auth_type PASS # 验证类型有两种 PASS和HA
auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
}
virtual_ipaddress {
192.168.10.50 # 虚拟IP地址,主、备节点必须一致,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
}
track_script { # 调用上边的脚本
chk_http_port
}
}
- 检测脚本(主机和备机一致):
vim /etc/keepalived/nginx_check.sh
#!/bin/bash
# 容器名称
container_name="nginx1"
# 检查容器状态
container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null)
# 如果容器不存在
if [ -z "$container_status" ]; then
echo "容器 $container_name 不存在! 关闭 keepalived..."
systemctl stop keepalived
echo "Keepalived 已关闭。"
exit 1
fi
echo "容器 $container_name 当前状态为: $container_status"
# 如果容器未运行,尝试重新启动
if [ "$container_status" != "running" ]; then
echo "容器 $container_name 未运行,尝试重新启动..."
docker start "$container_name"
sleep 5 # 等待 5 秒,确保容器有足够时间启动
# 再次检查容器状态
container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null)
if [ "$container_status" != "running" ]; then
echo "容器 $container_name 重启后仍未运行,将关闭 Keepalived。"
systemctl stop keepalived
echo "Keepalived 已关闭。"
exit 1
else
echo "容器 $container_name 已成功启动。"
fi
else
echo "容器 $container_name 已处于运行状态,无需重启。"
fi
赋予执行权限
chmod +x /etc/keepalived/nginx_check.sh
5. 配置主主(双主)模式
- 主机1:keepalived的配置(互为主备配置)
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.10.200
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_http_port {
script "/etc/keepalived/nginx_check.sh" # 脚本路径
interval 2 #(检测脚本执行的间隔)
weight 2
}
vrrp_instance VI_1 {
state MASTER # 主机使用: MASTER 备机使用: BACKUP
interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
virtual_router_id 51 # 虚拟路由标识,主、备服务器ID必须一样
priority 100 # 优先级,备份服务上将100改为小于100,可配置成90
advert_int 1 # 主备之间同步检查的时间间隔单位秒
authentication { # 验证类型和密码
auth_type PASS # 验证类型有两种 PASS和HA
auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
}
virtual_ipaddress {
192.168.10.50 # 虚拟IP地址,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
}
track_script { # 调用上边的脚本
chk_http_port
}
}
vrrp_instance VI_2 {
state BACKUP # 主机使用: MASTER 备机使用: BACKUP
interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
virtual_router_id 52 # 虚拟路由标识,主、备服务器ID必须一样
priority 90 # 优先级,备份服务上将100改为小于100,可配置成90
advert_int 1 # 主备之间同步检查的时间间隔单位秒
authentication { # 验证类型和密码
auth_type PASS # 验证类型有两种 PASS和HA
auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
}
virtual_ipaddress {
192.168.10.51 # 虚拟IP地址,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
}
track_script { # 调用上边的脚本
chk_http_port
}
}
- 主机2:keepalived的配置(互为主备配置)
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.10.200
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_script chk_http_port {
script "/etc/keepalived/nginx_check.sh" # 脚本路径
interval 2 #(检测脚本执行的间隔)
weight 2
}
vrrp_instance VI_1 {
state BACKUP # 主机使用: MASTER 备机使用: BACKUP
interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
virtual_router_id 51 # 虚拟路由标识,主、备服务器ID必须一样
priority 90 # 优先级,备份服务上将100改为小于100,可配置成90
advert_int 1 # 主备之间同步检查的时间间隔单位秒
authentication { # 验证类型和密码
auth_type PASS # 验证类型有两种 PASS和HA
auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
}
virtual_ipaddress {
192.168.10.50 # 虚拟IP地址,主、备节点必须一致,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
}
track_script { # 调用上边的脚本
chk_http_port
}
}
vrrp_instance VI_2 {
state MASTER # 主机使用: MASTER 备机使用: BACKUP
interface ens33 #实例绑定的网卡, 用ip a命令查看网卡编号
virtual_router_id 52 # 虚拟路由标识,主、备服务器ID必须一样
priority 100 # 优先级,备份服务上将100改为小于100,可配置成90
advert_int 1 # 主备之间同步检查的时间间隔单位秒
authentication { # 验证类型和密码
auth_type PASS # 验证类型有两种 PASS和HA
auth_pass 1111 # 验证密码,在一个实例中主备密码保持一样
}
virtual_ipaddress {
192.168.10.51 # 虚拟IP地址,主、备节点必须一致,可以有多个,每行一个,不需要指定端口,端口使用的是Nginx容器的端口
}
track_script { # 调用上边的脚本
chk_http_port
}
}
检测脚本(主机和备机一致):
#!/bin/bash
# 容器名称
container_name="nginx1"
# 检查容器状态
container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null)
# 如果容器不存在
if [ -z "$container_status" ]; then
echo "容器 $container_name 不存在! 关闭 keepalived..."
systemctl stop keepalived
echo "Keepalived 已关闭。"
exit 1
fi
echo "容器 $container_name 当前状态为: $container_status"
# 如果容器未运行,尝试重新启动
if [ "$container_status" != "running" ]; then
echo "容器 $container_name 未运行,尝试重新启动..."
docker start "$container_name"
sleep 5 # 等待 5 秒,确保容器有足够时间启动
# 再次检查容器状态
container_status=$(docker inspect -f '{{.State.Status}}' "$container_name" 2>/dev/null)
if [ "$container_status" != "running" ]; then
echo "容器 $container_name 重启后仍未运行,将关闭 Keepalived。"
systemctl stop keepalived
echo "Keepalived 已关闭。"
exit 1
else
echo "容器 $container_name 已成功启动。"
fi
else
echo "容器 $container_name 已处于运行状态,无需重启。"
fi
- 双主模式keepalived的主要区别
- 互为主备,两个实例,两个虚拟ip
- 每个实例都拥有自己独立的虚拟路由id(virtual_router_id这个属性)
6. 注意事项
没有出现虚拟ip,如果出现主备都抢用了虚拟ip的情况,那很可能是firewall的原因,keepalived 是基于vrrp做到虚拟ip漂移的,这里不开启的话,主备均会认为对方挂掉了,会造成主备都能获取到虚拟ip(vip)
防火墙开启vrrp
firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent
重新载入配置
firewall-cmd –reload