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文件夹 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
到此这篇关于nginx高可用(主从、主主模式)的项目实践的文章就介绍到这了,更多相关nginx高可用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论