当前位置:   article > 正文

Docker容器中部署高可用的前后端分离的Java Web项目_前后端分别部署在容器中

前后端分别部署在容器中

Docker容器中部署高可用的前后端分离的Java Web项目

1 项目说明

1.1 项目运行效果

  • 登录页面:
    在这里插入图片描述
  • 项目首页:
    在这里插入图片描述

1.2 项目运行环境

  • 运行环境版本说明:
环境名称环境版本环境说明
Ubuntuubuntu-18.04.3-desktop-amd64虚拟机操作系统
Docker19.03.5Docker容器版本
Java8后端API服务运行环境
MySQLlatest存储数据库
Redislatest缓存数据库
Nginxlatest前端Web服务运行环境
Haproxylatest集群负载均衡工具软件
Keepalived虚拟高可用工具软件

1.3 项目组成架构

  • 项目组成架构:该前端后分离的项目由一个高可用且具有负载均衡的MySQL存储服务集群,一个高可用的Redis缓存服务集群、一个高可用且具有负载均衡的API服务集群、一个高可用且具有负载均衡的Web服务集群组成。

1.4 项目部署总览

  • 项目部署总览:
    在这里插入图片描述
  • 项目部署说明:所有的容器节点都部署在一台基于虚拟机的Ubuntu操作系统的Docker环境中,且都在同一个Docker网络中,因此所有容器节点之间可以相互访问。因为没有做容器内部虚拟IP和主机IP之间的映射,所以只能在基于虚拟机的Ubuntu操作系统中才能访问虚拟IP,而在虚拟机所在的宿主机中无法访问虚拟IP。而所有的容器节点都做了端口映射,把基于虚拟机的Ubuntu操作系统的指定端点映射到了容器节点的指定端点,所以可以通过特定方式在虚拟机所在的宿主机中访问容器节点。

2 准备工作

2.1 下载项目源代码

  • 项目说明:本项目使用的是人人开源社区当中的renren-fast项目,该项目是开源的Java Web前后端分离项目,功能较为丰富,且具有较高的代码质量。后端是基于Spring Boot技术构建的Java项目,前端基于Vue.js和Element-UI组件开发。

  • 下载地址:

    https://www.renren.io/community/project
    
    • 1
  • 下载说明:访问上述地址后界面如下图所示,分别下载前端源码和后端源码。
    在这里插入图片描述

2.2 创建Docker网络

  • 项目网络说明:本次部署的高可用的前后端分离项目所涉及到的各个容器全部都在同一个Docker网络中,这样部署在该网络中的各个容器之间就可以相互访问。
  • 创建Docker网络:
    docker network create --subnet 172.20.0.0/16 net-renren
    
    • 1
  • 容器网络规划:这里列举了所有容器节点的IP,在创建容器节点时会指定IP地址。
    节点类型容器名称容器IP说明
    PXCpxc-node1172.20.0.2MySQL工作节点
    PXCpxc-node2172.20.0.3MySQL工作节点
    PXCpxc-node3172.20.0.4MySQL工作节点
    PXChaproxy-pxc1172.20.0.11MySQL集群负载均衡节点
    PXChaproxy-pxc2172.20.0.12MySQL集群负载均衡节点
    PXC172.20.0.100MySQL集群高可用的访问地址(虚拟IP地址)
    Redisredis-node1172.20.1.2Redis工作节点
    Redisredis-node2172.20.1.3Redis工作节点
    Redisredis-node3172.20.1.4Redis工作节点
    Redisredis-node4172.20.1.5Redis工作节点
    Redisredis-node5172.20.1.6Redis工作节点
    Redisredis-node6172.20.1.7Redis工作节点
    APIapi-node1172.20.2.2API工作节点
    APIapi-node2172.20.2.3API工作节点
    APIapi-node3172.20.2.4API工作节点
    APInginx-api1172.20.2.11API集群负载均衡节点
    APInginx-api2172.20.2.12API集群负载均衡节点
    API172.20.2.100API服务集群高可用的访问地址(虚拟IP地址)
    Webweb-node1172.20.3.2Web工作节点
    Webweb-node2172.20.3.3Web工作节点
    Webweb-node3172.20.3.4Web工作节点
    Webnginx-web1172.20.3.11Web集群负载均衡节点
    Webnginx-web2172.20.3.12Web集群负载均衡节点
    Web172.20.3.100Web服务集群高可用的访问地址(虚拟IP地址)

