赞
踩
环境名称 | 环境版本 | 环境说明 |
---|---|---|
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 | 虚拟高可用工具软件 |
项目说明:本项目使用的是人人开源社区当中的renren-fast项目,该项目是开源的Java Web前后端分离项目,功能较为丰富,且具有较高的代码质量。后端是基于Spring Boot技术构建的Java项目,前端基于Vue.js和Element-UI组件开发。
下载地址:
https://www.renren.io/community/project
下载说明:访问上述地址后界面如下图所示,分别下载前端源码和后端源码。
docker network create --subnet 172.20.0.0/16 net-renren
节点类型 | 容器名称 | 容器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地址) |
docker pull percona/percona-xtradb-cluster:latest
docker tag percona/percona-xtradb-cluster:latest pxc:latest
docker rmi percona/percona-xtradb-cluster:latest
docker volume create pxc1
docker volume create pxc2
docker volume create pxc3
# 创建名称为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
docker pull haproxy:latest
配置文件:在 /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
特别说明:如果只是想实现PXC集群的负载均衡,则只需要创建一个haproxy配置文件和一个haproxy容器即可。这里创建了两个配置文件,是因为在3.3.3小节中需要创建两个haproxy容器(都具有负载均衡的特性),而在3.3.4小节中会使用这两个haproxy容器实现PXC集群的高可用。
创建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
查看haproxy容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。
访问集群监控页面:3.2.3小节中创建了两个负载均衡的PXC集群访问节点,其中主机的4001端口映射到了haproxy-pxc1节点的集群监控管理页面的8888端口,主机的4002端口映射到了haproxy-pxc2节点的集群监控管理页面的8888端口,所以在浏览器中访问以下地址即可进入到haproxy的集群监控登录页面,登录后的页面如下图所示:
# 登录名:admin 密码:123456
192.168.0.114:4001/dbs
集群节点状态说明:从上图中可以看到,该集群中一共有pxc-node1、pxc-node2、pxc-node3这三个节点,但是这三个节点的Status列显示的都是DOWN,说明集群监控管理功能异常。这是因为haproxy默认需要使用一个名称为haproxy且密码为空的数据库用户来监控集群中各节点的心跳,而我们目前还没有在PXC集群中创建该心跳检测用户。
创建心跳检测用户:在Navicat for MySQL客户端中的任意一个集群节点上执行以下命令,即可在PXC集群中创建心跳检测用户。
create user 'haproxy'@'%' identified by ''; FLUSH PRIVILEGES;
刷新集群监控页面:创建了心跳检测用户之后,再刷新集群监控后如下图所示,可见PXC集群中的三个节点的Status已经变成了UP,而且背景颜色也由红色变成了绿色,说明集群状态监控功能正常。
docker exec -it haproxy-pxc1 bash
apt-get update
apt-get install 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
}
}
特别说明:keepalived.conf配置文件不能具有可执行的权限,否则keepalived会启动失败,可以将权限设置为644(rx-r- -r- -)。
sudo chmod 644 keepalived.conf
查看容器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
查看虚拟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。
# 登录名:admin 密码:123456
172.20.0.100:8888/dbs
docker pull redis:latest
docker volume create redis1
docker volume create redis2
docker volume create redis3
docker volume create redis4
docker volume create redis5
docker volume create redis6
# daemonize yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
appendonly yes
# 创建名称为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-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
测试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
修改说明:从人人开源网站把后端项目源码下载下来之后,需要修改后端项目的配置文件,主要是修改端口号,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。
打包API项目:配置文件修改完成之后,即可把后端项目生成 Jar 包,用于制作Docker镜像。本文是在IDEA开发工具中使用以下Maven命令来生成Jar包,命令执行完毕并构建成功之后,项目路径下的target目录下renren-fast.jar文件即为生成的Jar包。
mvn clean package
上传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"]
构建Docker镜像:使用命令行工具进入到Dockerfile文件所在目录下,并执行以下命令即可构建镜像,执行过程如下图所示。
docker build -t renren-fast-api:latest .
查看生成的镜像:使用 docker images 命令即可以查看本地已有的所有的镜像列表,本文中生成的API项目的Docker镜像的名称为 renren-fast-api,版本为 latest。
# 创建名称为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
访问API服务:API容器启动成功后,即可通过浏览器访问API服务的swagger接口页面,如果访问成功,则说明API服务启动成功。在虚拟机中的浏览器中访问api-node1节点的API服务的swagger接口页面的URL和结果如下所示:
http://172.20.2.2:8000/renren-fast/swagger/index.html
docker pull nginx:latest
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; } } }
创建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
查看nginx容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。
访问负载均衡节点: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
验证集群负载均衡:创建的负载均衡访问节点默认是使用轮询的负载均衡策略,对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就是为了实现高可用。
配置文件: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
}
}
特别说明:keepalived.conf配置文件不能具有可执行的权限,否则keepalived会启动失败,可以将权限设置为644(rx-r- -r- -)。
sudo chmod 644 keepalived.conf
暴露高可用集群服务:高可用的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
打包Web项目:配置文件修改完成之后,即可使用npm工具打包前端项目,并使用打包生成的dist目录制作Docker镜像。本文是在IDEA开发工具中使用以下npm命令来打包前端项目,命令执行完毕并构建成功之后,会在项目路径下生成一个名称为dist的目录,该目录下的文件即为打包生成的文件,结果如下所示。
# 使用npm命令打包Web项目,并指定使用index-qa.js配置文件(即测试环境配置)
npm run build --qa
上传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; } } }
编写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;"]
构建Docker镜像:使用命令行工具进入到Dockerfile文件所在目录下,并执行以下命令即可构建镜像,执行过程如下图所示。
docker build -t renren-fast-web:latest .
查看生成的镜像:使用 docker images 命令即可以查看本地已有的所有的镜像列表,本文中生成的API项目的Docker镜像的名称为 renren-fast-api,版本为 latest。
# 创建名称为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服务:Web容器启动成功后,即可通过浏览器访问Web服务登录页面,如果访问成功,则说明Web服务启动成功。在虚拟机中的浏览器中访问web-node1节点的Web服务的登录页面的URL和结果如下所示:
http://172.20.3.2:8080/#/login
登录使用系统:使用 用户名 admin 和密码 admin 登录之后,系统首页如下图所示:
docker pull nginx:latest
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; } } }
创建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
查看nginx容器是否启动成功:执行 docker ps 命令可以查看已启动的容器列表,结果如下图所示,如果STATUS列显示为UP,则表示容器启动成功。
访问负载均衡节点: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
验证集群负载均衡:创建的负载均衡访问节点默认是使用轮询的负载均衡策略,对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就是为了实现高可用。
配置文件: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
}
}
特别说明:keepalived.conf配置文件不能具有可执行的权限,否则keepalived会启动失败,可以将权限设置为644(rx-r- -r- -)。
sudo chmod 644 keepalived.conf
暴露高可用集群服务:高可用的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
这一篇干货文章终于完成了,心里还是蛮激动的。从在网上学习如何在Docker中部署高可用的前后端分离项目开始,一直到今天写完这篇文章,前前后后花了几个月的时间,其间遇到的种种问题不计其数,但是都被自己慢慢的解决了,为了总结记录整个过程,也是为了同大家一起分享,所以精心写了这篇文章,希望这篇文章能对大家有所帮助。文中使用到的配置文件都可以在这里找到。
如果觉得本文对您有帮助,请关注博主的微信公众号,会经常分享一些Java和大数据方面的技术案例!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。