Apr 6, 2022 No Comments Docker容器中部署高可用的前后端分离的Java Web项目 ## Docker容器中部署高可用的前后端分离的Java Web项目 ![](https://csdnimg.cn/release/blogv2/dist/pc/img/original.png) 版权声明:本文为博主原创文章,遵循 [CC 4.0 BY-SA](http://creativecommons.org/licenses/by-sa/4.0/) 版权协议,转载请附上原文出处链接和本声明。 ### Docker容器中部署高可用的前后端分离的Java Web项目 + [1 项目说明](#1__1) + + [1.1 项目运行效果](#11__2) + [1.2 项目运行环境](#12__8) + [1.3 项目组成架构](#13__21) + [1.4 项目部署总览](#14__23) + [2 准备工作](#2__28) + + [2.1 下载项目源代码](#21__29) + [2.2 创建Docker网络](#22_Docker_39) + [2.3 查看本机IP地址](#23_IP_75) + [3 搭建高可用的MySQL集群](#3_MySQL_78) + + [3.1 搭建PXC集群](#31_PXC_79) + + [3.1.1 集群方案选择](#311__80) + [3.1.2 拉取Docker镜像](#312_Docker_84) + [3.1.3 创建Docker数据卷](#313_Docker_91) + [3.1.4 创建PXC容器](#314_PXC_98) + [3.1.5 连接PXC容器](#315_PXC_128) + [3.1.6 验证PXC集群](#316_PXC_131) + [3.2 实现集群负载均衡](#32__136) + + [3.2.1 集群负载均衡方案](#321__137) + [3.2.2 拉取Docker镜像](#322_Docker_140) + [3.2.3 创建haproxy配置](#323_haproxy_145) + [3.2.4 创建haproxy容器](#324_haproxy_202) + [3.2.5 查看集群监控页面](#325__221) + [3.2.6 验证集群负载均衡](#326__238) + [3.3 实现集群高可用](#33__244) + + [3.3.1 集群高可用方案](#331__245) + [3.3.2 安装Keepalived软件](#332_Keepalived_248) + [3.3.3 创建Keepalived配置](#333_Keepalived_262) + [3.3.4 验证虚拟IP抢占](#334_IP_286) + [3.3.5 验证集群高可用](#335__299) + [4 搭建高可用的Redis集群](#4_Redis_310) + + [4.1 集群方案选择](#41__311) + [4.2 拉取Docker镜像](#42_Docker_314) + [4.3 创建Docker数据卷](#43_Docker_319) + [4.4 创建Redis配置](#44_Redis_329) + [4.5 创建Redis容器](#45_Redis_338) + [4.6 配置Redis集群](#46_Redis_390) + [4.7 测试Redis集群](#47_Redis_407) + [5 搭建高可用的API服务](#5_API_440) + + [5.1 搭建API服务集群](#51_API_441) + + [5.1.1 创建API数据库](#511_API_442) + [5.1.2 修改API配置](#512_API_446) + [5.1.3 打包API项目](#513_API_453) + [5.1.4 构建API镜像](#514_API_459) + [5.1.5 创建API容器](#515_API_476) + [5.1.6 访问API服务](#516_API_504) + [5.2 实现集群负载均衡](#52__511) + + [5.2.1 集群负载均衡方案](#521__512) + [5.2.2 拉取Docker镜像](#522_Docker_515) + [5.2.3 创建Nginx配置](#523_Nginx_520) + [5.2.4 创建Nginx容器](#524_Nginx_570) + [5.2.5 验证集群负载均衡](#525__590) + [5.3 实现集群高可用](#53__600) + + [5.3.1 集群高可用方案](#531__601) + [5.3.2 安装Keepalived软件](#532_Keepalived_604) + [5.3.3 创建Keepalived配置](#533_Keepalived_606) + [5.3.4 验证虚拟IP抢占](#534_IP_630) + [5.3.5 验证集群高可用](#535__633) + [6 搭建高可用的Web服务](#6_Web_644) + + [6.1 搭建Web服务集群](#61_Web_645) + + [6.1.1 修改Web配置](#611_Web_646) + [6.1.2 打包Web项目](#612_Web_652) + [6.1.3 构建Web镜像](#613_Web_660) + [6.1.4 创建Web容器](#614_Web_734) + [6.1.5 访问Web服务](#615_Web_756) + [6.2 实现集群负载均衡](#62__765) + + [6.2.1 集群负载均衡方案](#621__766) + [6.2.2 拉取Docker镜像](#622_Docker_769) + [6.2.3 创建Nginx配置](#623_Nginx_774) + [6.2.4 创建Nginx容器](#624_Nginx_836) + [6.2.5 验证集群负载均衡](#625__856) + [6.3 实现集群高可用](#63__867) + + [6.3.1 集群高可用方案](#631__868) + [6.3.2 安装Keepalived软件](#632_Keepalived_871) + [6.3.3 创建Keepalived配置](#633_Keepalived_873) + [6.3.4 验证虚拟IP抢占](#634_IP_897) + [6.3.5 验证集群高可用](#635__900) + [7 总结](#7__910) ## 1 项目说明 ## 1.1 项目运行效果 ## 1.2 项目运行环境 + 运行环境版本说明: | 环境名称 | 环境版本 | 环境说明 | | --- | --- | --- | | Ubuntu | ubuntu-18.04.3-desktop-amd64 | 虚拟机操作系统 | | Docker | 19.03.5 | Docker容器版本 | | Java | 8 | 后端API服务运行环境 | | MySQL | latest | 存储数据库 | | Redis | latest | 缓存数据库 | | Nginx | latest | 前端Web服务运行环境 | | Haproxy | latest | 集群负载均衡工具软件 | | Keepalived | | 虚拟高可用工具软件 | ## 1.3 项目组成架构 + 项目组成架构:该前端后分离的项目由一个高可用且具有负载均衡的MySQL存储服务集群,一个高可用的Redis缓存服务集群、一个高可用且具有负载均衡的API服务集群、一个高可用且具有负载均衡的Web服务集群组成。 ## 1.4 项目部署总览 + 项目部署总览: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200331103641403.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + **项目部署说明:所有的容器节点都部署在一台基于虚拟机的Ubuntu操作系统的Docker环境中,且都在同一个Docker网络中,因此所有容器节点之间可以相互访问。因为没有做容器内部虚拟IP和主机IP之间的映射,所以只能在基于虚拟机的Ubuntu操作系统中才能访问虚拟IP,而在虚拟机所在的宿主机中无法访问虚拟IP。而所有的容器节点都做了端口映射,把基于虚拟机的Ubuntu操作系统的指定端点映射到了容器节点的指定端点,所以可以通过特定方式在虚拟机所在的宿主机中访问容器节点。** ## 2 准备工作 ## 2.1 下载项目源代码 + 项目说明:本项目使用的是人人开源社区当中的renren-fast项目,该项目是开源的Java Web前后端分离项目,功能较为丰富,且具有较高的代码质量。后端是基于Spring Boot技术构建的Java项目,前端基于Vue.js和Element-UI组件开发。 + 下载地址: ```txt https://www.renren.io/community/project ``` + 下载说明:访问上述地址后界面如下图所示,分别下载前端源码和后端源码。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200219165129112.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 2.2 创建Docker网络 + 项目网络说明:本次部署的高可用的前后端分离项目所涉及到的各个容器全部都在同一个Docker网络中,这样部署在该网络中的各个容器之间就可以相互访问。 + 创建Docker网络: ```txt docker network create --subnet 172.20.0.0/16 net-renren ``` + 容器网络规划:这里列举了所有容器节点的IP,在创建容器节点时会指定IP地址。 | 节点类型 | 容器名称 | 容器IP | 说明 | | --- | --- | --- | --- | | PXC | pxc-node1 | 172.20.0.2 | MySQL工作节点 | | PXC | pxc-node2 | 172.20.0.3 | MySQL工作节点 | | PXC | pxc-node3 | 172.20.0.4 | MySQL工作节点 | | PXC | haproxy-pxc1 | 172.20.0.11 | MySQL集群负载均衡节点 | | PXC | haproxy-pxc2 | 172.20.0.12 | MySQL集群负载均衡节点 | | PXC | | 172.20.0.100 | MySQL集群高可用的访问地址(虚拟IP地址) | | | | | | | Redis | redis-node1 | 172.20.1.2 | Redis工作节点 | | Redis | redis-node2 | 172.20.1.3 | Redis工作节点 | | Redis | redis-node3 | 172.20.1.4 | Redis工作节点 | | Redis | redis-node4 | 172.20.1.5 | Redis工作节点 | | Redis | redis-node5 | 172.20.1.6 | Redis工作节点 | | Redis | redis-node6 | 172.20.1.7 | Redis工作节点 | | | | | | | API | api-node1 | 172.20.2.2 | API工作节点 | | API | api-node2 | 172.20.2.3 | API工作节点 | | API | api-node3 | 172.20.2.4 | API工作节点 | | API | nginx-api1 | 172.20.2.11 | API集群负载均衡节点 | | API | nginx-api2 | 172.20.2.12 | API集群负载均衡节点 | | API | | 172.20.2.100 | API服务集群高可用的访问地址(虚拟IP地址) | | | | | | | Web | web-node1 | 172.20.3.2 | Web工作节点 | | Web | web-node2 | 172.20.3.3 | Web工作节点 | | Web | web-node3 | 172.20.3.4 | Web工作节点 | | Web | nginx-web1 | 172.20.3.11 | Web集群负载均衡节点 | | Web | nginx-web2 | 172.20.3.12 | Web集群负载均衡节点 | | Web | | 172.20.3.100 | Web服务集群高可用的访问地址(虚拟IP地址) | ## 2.3 查看本机IP地址 + 查看本机IP地址:使用 ip a 命令可以查看本机IP地址如下图所示,可知本机IP地址为**192.168.0.114**,后面会多次使用到这个地址。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200220104831232.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 3 搭建高可用的MySQL集群 ## 3.1 搭建PXC集群 ### 3.1.1 集群方案选择 + Republication方案:MySQL官方的Republication方案是单向同步、弱一致性的集群解决方案。 + PXC方案:PXC方案是双向同步、强一致性的集群解决方案。 + MySQL集群说明:此次使用的是PXC集群方案,搭建的PXC集群中包含三个PXC节点(一般建议集群的节点个数为大于1的奇数)。 ### 3.1.2 拉取Docker镜像 + 拉取镜像:由于镜像名称太长,不便于书写,所以对镜像进行重命名。 ```txt docker pull percona/percona-xtradb-cluster:latest docker tag percona/percona-xtradb-cluster:latest pxc:latest docker rmi percona/percona-xtradb-cluster:latest ``` ### 3.1.3 创建Docker数据卷 + 创建数据卷: ```txt docker volume create pxc1 docker volume create pxc2 docker volume create pxc3 ``` ### 3.1.4 创建PXC容器 + 创建并启动pxc容器:该PXC集群中的三个节点的名称分别为pxc-node1、pxc-node2、pxc-node3,具体的创建命令信息如下所示。 ```txt # 创建名称为pxc-node1的pxc容器,该容器的ip地址为172.20.0.2,主机的3001端口映射到该容器的3306端口,用户名为root,密码为123456 docker run -d -p 3001:3306 -v pxc1:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ -e XTRABACKUP_PASSWORD=123456 \ -e CLUSTER_NAME=pxc-cluster \ --privileged --name=pxc-node1 --net=net-renren --ip=172.20.0.2 pxc:latest # 创建名称为pxc-node2的pxc容器,该容器的ip地址为172.20.0.3,主机的3002端口映射到该容器的3306端口,用户名为root,密码为123456 docker run -d -p 3002:3306 -v pxc2:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ -e XTRABACKUP_PASSWORD=123456 \ -e CLUSTER_NAME=pxc-cluster \ -e CLUSTER_JOIN=pxc-node1 \ --privileged --name=pxc-node2 --net=net-renren --ip=172.20.0.3 pxc:latest # 创建名称为pxc-node3的pxc容器,该容器的ip地址为172.20.0.4,主机的3003端口映射到该容器的3306端口,用户名为root,密码为123456 docker run -d -p 3003:3306 -v pxc3:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ -e XTRABACKUP_PASSWORD=123456 \ -e CLUSTER_NAME=pxc-cluster \ -e CLUSTER_JOIN=pxc-node1 \ --privileged --name=pxc-node3 --net=net-renren --ip=172.20.0.4 pxc:latest ``` + 查看PXC容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200220105309508.png) ### 3.1.5 连接PXC容器 + 连接PXC容器:由创建pxc容器的命令可知,pxc-node1容器映射到主机的3001端口,连接用户名为 root,连接密码为 123456。在主机上使用Navicat for MySQL的客户端工具连接pxc-node1容器如下图所示,连接成功后以同样的方式分别连接pxc-node2容器和pxc-node3容器。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200220110957988.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 3.1.6 验证PXC集群 + 验证PXC集群:使用Navicat for MySQL客户端连接工具连接该PXC集群中的pxc-node1、pxc-node2、pxc-node这3三个节点,连接成功后如下图所示。如果在其中一个节点中创建一个数据库(数据库名称自定),然后刷新其它两个节点,如果在其它两个节点中也成功出现了新建的数据库,则表示集群中的各节点之间同步成功,即表示PXC集群创建成功。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200220111833245.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 3.2 实现集群负载均衡 ### 3.2.1 集群负载均衡方案 + 集群负载均衡方案:本文通过haproxy技术来实现MySQL集群的负载均衡访问,创建的haproxy容器节点会把对MySQL集群的访问负载均衡到三个数据库节点上,默认选用了轮询的负载远程策略。负载均衡方案如下图所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200331121149490.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 3.2.2 拉取Docker镜像 + 拉取Haproxy镜像: ```txt docker pull haproxy:latest ``` ### 3.2.3 创建haproxy配置 + 配置文件:在 /home/soft/config/pxc/haproxy/haproxy-node1 目录和 /home/soft/config/pxc/haproxy/haproxy-node2 目录下各创建一个haproxy.cfg配置文件,两个配置文件内容完全相同,文件内容如下所示。 ```txt # Haproxy配置可分成为部分,这五部分不是必选的,可以根据需要进行配置: # global: 进程参数配置,通常和操作系统相关,只配置一次 # defaults: 默认参数配置,可以被用到frontend、backend、listen部分 # frontend: 接收请求的前端虚拟节点,可以根据规则直接指定具体使用的backend(可动态选择) # backend: 后端服务集群的配置,是真实的服务,一个backend对应一个或多个实体服务器 # listen: frontend和backend的组合体 ########## global参数配置 ########## global log 127.0.0.1 local0 err # 日志配置,使用rsyslog服务中local0日志设备(/var/log/local5),等级err chroot /usr/local/etc/haproxy # 当前工作目录 daemon # 守护进程运行 nbproc 1 # 进程数量 ########## defaults参数配置 ########## defaults mode http # 模式:默认{tcp:http:health},tcp是4层,http是7层,health只会返回ok,如果要让haproxy支持虚拟机,mode必须设为http log global # 日志配置 option httplog # 采用http日志格式 option dontlognull # 日志中不记录负载均衡的心跳检测记录 option http-server-close # 每次请求完毕后主动关闭http通道 option redispatch # 当serverId对应的服务器挂掉后,强制定向到其他健康的服务器 maxconn 4096 # 默认的最大连接数 retries 3 # 两次连接失败就认为是服务器不可用,也可以通过后面设置 timeout connect 5000ms # 连接超时 timeout server 50000ms # 服务器超时 timeout client 50000ms # 客户端超时 timeout check 5000ms # 心跳检测超时 balance roundrobin # 负载均衡算法:static-rr 权重, leastconn 最少连接, source 请求IP, 轮询 roundrobin ########## 监控界面配置 ########## listen admin_status mode http # 模式 bind 0.0.0.0:8888 # 监控端口 stats enable # 开启监控 stats uri /dbs # 统计页面url stats auth admin:123456 # 统计页面用户名和密码设置 stats realm Global\ statistics # 统计报告格式 stats refresh 30s # 统计页面自动刷新时间 option httplog # 采用http日志格式 ########## mysql负载均衡配置 ########## listen proxy-mysql mode tcp # 模式 bind 0.0.0.0:3306 # 监控端口 balance roundrobin # 负载均衡算法: static-rr 权重, leastconn 最少连接, source 请求IP, 轮询 roundrobin option mysql-check user haproxy # 心跳检测账户:在mysql创建一个没有权限的haproxy用户,密码为空。create user 'haproxy'@'%' identified by ''; FLUSH PRIVILEGES; option tcplog # 采用tcp日志格式 server pxc-node1 172.20.0.2:3306 check weight 1 maxconn 2000 # 容器的IP地址,轮询策略时,权重没有生效 server pxc-node2 172.20.0.3:3306 check weight 1 maxconn 2000 server pxc-node3 172.20.0.4:3306 check weight 1 maxconn 2000 ``` + **特别说明:如果只是想实现PXC集群的负载均衡,则只需要创建一个haproxy配置文件和一个haproxy容器即可。这里创建了两个配置文件,是因为在3.3.3小节中需要创建两个haproxy容器(都具有负载均衡的特性),而在3.3.4小节中会使用这两个haproxy容器实现PXC集群的高可用。** ### 3.2.4 创建haproxy容器 + 创建haproxy容器:创建的haproxy容器的配置文件默认为容器内部的/usr/local/etc/haproxy目录下的名为haproxy.cfg的文件,这里使用映射的方式将3.2.3节中在主机中创建的配置文件映射到容器内部。 ```txt # 创建名称为haproxy-pxc1的haproxy容器,该容器的ip地址为172.20.0.11,主机的4001/4002端口分别映射到该容器的8888/3306端口 # 主机中的/home/soft/config/pxc/haproxy/haproxy-node1目录映射到haproxy-pxc1容器中的/usr/local/etc/haproxy目录 docker run -it -d -p 4001:8888 -p 4002:3306 \ -v /home/soft/config/pxc/haproxy/haproxy-node1:/usr/local/etc/haproxy \ --privileged --name=haproxy-pxc1 --net=net-renren --ip=172.20.0.11 haproxy:latest # 创建名称为haproxy-pxc2的haproxy容器,该容器的ip地址为172.20.0.12,主机的4003/4004端口分别映射到该容器的8888/3306端口 # 主机中的/home/soft/config/pxc/haproxy/haproxy-node2目录映射到haproxy-pxc1容器中的/usr/local/etc/haproxy目录 docker run -it -d -p 4003:8888 -p 4004:3306 \ -v /home/soft/config/pxc/haproxy/haproxy-node2:/usr/local/etc/haproxy \ --privileged --name=haproxy-pxc2 --net=net-renren --ip=172.20.0.12 haproxy:latest ``` + 查看haproxy容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020031914532361.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 3.2.5 查看集群监控页面 + 访问集群监控页面:3.2.3小节中创建了两个负载均衡的PXC集群访问节点,其中主机的4001端口映射到了haproxy-pxc1节点的集群监控管理页面的8888端口,主机的4002端口映射到了haproxy-pxc2节点的集群监控管理页面的8888端口,所以在浏览器中访问以下地址即可进入到haproxy的集群监控登录页面,登录后的页面如下图所示: ```txt # 登录名:admin 密码:123456 192.168.0.114:4001/dbs ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200224142324404.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 集群节点状态说明:从上图中可以看到,该集群中一共有pxc-node1、pxc-node2、pxc-node3这三个节点,但是这三个节点的Status列显示的都是DOWN,说明集群监控管理功能异常。这是因为haproxy默认需要使用一个名称为haproxy且密码为空的数据库用户来监控集群中各节点的心跳,而我们目前还没有在PXC集群中创建该心跳检测用户。 + 创建心跳检测用户:在Navicat for MySQL客户端中的任意一个集群节点上执行以下命令,即可在PXC集群中创建心跳检测用户。 ```txt create user 'haproxy'@'%' identified by ''; FLUSH PRIVILEGES; ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200224143338845.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 刷新集群监控页面:创建了心跳检测用户之后,再刷新集群监控后如下图所示,可见PXC集群中的三个节点的Status已经变成了UP,而且背景颜色也由红色变成了绿色,说明集群状态监控功能正常。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200224143614435.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 3.2.6 验证集群负载均衡 ## 3.3 实现集群高可用 ### 3.3.1 集群高可用方案 + 集群高可用方案:本文通过keepalived技术来实现多个负载均衡访问节点之间争抢虚拟IP,争抢到虚拟IP地址的负载均衡访问节点则对外提供服务,未争抢到虚拟IP地址的负载均衡访问节点则不会对外提供服务。如果已经争抢到虚拟IP地址的负载均衡访问节点出现故障而不可用,则另外一个负载均衡访问节点就会争抢到虚拟IP,进而对外提供服务,从而达到集群高可用的目的。本文创建的两个负载均衡访问节点是主主结构,而不是主备结构,高可用方案如下图所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200331121300474.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 3.3.2 安装Keepalived软件 + 进入haproxy容器:执行以下Docker命令,即可以进入到haproxy-pxc1容器内部。 ```txt docker exec -it haproxy-pxc1 bash ``` + 更新软件包列表:进入到haproxy-pxc1容器内部后,执行以下Linux命令先更新软件包列表。 ```txt apt-get update ``` + 安装keepalived软件:软件包列表更新完毕后,执行以下Linux命令即可以安装keepalived软件。 ```txt apt-get install keepalived ``` + **特别说明:在haproxy-pxc1和haproxy-pxc2这两个容器内部都需要安装keepalived软件。** ### 3.3.3 创建Keepalived配置 + 配置文件:keepalived软件的默认配置文件为/etc/keepalived目录下的keepalived.conf文件,所以需要在haproxy-pxc1、haproxy-pxc2容器内部的/etc/keepalived目录下分别创建一个keepalived.conf配置文件,两个配置文件内容完全相同,文件内容如下所示: ```txt vrrp_instance haproxy-pxc { state MASTER interface eth0 virtual_router_id 99 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 172.20.0.100 } } ``` + **特别说明:keepalived.conf配置文件不能具有可执行的权限,否则keepalived会启动失败,可以将权限设置为644(rx-r- -r- -)。** ```txt sudo chmod 644 keepalived.conf ``` ### 3.3.4 验证虚拟IP抢占 + 查看容器IP地址:在haproxy-pxc1容器内部启动keepalived之前,先通过执行 **ip a** 这条Linux命令查看haproxy-pxc1容器的IP地址,结果如下图所示,从图中可看出此时haproxy-pxc1容器只有一个IP地址,即创建该容器时指定的IP地址172.20.0.11。以同样的方式可以查看到,在haproxy-pxc2容器内部启动keepalived之前,haproxy-pxc2容器也只有一个IP地址,即创建该容器时指定的IP地址172.20.0.12。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200224174928340.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 启动keepalived服务:在haproxy-pxc1容器内部启动keepalived之后,再执行 ip a 命令查看haproxy-pxc1容器的IP地址,结果如下图所示,从图中可看出此时haproxy-pxc1容器除了拥有创建容器时指定的IP地址172.20.0.11之外,还拥有抢占的虚拟IP地址172.20.0.100。以同样的方式进入到haproxy-pxc2容器内部并启动keepalived,再执行 ip a 命令查看haproxy-pxc2容器的IP地址,结果如下图所示,从图中可以看出haproxy-pxc2容器只有创建容器时分配的172.20.0.12那个IP地址,而没有虚拟IP地址,因为虚拟IP地址已经被haproxy-pxc1节点抢占了。 ```txt # 容器内部启动 keepalived 的命令 service keepalived start ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200224172017645.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 查看虚拟IP抢占:在haproxy-pxc1容器抢占到虚拟IP地址的情况下,当把haproxy-pxc1容器暂停掉,再进入到haproxy-pxc2容器内部并通执行 ip a 命令,结果如下图所示,从图中可以看到,此时haproxy-pxc2容器除了拥有创建容器时分配的IP地址172.20.0.12之外,还拥有抢占的虚拟IP地址172.0.20.100,说明haproxy-pxc2容器成功抢占到了虚拟IP。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200224174650228.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 3.3.5 验证集群高可用 ## 4 搭建高可用的Redis集群 ## 4.1 集群方案选择 + 集群方案选择:本文使用的是Redis官方的主从模型的集群方案,搭建的Redis集群由6个Redis节点组成,其中3个主节点,3个备用节点,集群方案如下图所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/2020033112540179.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 4.2 拉取Docker镜像 + 拉取Docker镜像: ```txt docker pull redis:latest ``` ## 4.3 创建Docker数据卷 + 创建Docker数据卷: ```txt docker volume create redis1 docker volume create redis2 docker volume create redis3 docker volume create redis4 docker volume create redis5 docker volume create redis6 ``` ## 4.4 创建Redis配置 + 配置文件:由于需要创建六个Redis节点,为了使得每个节点都拥有独立的配置,所以每个节点都需要拥有一个独立的配置文件。在/home/soft/config/redis目录下创建redis-node1、redis-node2、redis-node3、redis-node4、redis-node5、redis-node6 这6个子目录,并在每个子目录下都创建一个名称为redis.conf文件的Redis配置文件,这6个配置文件的内容全都一样,内容如下所示: ```txt # daemonize yes cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 15000 appendonly yes ``` ## 4.5 创建Redis容器 + 创建Redis容器:创建的redis容器使用容器内部的/usr/local/etc/redis/redis.conf文件为配置文件,这里使用映射的方式将4.4节中在主机中创建的配置文件映射到容器内部。该集群中一个包含6个Redis节点,各节点创建命令如下所示。 ```txt # 创建名称为redis-node1的redis容器,该容器的ip地址为172.20.1.2,主机的5001端口映射到该容器的6379端口 # 主机中的/home/soft/config/redis/redis-node1目录映射到该容器中的/usr/local/etc/redis目录 docker run -it -d -p 5001:6379 -v redis1:/data \ -v /home/soft/config/redis/redis-node1:/usr/local/etc/redis \ --privileged --name=redis-node1 --net=net-renren --ip=172.20.1.2 \ redis:latest redis-server /usr/local/etc/redis/redis.conf # 创建名称为redis-node2的redis容器,该容器的ip地址为172.20.1.3,主机的5002端口映射到该容器的6379端口 # 主机中的/home/soft/config/redis/redis-node2目录映射到该容器中的/usr/local/etc/redis目录 docker run -it -d -p 5002:6379 -v redis2:/data \ -v /home/soft/config/redis/redis-node2:/usr/local/etc/redis \ --privileged --name=redis-node2 --net=net-renren --ip=172.20.1.3 \ redis:latest redis-server /usr/local/etc/redis/redis.conf # 创建名称为redis-node3的redis容器,该容器的ip地址为172.20.1.4,主机的5003端口映射到该容器的6379端口 # 主机中的/home/soft/config/redis/redis-node3目录映射到该容器中的/usr/local/etc/redis目录 docker run -it -d -p 5003:6379 -v redis3:/data \ -v /home/soft/config/redis/redis-node3:/usr/local/etc/redis \ --privileged --name=redis-node3 --net=net-renren --ip=172.20.1.4 \ redis:latest redis-server /usr/local/etc/redis/redis.conf # 创建名称为redis-node4的redis容器,该容器的ip地址为172.20.1.5,主机的5004端口映射到该容器的6379端口 # 主机中的/home/soft/config/redis/redis-node4目录映射到该容器中的/usr/local/etc/redis目录 docker run -it -d -p 5004:6379 -v redis4:/data \ -v /home/soft/config/redis/redis-node4:/usr/local/etc/redis \ --privileged --name=redis-node4 --net=net-renren --ip=172.20.1.5 \ redis:latest redis-server /usr/local/etc/redis/redis.conf # 创建名称为redis-node5的redis容器,该容器的ip地址为172.20.1.6,主机的5005端口映射到该容器的6379端口 # 主机中的/home/soft/config/redis/redis-node5目录映射到该容器中的/usr/local/etc/redis目录 docker run -it -d -p 5005:6379 -v redis5:/data \ -v /home/soft/config/redis/redis-node5:/usr/local/etc/redis \ --privileged --name=redis-node5 --net=net-renren --ip=172.20.1.6 \ redis:latest redis-server /usr/local/etc/redis/redis.conf # 创建名称为redis-node6的redis容器,该容器的ip地址为172.20.1.7,主机的5006端口映射到该容器的6379端口 # 主机中的/home/soft/config/redis/redis-node6目录映射到该容器中的/usr/local/etc/redis目录 docker run -it -d -p 5006:6379 -v redis6:/data \ -v /home/soft/config/redis/redis-node6:/usr/local/etc/redis \ --privileged --name=redis-node6 --net=net-renren --ip=172.20.1.7 \ redis:latest redis-server /usr/local/etc/redis/redis.conf ``` + 查看Redis容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200319141351907.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 4.6 配置Redis集群 + 配置Redis集群:在4.5小节中创建的6个redis容器节点还是独立的redis服务节点,还并没有组建成为一个集群,此时需要进入到任意一个redis容器节点中,并执行以下命令才能把这6个节点组建成为一个集群。在执行该命令的过程中,会自动提出一种主备节点的方案,并要求用户手动输入 “yes” 同意这种方案才能继续组建,组建成功之后会显示所有的节点都已加入到该集群,执行过程和结果如下图所示。 ```txt # 进入 redis-node1 容器内部 docker exec -it redis-node1 bash # 配置Redis集群 redis-cli --cluster create \ 172.20.1.2:6379 \ 172.20.1.3:6379 \ 172.20.1.4:6379 \ 172.20.1.5:6379 \ 172.20.1.6:6379 \ 172.20.1.7:6379 \ --cluster-replicas 1 ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200319150120402.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 4.7 测试Redis集群 + 测试Redis集群:集群组建完成之后,可以先进入到 redis-node1 容器节点并设置一个键值对,然后再进入到另外一个容器节点中查看是否存在同名的键值对,如果存在则表示集群各节点之间同步成功,否则可能是集群没有配置成功。测试执行命令和执行过程如下所示。 ```txt # 进入到 redis-node1 容器内部 docker exec -it redis-node1 bash # 使用 redis-cli客户端工具连接redis redis-cli -c -p 6379 # 设置键为 username 值为 zhangsan set username zhangsan # 查看键为 username 的值 get username # 退出 redis连接 exit # 退出 redis-node1容器 exit # 进入到redis-node2容器内部 docker exec -it redis-node2 bash # 使用 redis-cli客户端工具连接redis redis-cli -c -p 6379 # 查看键为 username 的值 get username ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200319141127328.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 5 搭建高可用的API服务 ## 5.1 搭建API服务集群 ### 5.1.1 创建API数据库 ### 5.1.2 修改API配置 + 修改说明:从人人开源网站把后端项目源码下载下来之后,需要修改后端项目的配置文件,主要是修改端口号,Redis缓存配置和MySQL数据库配置。 + 修改端口号和Redis配置:修改src/main/resources目录下的application.yml配置文件,修改端口号为8000,设置启用redis缓存,并指定Redis为第4节中搭建的Redis集群,如下图所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200319162032644.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 修改MySQL数据库配置:项目中有开发、测试、生产三种环境的配置文件,读者可根据自己的情况来选择发布API服务时使用哪种环境的配置文件。本文使用测试环境,所以需要修改src/main/resources目录下的application-test.yml文件,指定MySQL数据库为第3节中搭建的PXC集群,如下图所示。**注意:这里需要指定MySQL数据库的IP地址为PXC集群高可用的访问地址 172.20.0.100。** ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200319161801325.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 5.1.3 打包API项目 + 打包API项目:配置文件修改完成之后,即可把后端项目生成 Jar 包,用于制作Docker镜像。本文是在IDEA开发工具中使用以下Maven命令来生成Jar包,命令执行完毕并构建成功之后,项目路径下的target目录下renren-fast.jar文件即为生成的Jar包。 ```txt mvn clean package ``` ### 5.1.4 构建API镜像 + 上传Jar包:由于需要使用生成的Jar包和Dockerfile文件来构建API项目的Docker镜像,所以需要先把5.1.3节中生成的renren-fast.jar包上传到安装了Docker环境的Linux系统中,本文把生成的Jar包放入到Linux系统的 **/usr/local/app/renren-fast/api** 目录下。 + 编写Dockerfile文件:本文使用Dockerfile文件构建API项目的Docker镜像,所以需要准备一下Dockerfile文件。在Linux系统的 **/usr/local/app/renren-fast/api** 目录下创建一个Dockerfile文件,内容如下所示: ```txt FROM openjdk:8 EXPOSE 8000 COPY ./renren-fast.jar app.jar ENTRYPOINT ["java","-jar","-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}","/app.jar"] ``` + 构建Docker镜像:使用命令行工具进入到Dockerfile文件所在目录下,并执行以下命令即可构建镜像,执行过程如下图所示。 ```txt docker build -t renren-fast-api:latest . ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200319165658448.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 查看生成的镜像:使用 docker images 命令即可以查看本地已有的所有的镜像列表,本文中生成的API项目的Docker镜像的名称为 renren-fast-api,版本为 latest。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200319165833278.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 5.1.5 创建API容器 ### 5.1.6 访问API服务 + 访问API服务:API容器启动成功后,即可通过浏览器访问API服务的swagger接口页面,如果访问成功,则说明API服务启动成功。**在虚拟机中**的浏览器中访问api-node1节点的API服务的swagger接口页面的URL和结果如下所示: ```txt http://172.20.2.2:8000/renren-fast/swagger/index.html ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320100526420.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 5.2 实现集群负载均衡 ### 5.2.1 集群负载均衡方案 + 集群负载均衡方案:本文通过nginx技术来实现API集群的负载均衡访问,创建的nginx容器节点会把对API集群的访问负载均衡到三个API节点上,默认选用了轮询的负载远程策略。负载均衡方案如下图所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200331122236997.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 5.2.2 拉取Docker镜像 + 拉取Docker容器: ```txt docker pull nginx:latest ``` ### 5.2.3 创建Nginx配置 + 配置文件:在 /home/soft/config/api/nginx/nginx-node1 目录和 /home/soft/config/api/nginx/nginx-node2 目录下各创建一个nginx.conf配置文件,两个配置文件内容完全相同,文件内容如下所示: ```txt http { include /etc/nginx/mime.types; 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 65; #gzip on; 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; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; upstream tomcat { server 172.20.2.2:8000; server 172.20.2.3:8000; server 172.20.2.4:8000; } server { listen 8000; server_name 127.0.0.1; location / { proxy_pass http://tomcat; index index.html; } } } ``` + **特别说明:如果只是想实现API服务集群的负载均衡,则只需要创建一个nginx配置文件和一个nginx容器即可。这里创建了两个配置文件,是因为在5.2.4小节中需要创建两个nginx容器(都具有负载均衡的特性),而在5.2.5小节中会使用这两个nginx容器实现API服务集群的高可用。** ### 5.2.4 创建Nginx容器 + 创建nginx容器:创建的nginx容器的配置文件为容器内部的/etc/nginx目录下的名为nginx.conf的文件,这里使用映射的方式将5.2.3节中在主机中创建的配置文件映射到容器内部。 ```txt # 创建名称为nginx-api1的nginx容器,该容器的ip地址为172.20.2.11,主机的8101端口映射到该容器的8000端口 docker run -it -d -p 8101:8000 \ -v /home/soft/config/api/nginx/nginx-node1:/usr/local/etc/nginx \ -v /home/soft/config/api/nginx/nginx-node1/nginx.conf:/etc/nginx/nginx.conf \ --privileged --name=nginx-api1 --net=net-renren --ip=172.20.2.11 nginx:latest # 创建名称为nginx-api2的nginx容器,该容器的ip地址为172.20.2.12,主机的8102端口映射到该容器的8000端口 docker run -it -d -p 8102:8000 \ -v /home/soft/config/api/nginx/nginx-node2:/usr/local/etc/nginx \ -v /home/soft/config/api/nginx/nginx-node2/nginx.conf:/etc/nginx/nginx.conf \ --privileged --name=nginx-api2 --net=net-renren --ip=172.20.2.12 nginx:latest ``` + 查看nginx容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320105132178.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 5.2.5 验证集群负载均衡 + 访问负载均衡节点:5.2.4节中创建了两个名称分别为nginx-api1和nginx-api2的具有负载均衡特性的API服务集群访问节点,其中主机的8101端口映射到了nginx-api1节点的8000端口,主机的8102端口映射到了nginx-api2节点的8000端口。**在虚拟机中**的浏览器中访问nginx-api1节点的API服务的swagger接口页面的URL和结果如下所示: ```txt http://172.20.2.11:8000/renren-fast/swagger/index.html ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320111426334.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 验证集群负载均衡:创建的负载均衡访问节点默认是使用轮询的负载均衡策略,对nginx-api1节点或nginx-api2节点的访问会被负载均衡到api-node1、api-node2、api-node3节点上。作为负载均衡访问节点,一般是对外暴露nginx-api1或nginx-api2节点的访问方式,而不会对外暴露api-node1、api-node2、api-node3节点的访问方式。读者可以自行试验当暂停掉一部分API服务节点时,访问负载均衡节点能否访问成功,以及暂停掉所有的API服务节点时,访问负载远程节点又能否访问成功。 + **特别说明:虽然nginx-api1节点负载均衡到了api-node1、api-node2、api-node3节点,但是nginx-api1节点仍然存在单点故障的风险,如果nginx-api1节点服务不可用,则整个集群就不可用了,所以需要实现集群访问节点的高可用。本节中创建了两个具有负载均衡特性的集群访问节点nginx-api1、nginx-api2就是为了实现高可用。** ## 5.3 实现集群高可用 ### 5.3.1 集群高可用方案 + 集群高可用方案:本文通过keepalived技术来实现多个负载均衡访问节点之间争抢虚拟IP,争抢到虚拟IP地址的负载均衡访问节点则对外提供服务,未争抢到虚拟IP地址的负载均衡访问节点则不会对外提供服务。如果已经争抢到虚拟IP地址的负载均衡访问节点出现故障而不可用,则另外一个负载均衡访问节点就会争抢到虚拟IP,进而对外提供服务,从而达到集群高可用的目的。本文创建的两个负载均衡访问节点是主主结构,而不是主备结构,高可用方案如下图所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200331122310431.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 5.3.2 安装Keepalived软件 + 安装Keepalived软件:在API服务集群的负载均衡访问节点nginx-api1和nginx-api2中安装keepalived软件的步骤请参考3.3.2小节。 ### 5.3.3 创建Keepalived配置 + 配置文件:keepalived软件的默认配置文件为/etc/keepalived目录下的keepalived.conf文件,所以需要在nginx-api1、nginx-api2容器内部的/etc/keepalived目录下分别创建一个keepalived.conf配置文件,两个配置文件内容完全相同,文件内容如下所示: ```txt vrrp_instance nginx-api { state MASTER interface eth0 virtual_router_id 98 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 123456 } virtual_ipaddress { 172.20.2.100 } } ``` + **特别说明:keepalived.conf配置文件不能具有可执行的权限,否则keepalived会启动失败,可以将权限设置为644(rx-r- -r- -)。** ```txt sudo chmod 644 keepalived.conf ``` ### 5.3.4 验证虚拟IP抢占 + 验证虚拟IP抢占:在负载均衡访问节点nginx-api1和nginx-api2中启动keepalived以及验证虚拟IP抢占的步骤请参考3.3.4小节。 + 虚拟IP说明:在5.2.3节中的配置文件中可以指定nginx-api1和nginx-api2这两个节点抢占的虚拟IP地址,**本文设置的虚拟IP地址为 172.20.2.100,在后面会使用这个虚拟IP来作为整个API服务集群的访问地址。** ### 5.3.5 验证集群高可用 + 暴露高可用集群服务:高可用的API集群具有api-node1、api-node2、api-node3这三个API服务节点和nginx-api1、nginx-api2这两个负载均衡访问节点,对任意一个负载均衡访问节点的访问都会被负载均衡到其中一个API服务节点上,而这两个负载均衡访问节点之间通过虚拟IP抢占技术实现了高可用,只要还有一个负载均衡访问节点正常工作,整个API集群服务就可正常访问。作为高可用的集群服务,一般是对外暴露虚拟IP地址以供外部访问集群服务,而不会对外暴露任意一个API服务节点或负载均衡访问节点。 + 查看高可用API服务:**在虚拟机中**的浏览器中访问以下地址即可访问API服务集群的swagger接口页面,读者可以自行停止掉一个负载均衡访问节点,以查看该页面是否仍然还能显示出接口信息,如果仍能显示,则说明搭建的API服务集群是高可用的,否则说明搭建的API服务集群有问题。 ```txt http://172.20.2.100:8000/renren-fast/swagger/index.html ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320114821229.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 6 搭建高可用的Web服务 ## 6.1 搭建Web服务集群 ### 6.1.1 修改Web配置 ### 6.1.2 打包Web项目 + 打包Web项目:配置文件修改完成之后,即可使用npm工具打包前端项目,并使用打包生成的dist目录制作Docker镜像。本文是在IDEA开发工具中使用以下npm命令来打包前端项目,命令执行完毕并构建成功之后,会在项目路径下生成一个名称为dist的目录,该目录下的文件即为打包生成的文件,结果如下所示。 ```txt # 使用npm命令打包Web项目,并指定使用index-qa.js配置文件(即测试环境配置) npm run build --qa ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320135746340.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 6.1.3 构建Web镜像 + 上传dist目录:由于需要使用生成的dist目录下的文件来构建Web项目的Docker镜像,所以需要先把6.1.2节中生成的dist目录上传到安装了Docker环境的Linux系统中,本文把生成的dist目录放入到Linux系统的 **/usr/local/app/renren-fast/web** 目录下。 + 创建nginx配置:由于是把Web项目放入到Nginx容器中运行,所以基于Nginx镜像和生成的dist目录生成Web项目的Docker镜像时,需要在镜像中指定Nginx的配置文件。本文是把编辑好的Nginx的配置文件放入到Linux系统的 **/usr/local/app/renren-fast/web/conf** 目录下,并在Dockerfile文件中使用COPY指令把配置文件复制到镜像内部。创建的Nginx配置文件的名称为nginx.conf,内容如下所示: ```txt user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; 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 65; #gzip on; 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; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; server { listen 8080; server_name 127.0.0.1; location / { root /usr/share/nginx/html/renren-fast; index index.html; } } } ``` + 编写Dockerfile文件:本文使用Dockerfile文件构建Web项目的Docker镜像,所以需要准备一下Dockerfile文件。在Linux系统的 **/usr/local/app/renren-fast/web** 目录下创建一个Dockerfile文件,内容如下所示: ```txt FROM nginx:latest EXPOSE 8080 COPY ./conf/nginx.conf /etc/nginx/nginx.conf COPY ./dist /usr/share/nginx/html/renren-fast CMD ["nginx","-g","daemon off;"] ``` + 构建Docker镜像:使用命令行工具进入到Dockerfile文件所在目录下,并执行以下命令即可构建镜像,执行过程如下图所示。 ```txt docker build -t renren-fast-web:latest . ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320142615340.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 查看生成的镜像:使用 docker images 命令即可以查看本地已有的所有的镜像列表,本文中生成的API项目的Docker镜像的名称为 renren-fast-api,版本为 latest。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320142805693.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 6.1.4 创建Web容器 + 创建并启动Web容器:执行以下命令即可使用构建的Web镜像来创建Web容器,以下命令创建了三个Web容器,这是为了在后续章节中利用这三个Web容器实现负载均衡和高可用的特性,如果读者不想实现负载均衡以及高可用的特性,则只需要创建一个Web容器即可。 ```txt # 创建名称为web-node1的Web容器,该容器的ip地址为172.20.3.2,主机的8081端口映射到该容器的8080端口 docker run -d -p 8081:8080 \ --name=web-node1 \ --net=net-renren --ip=172.20.3.2 renren-fast-web:latest # 创建名称为web-node1的Web容器,该容器的ip地址为172.20.3.2,主机的8081端口映射到该容器的8080端口 docker run -d -p 8082:8080 \ --name=web-node2 \ --net=net-renren --ip=172.20.3.3 renren-fast-web:latest # 创建名称为web-node1的Web容器,该容器的ip地址为172.20.3.2,主机的8081端口映射到该容器的8080端口 docker run -d -p 8083:8080 \ --name=web-node3 \ --net=net-renren --ip=172.20.3.4 renren-fast-web:latest ``` + 查看Web容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320145134860.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 6.1.5 访问Web服务 + 访问Web服务:Web容器启动成功后,即可通过浏览器访问Web服务登录页面,如果访问成功,则说明Web服务启动成功。**在虚拟机中**的浏览器中访问web-node1节点的Web服务的登录页面的URL和结果如下所示: ```txt http://172.20.3.2:8080/#/login ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320150110794.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 登录使用系统:使用 **用户名 admin 和密码 admin** 登录之后,系统首页如下图所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/202003201503089.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ## 6.2 实现集群负载均衡 ### 6.2.1 集群负载均衡方案 + 集群负载均衡方案:本文通过nginx技术来实现Web集群的负载均衡访问,创建的nginx容器节点会把对Web集群的访问负载均衡到三个Web节点上,默认选用了轮询的负载远程策略。负载均衡方案如下图所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200331122601218.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 6.2.2 拉取Docker镜像 + 拉取Docker容器: ```txt docker pull nginx:latest ``` ### 6.2.3 创建Nginx配置 + 配置文件:在 /home/soft/config/web/nginx/nginx-node1 目录和 /home/soft/config/web/nginx/nginx-node2 目录下各创建一个nginx.conf配置文件,两个配置文件内容完全相同,文件内容如下所示: ```txt user nginx; worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; 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 65; #gzip on; 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; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 5s; proxy_send_timeout 5s; proxy_read_timeout 5s; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; upstream tomcat { server 172.20.3.2:8080; server 172.20.3.3:8080; server 172.20.3.4:8080; } server { listen 8080; server_name 127.0.0.1; location / { proxy_pass http://tomcat; index index.html; } } } ``` + **特别说明:如果只是想实现Web服务集群的负载均衡,则只需要创建一个nginx配置文件和一个nginx容器即可。这里创建了两个配置文件,是因为在6.2.4小节中需要创建两个nginx容器(都具有负载均衡的特性),而在6.2.5小节中会使用这两个nginx容器实现Web服务集群的高可用。** ### 6.2.4 创建Nginx容器 + 创建nginx容器:创建的nginx容器的配置文件为容器内部的/etc/nginx目录下的名为nginx.conf的文件,这里使用映射的方式将6.2.3节中在主机中创建的配置文件映射到容器内部。 ```txt # 创建名称为nginx-web1的nginx容器,该容器的ip地址为172.20.3.11,主机的8201端口映射到该容器的8080端口 docker run -it -d -p 8201:8080 \ -v /home/soft/config/web/nginx/nginx-node1:/usr/local/etc/nginx \ -v /home/soft/config/web/nginx/nginx-node1/nginx.conf:/etc/nginx/nginx.conf \ --privileged --name=nginx-web1 --net=net-renren --ip=172.20.3.11 nginx:latest # 创建名称为nginx-web2的nginx容器,该容器的ip地址为172.20.3.12,主机的8202端口映射到该容器的8080端口 docker run -it -d -p 8202:8080 \ -v /home/soft/config/web/nginx/nginx-node2:/usr/local/etc/nginx \ -v /home/soft/config/web/nginx/nginx-node2/nginx.conf:/etc/nginx/nginx.conf \ --privileged --name=nginx-web2 --net=net-renren --ip=172.20.3.12 nginx:latest ``` + 查看nginx容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320152506870.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) ### 6.2.5 验证集群负载均衡 + 访问负载均衡节点:6.2.4节中创建了两个名称分别为nginx-web1和nginx-web2的具有负载均衡特性的Web服务集群访问节点,其中主机的8201端口映射到了nginx-web1节点的8080端口,主机的8202端口映射到了nginx-web2节点的8080端口。**在虚拟机中**的浏览器中访问nginx-web1节点的Web服务的登录页面的URL和结果如下所示: ```txt http://172.20.3.11:8080/#/login ``` ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200320152835911.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDUxNjMwNQ==,size_16,color_FFFFFF,t_70) + 验证集群负载均衡:创建的负载均衡访问节点默认是使用轮询的负载均衡策略,对nginx-web1节点或nginx-web2节点的访问会被负载均衡到web-node1、web-node2、web-node3节点上。作为负载均衡访问节点,一般是对外暴露nginx-web1或nginx-web2节点的访问方式,而不会对外暴露web-node1、web-node2、web-node3节点的访问方式。读者可以自行试验当暂停掉一部分Web服务节点时,访问负载均衡节点能否访问成功,以及暂停掉所有的Web服务节点时,访问负载远程节点又能否访问成功。 + **特别说明:虽然nginx-web1节点负载均衡到了web-node1、web-node2、web-node3节点,但是nginx-web1节点仍然存在单点故障的风险,如果nginx-web1节点服务不可用,则整个集群就不可用了,所以需要实现集群访问节点的高可用。本节中创建了两个具有负载均衡特性的集群访问节点nginx-web1、nginx-web2就是为了实现高可用。** ## 6.3 实现集群高可用 ### 6.3.1 集群高可用方案 + 集群高可用方案:本文通过keepalived技术来实现多个负载均衡访问节点之间争抢虚拟IP,争抢到虚拟IP地址的负载均衡访问节点则对外提供服务,未争抢到虚拟IP地址的负载均衡访问节点则不会对外提供服务。如果已经争抢到虚拟IP地址的负载均衡访问节点出现故障而不可用,则另外一个负载均衡访问节点就会争抢到虚拟IP,进而对外提供服务,从而达到集群高可用的目的。本文创建的两个负载均衡访问节点是主主结构,而不是主备结 最后更新于 2022-04-06 09:34:49 并被添加「」标签,已有 2527 位童鞋阅读过。 本站使用「署名 4.0 国际」创作共享协议,可自由转载、引用,但需署名作者且注明文章出处
此处评论已关闭