2.3 查看本机IP地址

  • 查看本机IP地址:使用 ip a 命令可以查看本机IP地址如下图所示,可知本机IP地址为192.168.0.114,后面会多次使用到这个地址。
    在这里插入图片描述

3 搭建高可用的MySQL集群

3.1 搭建PXC集群

3.1.1 集群方案选择

  • Republication方案:MySQL官方的Republication方案是单向同步、弱一致性的集群解决方案。
  • PXC方案:PXC方案是双向同步、强一致性的集群解决方案。
  • MySQL集群说明:此次使用的是PXC集群方案,搭建的PXC集群中包含三个PXC节点(一般建议集群的节点个数为大于1的奇数)。

3.1.2 拉取Docker镜像

  • 拉取镜像:由于镜像名称太长,不便于书写,所以对镜像进行重命名。
    docker pull percona/percona-xtradb-cluster:latest
    docker tag percona/percona-xtradb-cluster:latest pxc:latest
    docker rmi percona/percona-xtradb-cluster:latest
    
    • 1
    • 2
    • 3

3.1.3 创建Docker数据卷

  • 创建数据卷:
    docker volume create pxc1
    docker volume create pxc2
    docker volume create pxc3
    
    • 1
    • 2
    • 3

3.1.4 创建PXC容器

  • 创建并启动pxc容器:该PXC集群中的三个节点的名称分别为pxc-node1、pxc-node2、pxc-node3,具体的创建命令信息如下所示。
    # 创建名称为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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 查看PXC容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。
    在这里插入图片描述

3.1.5 连接PXC容器

  • 连接PXC容器:由创建pxc容器的命令可知,pxc-node1容器映射到主机的3001端口,连接用户名为 root,连接密码为 123456。在主机上使用Navicat for MySQL的客户端工具连接pxc-node1容器如下图所示,连接成功后以同样的方式分别连接pxc-node2容器和pxc-node3容器。
    在这里插入图片描述

3.1.6 验证PXC集群

  • 验证PXC集群:使用Navicat for MySQL客户端连接工具连接该PXC集群中的pxc-node1、pxc-node2、pxc-node这3三个节点,连接成功后如下图所示。如果在其中一个节点中创建一个数据库(数据库名称自定),然后刷新其它两个节点,如果在其它两个节点中也成功出现了新建的数据库,则表示集群中的各节点之间同步成功,即表示PXC集群创建成功。
    在这里插入图片描述

3.2 实现集群负载均衡

3.2.1 集群负载均衡方案

  • 集群负载均衡方案:本文通过haproxy技术来实现MySQL集群的负载均衡访问,创建的haproxy容器节点会把对MySQL集群的访问负载均衡到三个数据库节点上,默认选用了轮询的负载远程策略。负载均衡方案如下图所示:
    在这里插入图片描述

3.2.2 拉取Docker镜像

  • 拉取Haproxy镜像:
    docker pull haproxy:latest
    
    • 1

3.2.3 创建haproxy配置

  • 配置文件:在 /home/soft/config/pxc/haproxy/haproxy-node1 目录和 /home/soft/config/pxc/haproxy/haproxy-node2 目录下各创建一个haproxy.cfg配置文件,两个配置文件内容完全相同,文件内容如下所示。

    # 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
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
  • 特别说明:如果只是想实现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节中在主机中创建的配置文件映射到容器内部。

    # 创建名称为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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 查看haproxy容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。
    在这里插入图片描述

