一.体系架构
在 Keepalived + Nginx 高可用负载均衡架构中, keepalived 负责实现 High-availability (HA) 功能控制前端机 VIP(虚拟网络地址), 当有设备发生故障时, 热备服务器可以瞬间将 VIP 自动切换过来, 实际运行中体验只有 2 秒钟切换时间, DNS 服务可以负责前端 VIP 的负载均衡.
nginx 负责控制后端 web 服务器的负载均衡, 将客户端的请求按照一定的算法转发给后端 Real Server 处理, 而 Real Server 将响应直接返回给客户端.
二.简单原理
NGINX_MASTER,NGINX_BACKUP 两台服务器均通过 keepalived 软件把 ens32 网卡绑上一个虚拟 IP(VIP) 地址 192.168.2.242, 此 VIP 当前由谁承载着服务就绑定在谁的 ens32 上, 当 NGINX_MASTER 发生故障时, NGINX_BACKUP 会通过 / etc/keepalived/keepalived.conf 文件中设置的心跳时间 advert_int 1 检查, 无法获取 NGINX_MASTER 正常状态的话, NGINX_BACKUP 会瞬间绑定 VIP 来接替 nginx_master 的工作, 当 NGINX_MASTER 恢复后 keepalived 会通过 priority 参数判断优先权将虚拟 VIP 地址 192.168.2.242 重新绑定给 NGINX_MASTER 的 ens32 网卡.
使用此方案的优越性
1. 实现了可弹性化的架构, 在压力增大的时候可以临时添加 Web 服务器添加到这个架构里面去;
2.upstream 具有负载均衡能力, 可以自动判断后端的机器, 并且自动踢出不能正常提供服务的机器;
3. 相对于 lvs 而言, 正则分发和重定向更为灵活. 而 Keepalvied 可保证单个 nginx 负载均衡器的有效性, 避免单点故障;
4. 用 nginx 做负载均衡, 无需对后端的机器做任何改动.
5.nginx 部署在 docker 容器里, 即大量地节约开发, 测试, 部署的时间, 又可以在出现故障时通过镜像快速恢复业务.
三, 系统环境
两台负载机器安装: centos7.5+docker+nginx+keepalived, 分别命名为: NGINX_MASTER,NGINX_BACKUP.
后端 Web 服务器, 可以是提供 Web 服务的任何架构, 分别命名为: WEB_1,WEB_2.
后端数据库机器可任意架构, 只要能提供数据库服务即可.
服务器 | 操作系统 | IP 地址 | 安装软件 |
---|---|---|---|
NGINX_MASTER | CentOS 7.5 64 位 | 192.168.2.228 | docker+nginx+keepalived |
NGINX_BACKUP | CentOS 7.5 64 位 | 192.168.2.229 | docker+nginx+keepalived |
WEB_1 | CentOS 7.5 64 位 | 192.168.2.226 | docker+apache+PHP |
WEB_2 | CentOS 7.5 64 位 | 192.168.2.227 | docker+apache+PHP |
数据库集群 | CentOS 7.5 64 位 | MySQL 集群 |
四, Web 服务器部署
Web 服务器我这里用的是 LAMP 架构, 具体的安装部署请参考我的另一篇博文《CentOS 7 使用 docker 部署 LAMP 搭建 WordPress 博客系统》,http://blog.51cto.com/andyxu/2177116.
五, 安装配置 nginx
分别在 NGINX_MASTER,NGINX_BACKUP 两台服务器上操作
1, 部署 docker 环境
(1) 安装 docker
注: 安装的是 docker 社区版本
- yum install -y yum-utils device-mapper-persistent-data lvm2
- yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/Linux/CentOS/docker-ce.repo
- yum makecache fast
- yum -y install docker-ce
(2) 修改配置文件, 添加私有仓库地址和阿里云镜像地址, 并指定 docker 数据存储目录
- mkdir -p /data/docker
- mkdir -p /etc/docker
- VIM /etc/docker/daemon.JSON
- {
- "registry-mirrors": ["https://registry.docker-cn.com"], "graph": "/data/docker",
- "insecure-registries": ["192.168.2.225:5000"]
- }
(3) 启动 docker, 并加入开机启动
- systemctl start docker
- systemctl enable docker
2, 配置 nginx 容器
(1) 下载 nginx 镜像
docker pull nginx
(2) 复制 nginx 主配置文件到本地
- mkdir -p /data/docker/nginx/conf
- docker run --name tmp-nginx-container -d nginx:latest
- docker cp tmp-nginx-container:/etc/nginx/nginx.conf /data/docker/nginx/conf/
- docker rm -f tmp-nginx-container
(4) 创建运行 nginx 镜像的脚本
- VIM docker_nginx.sh
- #!/bin/bash
- docker run --name nginx --restart=always -p 80:80 \
- -v /data/docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
- -v /data/docker/nginx/conf/conf.d:/etc/nginx/conf.d \
- -v /data/docker/nginx/html:/usr/share/nginx/HTML \
- -v /data/docker/nginx/logs:/var/log/nginx \
- -d nginx:latest
注:--restart=always 是重启策略, 当 docker 服务重启后, 容器也会自动启动
(5) 启动 nginx 容器
sh docker_nginx.sh
(6) 修改 nginx 主配置文件
- VIM /data/docker/nginx/conf/nginx.conf
- user nginx;
- worker_processes 4; #工作进程数, 为 CPU 的核心数或者两倍
- error_log /var/log/nginx/error.log warn;
- pid /var/run/nginx.pid;
- events {
- use epoll; #Linux 最常用支持大并发的事件触发机制
- worker_connections 65535;
- }
- http {
- include /etc/nginx/mime.types; #设定 mime 类型, 类型由 mime.type 文件定义
- default_type application/octet-stream;
- log_format main '$remote_addr - $remote_user [$time_local]"$request" '
- '$status $body_bytes_sent"$http_referer" '
- '"$http_user_agent" "$http_x_forwarded_for"';
- access_log /var/log/nginx/access.log main;
- sendfile on;
- #tcp_nopush on;
- keepalive_timeout 120;
- #gzip on;
- limit_conn_zone $binary_remote_addr zone=perip:10m; #添加 limit_zone, 限制同一 IP 并发数
- include /etc/nginx/conf.d/*.conf; #包含 nginx 虚拟主机配置文件目录
- }
(7) 创建 upstream 配置文件
- VIM /data/docker/nginx/conf/conf.d/myhost.conf
- upstream xuad {
- ip_hash; #会话保持
- server 192.168.2.226 max_fails=1 fail_timeout=60s;
- server 192.168.2.227 max_fails=1 fail_timeout=60s;
- }
(8) 创建虚拟主机配置文件
- VIM /data/docker/nginx/conf/conf.d/xuad.conf
- server {
- listen 80;
- server_name localhost;
- #charset GB2312;
- location /
- {
- proxy_redirect off;
- 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_pass http://xuad;
- }
- # 查看 nginx 的并发连接数配置
- location /NginxStatus
- {
- stub_status on;
- access_log off;
- auth_basic "NginxStatus";
- }
- access_log off;
- error_page 404 /404.HTML;
- error_page 500 502 503 504 /404.HTML;
- location = /404.HTML {
- root HTML;
- }
- limit_conn perip 200; #同一 ip 并发数为 200, 超过会返回 503
- }
(9) 重启 nginx 容器
docker restart nginx
六, 安装配置 keepalived
分别在 NGINX_MASTER,NGINX_BACKUP 两台服务器上操作
1, 下载并安装 keepalived
注: keepalived 安装在实体机上
- yum install wget make gcc gcc-c++ openssl-devel
- wget http://www.keepalived.org/software/keepalived-2.0.7.tar.gz
- tar zxvf keepalived-2.0.7.tar.gz
- cd keepalived-2.0.7
- ./configure --prefix=/data/keepalived
如果报以下警告:
*** WARNING - this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.
不用担心, 我们只需要用到 VRRP 功能, 不需要用 IPVS 功能, 所以请确保以下三项是 yes 就行了.
- Use VRRP Framework : Yes
- Use VRRP VMAC : Yes
- Use VRRP authentication : Yes
- make make install
2, 将 keepalived 以服务方式启动
- mkdir /etc/keepalived
- cp /data/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/
- systemctl enable keepalived
3, 修改 keepalived 配置文件
- VIM /etc/keepalived/keepalived.conf
- ! Configuration File for keepalived
- global_defs {
- notification_email {
- xuad@xuad.com
- }
- notification_email_from root@xuad.com
- smtp_server mail.xuad.com
- smtp_connect_timeout 30
- router_id LVS_DEVEL
- vrrp_skip_check_adv_addr
- vrrp_strict
- vrrp_garp_interval 0
- vrrp_gna_interval 0
- }
- vrrp_script chk_nginx {
- script "/etc/keepalived/nginx_pid.sh" # 检查 nginx 状态的脚本
- interval 2
- weight 3
- }
- vrrp_instance VI_1 {
- state MASTER #备份服务器上将 MASTER 改为 BACKUP
- interface ens32
- virtual_router_id 51
- priority 100 #备份服务上将 100 改为小于 100, 可配置成 90
- advert_int 1
- authentication {
- auth_type PASS
- auth_pass 1111
- }
- virtual_ipaddress {
- 192.168.2.242 #有多个 vip 可在下面继续增加
- }
- track_script {
- chk_nginx
- }
- }
4, 添加检查 nginx 状态的脚本
- VIM /etc/keepalived/nginx_pid.sh
- #!/bin/bash
- #version 0.0.1
- #
- A=`ps -C nginx --no-header |wc -l`
- if [ $A -eq 0 ];then
- systemctl restart docker
- sleep 3
- if [ `ps -C nginx --no-header |wc -l` -eq 0 ];then
- systemctl stop keepalived
- fi
- fi
脚本说明: 当 nginx 进程不存在时, 会自动重启 docker 服务, docker 服务启动时会自动启动 nginx 容器; 再次检查 nginx 进程, 如果不存在, 就停止 keepalived 服务, 然后 NGINX_BACKUP 主机会自动接替 NGINX_MASTER 的工作.
chmod +x /etc/keepalived/nginx_pid.sh
5, 配置 firewalld 防火墙允许 vrrp 协议
- VRRP(Virtual Router Redundancy Protocol, 虚拟路由器冗余协议)
- firewall-cmd --permanent --add-rich-rule="rule family="ipv4"source address="192.168.2.229"protocol value="vrrp"accept"
- firewall-cmd --reload
如果是 backup 服务器, source address 改成 master 服务器的 IP
6, 启动 keepalived
systemctl start keepalived
七, 测试
1, 当 NGINX_MASTER,NGINX_BACKUP 服务器 nginx 均正常工作时
在 NGINX_MASTER 上:
在 NGINX_BACKUP 上:
master 服务器 ens32 网卡正常绑定 VIP, 而 backup 却没有绑定, 通过浏览器可正常访问网站.
2, 关闭 NGINX_MASTER 的 nginx 容器
当 nginx 容器停止后, 马上就又启起来了, nginx 启动脚本没问题
3, 关闭 NGINX_MASTER 的 keepalived 服务
在 NGINX_MASTER 上:
在 NGINX_BACKUP 上:
NGINX_BACKUP 的 ens32 网卡已瞬间绑定 VIP, 通过浏览器访问网站正常.
4, 将 NGINX_MASTER 的 keepalived 服务启动
在 NGINX_MASTER 上:
在 NGINX_BACKUP 上:
NGINX_MASTER 的 ens32 网卡重新绑定 VIP, 通过浏览器访问网站正常.
5, 关闭 WEB_1 服务器, 通过浏览器访问网站正常.
附 1: 配置时间同步
1, 在 NGINX_MASTER 和 NGINX_BACKUP 上安装 ntp
yum -y install ntp
2, 在 NGINX_MASTER 上修改 ntp 配置文件
添加以下两行
- server 127.127.1.0 iburst local clock #添加使用本地时间
- restrict 192.168.2.0 mask 255.255.255.0 nomodify #允许更新的 IP 地址段
3, 在 NGINX_MASTER 上启动 ntp 服务, 并加入开机启动
- systemctl start ntpd
- systemctl enable ntpd
4, 在 NGINX_MASTER 上添加防火墙策略
只允许 192.168.2.229 访问 ntp 服务
- firewall-cmd --permanent --add-rich-rule="rule family="ipv4"source address="192.168.2.229"port protocol="udp"port="123"accept"
- firewall-cmd --reload
5, 在 NGINX_BACKUP 上同步 NGINX_MASTER 的时间
ntpdate 192.168.2.228
6, 在 NGINX_BACKUP 上设置计划任务, 每天凌晨 5 点 01 分同步时间
- crontab -e
- 1 5 * * */usr/sbin/ntpdate 192.168.2.228>> /var/log/upClock.log
来源: http://blog.51cto.com/andyxu/2286045