3.2.5 查看集群监控页面

  • 访问集群监控页面:3.2.3小节中创建了两个负载均衡的PXC集群访问节点,其中主机的4001端口映射到了haproxy-pxc1节点的集群监控管理页面的8888端口,主机的4002端口映射到了haproxy-pxc2节点的集群监控管理页面的8888端口,所以在浏览器中访问以下地址即可进入到haproxy的集群监控登录页面,登录后的页面如下图所示:

    # 登录名:admin   密码:123456
    192.168.0.114:4001/dbs
    
    • 1
    • 2

    在这里插入图片描述

  • 集群节点状态说明:从上图中可以看到,该集群中一共有pxc-node1、pxc-node2、pxc-node3这三个节点,但是这三个节点的Status列显示的都是DOWN,说明集群监控管理功能异常。这是因为haproxy默认需要使用一个名称为haproxy且密码为空的数据库用户来监控集群中各节点的心跳,而我们目前还没有在PXC集群中创建该心跳检测用户。

  • 创建心跳检测用户:在Navicat for MySQL客户端中的任意一个集群节点上执行以下命令,即可在PXC集群中创建心跳检测用户。

    create user 'haproxy'@'%' identified by ''; FLUSH PRIVILEGES;
    
    • 1

    在这里插入图片描述

  • 刷新集群监控页面:创建了心跳检测用户之后,再刷新集群监控后如下图所示,可见PXC集群中的三个节点的Status已经变成了UP,而且背景颜色也由红色变成了绿色,说明集群状态监控功能正常。
    在这里插入图片描述

3.2.6 验证集群负载均衡

  • 连接负载均衡节点:3.2.3小节中创建了两个负载均衡的PXC集群访问节点,其中主机的4002端口映射到了haproxy-pxc1节点的集群访问的3306端口,主机的4004端口映射到了haproxy-pxc2节点的集群访问的3306端口,而3.2.3中创建的PXC集群的三个节点的连接名都是root,密码都是123456,所以使用Navicat for MySQL客户端连接工具即可连接PXC集群的负载均衡访问节点,如下图所示:
    在这里插入图片描述
    在这里插入图片描述
  • 负载均衡访问集群:haproxy-pxc1节点是PXC集群的负载均衡访问节点,默认是使用轮询的负载均衡策略。如果在haproxy-pxc1节点中对数据库进行操作,则pxc-node1、pxc-node2、pxc-node3节点中都会进行同步。作为集群的负载均衡访问节点,一般是对外暴露haproxy-node1节点的访问方式,而不会对外暴露pxc-node1、pxc-node2、pxc-node3节点的访问方式。
  • 特别说明:虽然haproxy-pxc1节点负载均衡到了pxc-node1、pxc-node2、pxc-node3节点,但是haproxy-pxc1节点仍然存在单点故障的风险,如果haproxy-pxc1节点服务不可用,则整个集群就不可用了,所以需要实现集群访问节点的高可用。本节中创建了两个具有负载均衡特性的集群访问节点haproxy-pxc1、haproxy-pxc2就是为了实现高可用。

3.3 实现集群高可用

3.3.1 集群高可用方案

  • 集群高可用方案:本文通过keepalived技术来实现多个负载均衡访问节点之间争抢虚拟IP,争抢到虚拟IP地址的负载均衡访问节点则对外提供服务,未争抢到虚拟IP地址的负载均衡访问节点则不会对外提供服务。如果已经争抢到虚拟IP地址的负载均衡访问节点出现故障而不可用,则另外一个负载均衡访问节点就会争抢到虚拟IP,进而对外提供服务,从而达到集群高可用的目的。本文创建的两个负载均衡访问节点是主主结构,而不是主备结构,高可用方案如下图所示:
    在这里插入图片描述

3.3.2 安装Keepalived软件

  • 进入haproxy容器:执行以下Docker命令,即可以进入到haproxy-pxc1容器内部。
    docker exec -it haproxy-pxc1 bash
    
    • 1
  • 更新软件包列表:进入到haproxy-pxc1容器内部后,执行以下Linux命令先更新软件包列表。
    apt-get update
    
    • 1
  • 安装keepalived软件:软件包列表更新完毕后,执行以下Linux命令即可以安装keepalived软件。
    apt-get install keepalived
    
    • 1
  • 特别说明:在haproxy-pxc1和haproxy-pxc2这两个容器内部都需要安装keepalived软件。

3.3.3 创建Keepalived配置

  • 配置文件:keepalived软件的默认配置文件为/etc/keepalived目录下的keepalived.conf文件,所以需要在haproxy-pxc1、haproxy-pxc2容器内部的/etc/keepalived目录下分别创建一个keepalived.conf配置文件,两个配置文件内容完全相同,文件内容如下所示:

    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
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 特别说明:keepalived.conf配置文件不能具有可执行的权限,否则keepalived会启动失败,可以将权限设置为644(rx-r- -r- -)。

    sudo chmod 644 keepalived.conf
    
    • 1

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。
    在这里插入图片描述

  • 启动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节点抢占了。

    # 容器内部启动 keepalived 的命令
    service keepalived start
    
    • 1
    • 2

    在这里插入图片描述

  • 查看虚拟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。
    在这里插入图片描述

3.3.5 验证集群高可用

  • 暴露高可用集群服务:高可用的PXC数据库集群具有pxc-node1、pxc-node2、pxc-node3这三个数据库节点和haproxy-pxc1、haproxy-pxc2这两个负载均衡访问节点,对任意一个负载均衡访问节点的访问都会被负载均衡到其中一个数据库节点上,而这两个负载均衡访问节点之间通过虚拟IP抢占技术实现了高可用,只要还有一个负载均衡访问节点正常工作,整个PXC集群服务就可正常访问。作为高可用的集群服务,一般是对外暴露虚拟IP地址以供外部访问集群服务,而不会对外暴露任意一个数据库节点或负载均衡访问节点。
  • 连接高可用数据库集群服务:在虚拟机中的Navicat for MySQL客户端连接工具中或Java程序中按照以下连接信息便可以连接上高可用的数据库集群服务。
    在这里插入图片描述
  • 查看高可用数据库集群监控:在虚拟机中的浏览器中访问以下地址即可访问PXC集群的监控管理登录页面,使用 admin / 123456 登录后的界面如下图所示,读者可以自行停止掉一个负载均衡访问节点,以查看该页面是否仍然还能显示出监控内容,如果仍能显示,则说明搭建的PXC集群是高可用的,否则说明搭建的PXC集群有问题。
    # 登录名:admin   密码:123456
    172.20.0.100:8888/dbs
    
    • 1
    • 2
    在这里插入图片描述

4 搭建高可用的Redis集群

4.1 集群方案选择

  • 集群方案选择:本文使用的是Redis官方的主从模型的集群方案,搭建的Redis集群由6个Redis节点组成,其中3个主节点,3个备用节点,集群方案如下图所示:
    在这里插入图片描述

4.2 拉取Docker镜像

  • 拉取Docker镜像:
    docker pull redis:latest
    
    • 1

4.3 创建Docker数据卷

  • 创建Docker数据卷:
    docker volume create redis1
    docker volume create redis2
    docker volume create redis3
    docker volume create redis4
    docker volume create redis5
    docker volume create redis6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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个配置文件的内容全都一样,内容如下所示:
    # daemonize yes
    cluster-enabled yes
    cluster-config-file nodes.conf
    cluster-node-timeout 15000
    appendonly yes
    
    • 1
    • 2
    • 3
    • 4
    • 5

4.5 创建Redis容器

  • 创建Redis容器:创建的redis容器使用容器内部的/usr/local/etc/redis/redis.conf文件为配置文件,这里使用映射的方式将4.4节中在主机中创建的配置文件映射到容器内部。该集群中一个包含6个Redis节点,各节点创建命令如下所示。
    # 创建名称为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
    
    • 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
    • 44
    • 45
    • 46
  • 查看Redis容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。
    在这里插入图片描述

4.6 配置Redis集群

  • 配置Redis集群:在4.5小节中创建的6个redis容器节点还是独立的redis服务节点,还并没有组建成为一个集群,此时需要进入到任意一个redis容器节点中,并执行以下命令才能把这6个节点组建成为一个集群。在执行该命令的过程中,会自动提出一种主备节点的方案,并要求用户手动输入 “yes” 同意这种方案才能继续组建,组建成功之后会显示所有的节点都已加入到该集群,执行过程和结果如下图所示。
    # 进入 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    在这里插入图片描述

4.7 测试Redis集群

  • 测试Redis集群:集群组建完成之后,可以先进入到 redis-node1 容器节点并设置一个键值对,然后再进入到另外一个容器节点中查看是否存在同名的键值对,如果存在则表示集群各节点之间同步成功,否则可能是集群没有配置成功。测试执行命令和执行过程如下所示。

    # 进入到 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
    
    • 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

    在这里插入图片描述

5 搭建高可用的API服务

5.1 搭建API服务集群

5.1.1 创建API数据库

  • 导入数据库:从人人开源网站下载的后端项目源码中包含有该项目的数据库创建脚本,由于本文使用的数库是MySQL类型的数据库,所以需要使用的是mysql.sql这个数据库脚本,然后在第3.2节中创建的PXC集群的负载均衡访问节点(例如 haproxy-pxc1节点)上创建一个名称为renren_fast的数库,然后在该数库中执行该mysql.sql数据库脚本,脚本执行成功之后,数据库就创建好了,此时用户可以查看PXC集群的其它节点中是否都自动同步了新创建的renren_fast数据库,如果同步成功,则数据库创建成功。
    在这里插入图片描述
    在这里插入图片描述

5.1.2 修改API配置

  • 修改说明:从人人开源网站把后端项目源码下载下来之后,需要修改后端项目的配置文件,主要是修改端口号,Redis缓存配置和MySQL数据库配置。

  • 修改端口号和Redis配置:修改src/main/resources目录下的application.yml配置文件,修改端口号为8000,设置启用redis缓存,并指定Redis为第4节中搭建的Redis集群,如下图所示:
    在这里插入图片描述

  • 修改MySQL数据库配置:项目中有开发、测试、生产三种环境的配置文件,读者可根据自己的情况来选择发布API服务时使用哪种环境的配置文件。本文使用测试环境,所以需要修改src/main/resources目录下的application-test.yml文件,指定MySQL数据库为第3节中搭建的PXC集群,如下图所示。注意:这里需要指定MySQL数据库的IP地址为PXC集群高可用的访问地址 172.20.0.100。
    在这里插入图片描述

5.1.3 打包API项目

  • 打包API项目:配置文件修改完成之后,即可把后端项目生成 Jar 包,用于制作Docker镜像。本文是在IDEA开发工具中使用以下Maven命令来生成Jar包,命令执行完毕并构建成功之后,项目路径下的target目录下renren-fast.jar文件即为生成的Jar包。

    mvn clean package
    
    • 1

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文件,内容如下所示:

    FROM openjdk:8
    EXPOSE 8000
    COPY ./renren-fast.jar  app.jar
    ENTRYPOINT ["java","-jar","-Dspring.profiles.active=${SPRING_PROFILES_ACTIVE}","/app.jar"]
    
    • 1
    • 2
    • 3
    • 4
  • 构建Docker镜像:使用命令行工具进入到Dockerfile文件所在目录下,并执行以下命令即可构建镜像,执行过程如下图所示。

    docker build -t renren-fast-api:latest .
    
    • 1

    在这里插入图片描述

  • 查看生成的镜像:使用 docker images 命令即可以查看本地已有的所有的镜像列表,本文中生成的API项目的Docker镜像的名称为 renren-fast-api,版本为 latest。
    在这里插入图片描述

5.1.5 创建API容器

  • 创建并启动API容器:执行以下命令即可使用构建的API镜像来创建API容器,以下命令创建了三个API容器,这是为了在后续章节中利用这三个API容器实现负载均衡和高可用的特性,如果读者不想实现负载均衡以及高可用的特性,则只需要创建一个API容器即可。
    # 创建名称为api-node1的API容器,该容器的ip地址为172.20.2.2,主机的8001端口映射到该容器的8000端口,使用test环境配置文件
    docker run -d -p 8001:8000 \
    -e SPRING_PROFILES_ACTIVE=test \
    --name=api-node1 \
    --net=net-renren --ip=172.20.2.2 renren-fast-api:latest
    
    
    # 创建名称为api-node2的API容器,该容器的ip地址为172.20.2.3,主机的8002端口映射到该容器的8000端口,使用test环境配置文件
    docker run -d -p 8002:8000 \
    -e SPRING_PROFILES_ACTIVE=test \
    --name=api-node2 \
    --net=net-renren --ip=172.20.2.3 renren-fast-api:latest
    
    
    # 创建名称为api-node3的API容器,该容器的ip地址为172.20.2.4,主机的8003端口映射到该容器的8000端口,使用test环境配置文件
    docker run -d -p 8003:8000 \
    -e SPRING_PROFILES_ACTIVE=test \
    --name=api-node3 \
    --net=net-renren --ip=172.20.2.4 renren-fast-api:latest
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 查看API容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。在这里插入图片描述
  • 查看API容器启动日志:执行docker logs api-node1命令即可查看api-node1容器的启动日志,本文查看到的启动日志如下图所示,可知API服务启动时确实是使用的test环境的配置文件,使用的是8000端口,API服务启动成功无报错。
    在这里插入图片描述
    在这里插入图片描述

5.1.6 访问API服务

  • 访问API服务:API容器启动成功后,即可通过浏览器访问API服务的swagger接口页面,如果访问成功,则说明API服务启动成功。在虚拟机中的浏览器中访问api-node1节点的API服务的swagger接口页面的URL和结果如下所示:

    http://172.20.2.2:8000/renren-fast/swagger/index.html
    
    • 1

    在这里插入图片描述

5.2 实现集群负载均衡

5.2.1 集群负载均衡方案

  • 集群负载均衡方案:本文通过nginx技术来实现API集群的负载均衡访问,创建的nginx容器节点会把对API集群的访问负载均衡到三个API节点上,默认选用了轮询的负载远程策略。负载均衡方案如下图所示:
    在这里插入图片描述

5.2.2 拉取Docker镜像

  • 拉取Docker容器:
    docker pull nginx:latest
    
    • 1

5.2.3 创建Nginx配置

  • 配置文件:在 /home/soft/config/api/nginx/nginx-node1 目录和 /home/soft/config/api/nginx/nginx-node2 目录下各创建一个nginx.conf配置文件,两个配置文件内容完全相同,文件内容如下所示:
    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;  
            }  
        }
    }
    
    • 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
    • 44
    • 45
  • 特别说明:如果只是想实现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节中在主机中创建的配置文件映射到容器内部。

    # 创建名称为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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 查看nginx容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。
    在这里插入图片描述

5.2.5 验证集群负载均衡

  • 访问负载均衡节点:5.2.4节中创建了两个名称分别为nginx-api1和nginx-api2的具有负载均衡特性的API服务集群访问节点,其中主机的8101端口映射到了nginx-api1节点的8000端口,主机的8102端口映射到了nginx-api2节点的8000端口。在虚拟机中的浏览器中访问nginx-api1节点的API服务的swagger接口页面的URL和结果如下所示:

    http://172.20.2.11:8000/renren-fast/swagger/index.html
    
    • 1

    在这里插入图片描述

  • 验证集群负载均衡:创建的负载均衡访问节点默认是使用轮询的负载均衡策略,对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,进而对外提供服务,从而达到集群高可用的目的。本文创建的两个负载均衡访问节点是主主结构,而不是主备结构,高可用方案如下图所示:
    在这里插入图片描述

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配置文件,两个配置文件内容完全相同,文件内容如下所示:

    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
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 特别说明:keepalived.conf配置文件不能具有可执行的权限,否则keepalived会启动失败,可以将权限设置为644(rx-r- -r- -)。

    sudo chmod 644 keepalived.conf
    
    • 1

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服务集群有问题。

    http://172.20.2.100:8000/renren-fast/swagger/index.html
    
    • 1

    在这里插入图片描述

6 搭建高可用的Web服务

6.1 搭建Web服务集群

6.1.1 修改Web配置

  • 修改说明:从人人开源网站把前端项目源码下载下来之后,需要修改前端项目的配置文件,主要是修改端口号和API服务配置。
  • 修改端口号:修改config目录下的index.js配置文件,修改端口号为8080,如下图所示:
    在这里插入图片描述
  • 修改API服务配置:项目中有开发、测试、验收、生产四种环境的配置文件,读者可根据自己的情况来选择发布WEB服务时使用哪种环境的配置文件。本文使用测试环境,所以需要修改static/config目录下的index-qa.js文件,指定API服务地址为第5节中搭建的API集群的高可用访问地址,如下图所示。注意:这里需要指定API服务的IP地址为API服务集群高可用的访问地址 172.20.2.100。
    在这里插入图片描述

6.1.2 打包Web项目

  • 打包Web项目:配置文件修改完成之后,即可使用npm工具打包前端项目,并使用打包生成的dist目录制作Docker镜像。本文是在IDEA开发工具中使用以下npm命令来打包前端项目,命令执行完毕并构建成功之后,会在项目路径下生成一个名称为dist的目录,该目录下的文件即为打包生成的文件,结果如下所示。

    # 使用npm命令打包Web项目,并指定使用index-qa.js配置文件(即测试环境配置)
    npm run build --qa
    
    • 1
    • 2

    在这里插入图片描述

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,内容如下所示:

    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;
            }
        }
    }
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
  • 编写Dockerfile文件:本文使用Dockerfile文件构建Web项目的Docker镜像,所以需要准备一下Dockerfile文件。在Linux系统的 /usr/local/app/renren-fast/web 目录下创建一个Dockerfile文件,内容如下所示:

    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;"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 构建Docker镜像:使用命令行工具进入到Dockerfile文件所在目录下,并执行以下命令即可构建镜像,执行过程如下图所示。

    docker build -t renren-fast-web:latest .
    
    • 1

    在这里插入图片描述

  • 查看生成的镜像:使用 docker images 命令即可以查看本地已有的所有的镜像列表,本文中生成的API项目的Docker镜像的名称为 renren-fast-api,版本为 latest。
    在这里插入图片描述

6.1.4 创建Web容器

  • 创建并启动Web容器:执行以下命令即可使用构建的Web镜像来创建Web容器,以下命令创建了三个Web容器,这是为了在后续章节中利用这三个Web容器实现负载均衡和高可用的特性,如果读者不想实现负载均衡以及高可用的特性,则只需要创建一个Web容器即可。
    # 创建名称为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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 查看Web容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。
    在这里插入图片描述

6.1.5 访问Web服务

  • 访问Web服务:Web容器启动成功后,即可通过浏览器访问Web服务登录页面,如果访问成功,则说明Web服务启动成功。在虚拟机中的浏览器中访问web-node1节点的Web服务的登录页面的URL和结果如下所示:

    http://172.20.3.2:8080/#/login
    
    • 1

    在这里插入图片描述

  • 登录使用系统:使用 用户名 admin 和密码 admin 登录之后,系统首页如下图所示:
    在这里插入图片描述

6.2 实现集群负载均衡

6.2.1 集群负载均衡方案

  • 集群负载均衡方案:本文通过nginx技术来实现Web集群的负载均衡访问,创建的nginx容器节点会把对Web集群的访问负载均衡到三个Web节点上,默认选用了轮询的负载远程策略。负载均衡方案如下图所示:
    在这里插入图片描述

6.2.2 拉取Docker镜像

  • 拉取Docker容器:
    docker pull nginx:latest
    
    • 1

6.2.3 创建Nginx配置

  • 配置文件:在 /home/soft/config/web/nginx/nginx-node1 目录和 /home/soft/config/web/nginx/nginx-node2 目录下各创建一个nginx.conf配置文件,两个配置文件内容完全相同,文件内容如下所示:
    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;  
            }  
        }
    }
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
  • 特别说明:如果只是想实现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节中在主机中创建的配置文件映射到容器内部。

    # 创建名称为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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 查看nginx容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。
    在这里插入图片描述

6.2.5 验证集群负载均衡

  • 访问负载均衡节点:6.2.4节中创建了两个名称分别为nginx-web1和nginx-web2的具有负载均衡特性的Web服务集群访问节点,其中主机的8201端口映射到了nginx-web1节点的8080端口,主机的8202端口映射到了nginx-web2节点的8080端口。在虚拟机中的浏览器中访问nginx-web1节点的Web服务的登录页面的URL和结果如下所示:

    http://172.20.3.11:8080/#/login
    
    • 1

    在这里插入图片描述

  • 验证集群负载均衡:创建的负载均衡访问节点默认是使用轮询的负载均衡策略,对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,进而对外提供服务,从而达到集群高可用的目的。本文创建的两个负载均衡访问节点是主主结构,而不是主备结构,高可用方案如下图所示:
    在这里插入图片描述

6.3.2 安装Keepalived软件

  • 安装Keepalived软件:在Web服务集群的负载均衡访问节点nginx-web1和nginx-web2中安装keepalived软件的步骤请参考3.3.2小节。

6.3.3 创建Keepalived配置

  • 配置文件:keepalived软件的默认配置文件为/etc/keepalived目录下的keepalived.conf文件,所以需要在nginx-web1、nginx-web2容器内部的/etc/keepalived目录下分别创建一个keepalived.conf配置文件,两个配置文件内容完全相同,文件内容如下所示:

    vrrp_instance nginx-web {
        state MASTER
        interface eth0
        virtual_router_id 97
        priority 100
        advert_int 1
        authentication {
            auth_type PASS
            auth_pass 123456
        }
        virtual_ipaddress {
            172.20.3.100
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 特别说明:keepalived.conf配置文件不能具有可执行的权限,否则keepalived会启动失败,可以将权限设置为644(rx-r- -r- -)。

    sudo chmod 644 keepalived.conf
    
    • 1

6.3.4 验证虚拟IP抢占

  • 验证虚拟IP抢占:在负载均衡访问节点nginx-web1和nginx-web2中启动keepalived以及验证虚拟IP抢占的步骤请参考3.3.4小节。
  • 虚拟IP说明:在6.2.3节中的配置文件中可以指定nginx-web1和nginx-web2这两个节点抢占的虚拟IP地址,本文设置的虚拟IP地址为 172.20.3.100,在后面会使用这个虚拟IP来作为整个Web服务集群的访问地址。

6.3.5 验证集群高可用

  • 暴露高可用集群服务:高可用的Web集群具有web-node1、web-node2、web-node3这三个Web服务节点和nginx-web1、nginx-web2这两个负载均衡访问节点,对任意一个负载均衡访问节点的访问都会被负载均衡到其中一个Web服务节点上,而这两个负载均衡访问节点之间通过虚拟IP抢占技术实现了高可用,只要还有一个负载均衡访问节点正常工作,整个Web集群服务就可正常访问。作为高可用的集群服务,一般是对外暴露虚拟IP地址以供外部访问集群服务,而不会对外暴露任意一个Web服务节点或负载均衡访问节点。

  • 查看高可用Web服务:在虚拟机中的浏览器中访问以下地址即可访问Web服务集群的登录页面,读者可以自行停止掉一个负载均衡访问节点,以查看该页面是否仍然还能显示出来,如果仍能显示,则说明搭建的Web服务集群是高可用的,否则说明搭建的Web服务集群有问题。

    http://172.20.3.100:8080/#/login
    
    • 1

    在这里插入图片描述

7 总结

这一篇干货文章终于完成了,心里还是蛮激动的。从在网上学习如何在Docker中部署高可用的前后端分离项目开始,一直到今天写完这篇文章,前前后后花了几个月的时间,其间遇到的种种问题不计其数,但是都被自己慢慢的解决了,为了总结记录整个过程,也是为了同大家一起分享,所以精心写了这篇文章,希望这篇文章能对大家有所帮助。文中使用到的配置文件都可以在这里找到

如果觉得本文对您有帮助,请关注博主的微信公众号,会经常分享一些Java和大数据方面的技术案例!
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/232332
推荐阅读
相关标签
  

闽ICP备14008679号