【亲测】Docker容器分布式部署Java前后端,高可用教程
一、项目说明
Docker容器部署高可用的前后端分离的Java Web项目体验,由Docker容器部署Java web前后端分离,Docker容器部署Java web高可用两步构成。
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 项目部署总览
项目部署总览;
项目部署说明;所有的容器节点都部署在一台基于虚拟机的Ubuntu操作系统的Docker环境中;且都在同一个Docker网络中;因此所有容器节点之间可以相互访问。因为没有做容器内部虚拟IP和主机IP之间的映射;所以只能在基于虚拟机的Ubuntu操作系统中才能访问虚拟IP;而在虚拟机所在的宿主机中无法访问虚拟IP。而所有的容器节点都做了端口映射;把基于虚拟机的Ubuntu操作系统的指定端点映射到了容器节点的指定端点;所以可以通过特定方式在虚拟机所在的宿主机中访问容器节点。
二、准备工作
2.1 下载项目源代码
项目说明;本项目使用的是人人开源社区当中的renren-fast项目;该项目是开源的Java Web前后端分离项目;功能较为丰富;且具有较高的代码质量。后端是基于Spring Boot技术构建的Java项目;前端基于Vue.js和Element-UI组件开发。
下载地址;https://www.renren.io/community/project
下载说明;访问上述地址后界面如下图所示;分别下载前端源码和后端源码。
2.2 创建Docker网络
项目网络说明;本次部署的高可用的前后端分离项目所涉及到的各个容器全部都在同一个Docker网络中;这样部署在该网络中的各个容器之间就可以相互访问。
[root@pxc-node1 ~]# sudo yum install -y yum-utils device-mapper-persistent-data lvm2 vim wget
[root@pxc-node1 ~]# sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@pxc-node1 ~]# sudo yum install -y docker-ce-18.09.9-3.el7
创建Docker网络;
[root@pxc-node1 ~]# docker network create --subnet 172.18.0.0/16 net-renren
e019bf53ba512eb106d9a0a584e614b9c6dc46455cce997d29a945e5ced5a945
[root@pxc-node2 ~]# docker network create --subnet 172.18.0.0/16 net-renren
fb8439a960c7339befccd41f2d3a5c11f170d2aaaa7b0088a013be8fe0fa1868
[root@pxc-node3 ~]# docker network create --subnet 172.18.0.0/16 net-renren
a583a25c2ac8b10847fad35ea004c07a4daa4e4189f9a295d7217f595448590e
容器网络规划;这里列举了所有容器节点的IP;在创建容器节点时会指定IP地址。节点类型容器名称容器IP
节点类型 | 主机名 | 容器名称 | 容器IP | 说明 |
---|---|---|---|---|
PXC | pxc-node1 | pxc-node1 | 172.18.0.2 | MySQL工作节点 |
PXC | pxc-node2 | pxc-node2 | 172.18.0.3 | MySQL工作节点 |
PXC | pxc-node3 | pxc-node3 | 172.18 .0.4 | MySQL工作节点 |
PXC | ... | haproxy-pxc1 | 172.18.0.11 | MySQL集群负载均衡节点 |
PXC | haproxy-pxc2 | 172.18.0.12 | MySQL集群负载均衡节点 | |
PXC | 172.18.0.100 | MySQL集群高可用的访问地址;虚拟IP地址; | ||
Redis | redis-node1 | 172.18.1.2 | Redis工作节点 | |
Redis | redis-node2 | 172.18.1.3 | Redis工作节点 | |
Redis | redis-node3 | 172.18.1.4 | Redis工作节点 | |
Redis | redis-node4 | 172.18.1.5 | Redis工作节点 | |
Redis | redis-node5 | 172.18.1.6 | Redis工作节点 | |
Redis | redis-node6 | 172.18.1.7 | Redis工作节点 | |
API | api-node1 | 172.18.2.2 | API工作节点 | |
API | api-node2 | 172.18.2.3 | API工作节点 | |
API | api-node3 | 172.18.2.4 | API工作节点 | |
API | nginx-api1 | 172.18.2.11 | API集群负载均衡节点 | |
API | nginx-api2 | 172.18.2.12 | API集群负载均衡节点 | |
API | 172.18.2.100 | API服务集群高可用的访问地址;虚拟IP地址; | ||
Web | web-node1 | 172.18.3.2 | Web工作节点 | |
Web | web-node2 | 172.18.3.3 | Web工作节点 | |
Web | web-node3 | 172.18.3.4 | Web工作节点 | |
Web | nginx-web1 | 172.18.3.11 | Web集群负载均衡节点 | |
Web | nginx-web2 | 172.18.3.12 | Web集群负载均衡节点 | |
Web | 172.18.3.100 | Web服务集群高可用的访问地址;虚拟IP地址; |
docker容器部署java web高可用完整IP地址规划
[root@runo ~]# hostnamectl set-hostname pxc-node1
[root@runo ~]# hostnamectl set-hostname redis-node1
[root@runo ~]# hostnamectl set-hostname api-node1
...
2.3 查看本机IP地址
查看本机IP地址;使用 ip a 命令可以查看本机IP地址如下图所示;可知本机IP地址为192.168.0.114;后面会多次使用到这个地址。
三、搭建高可用的MySQL集群
3.1 搭建PXC集群
3.1.1 集群方案选择
Republication方案;MySQL官方的Republication方案是单向同步、弱一致性的集群解决方案。
PXC方案;PXC方案是双向同步、强一致性的集群解决方案。
MySQL集群说明;此次使用的是PXC集群方案;搭建的PXC集群中包含三个PXC节点;一般建议集群的节点个数为大于1的奇数;。
3.1.2 拉取Docker镜像
拉取镜像;由于镜像名称太长;不便于书写;所以对镜像进行重命名。
[root@pxc-node1 ~]# docker pull percona/percona-xtradb-cluster:5.7.20
5.7.20: Pulling from percona/percona-xtradb-cluster
10a267c67f42: Pull complete
814bc8809fc0: Pull complete
c32e31261673: Pull complete
7ef40c6d0d95: Pull complete
74a5ecb87cc4: Pull complete
c08c635cfaf1: Pull complete
67115204d437: Pull complete
845e6898cf10: Pull complete
392865b4a828: Pull complete
d1440aef4590: Pull complete
ad08fcbea5cd: Pull complete
03d173884318: Pull complete
74a8c9c96123: Pull complete
Digest: sha256:84bbe0269d3e2223556ac98e71320997bd6df09dccef5cad865b636403d36b6e
Status: Downloaded newer image for percona/percona-xtradb-cluster:5.7.20
docker.io/percona/percona-xtradb-cluster:5.7.20
[root@pxc-node1 ~]# docker tag percona/percona-xtradb-cluster:5.7.20 mysql:5.7.20
[root@pxc-node1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
percona/percona-xtradb-cluster 5.7.20 01b74a9694c0 3 years ago 413MB
mysql 5.7.20 01b74a9694c0 3 years ago 413MB
3.1.3 创建Docker数据卷
创建数据卷;
[root@pxc-node1 ~]# docker volume create --name v1
v1
[root@pxc-node1 ~]# docker volume create --name v2
v2
[root@pxc-node1 ~]# docker volume create --name v3
v3
3.1.4 创建PXC容器
创建并启动pxc容器;该PXC集群中的三个节点的名称分别为pxc-node1、pxc-node2、pxc-node3;具体的创建命令信息如下所示。
# 创建名称为pxc-node1的pxc容器;该容器的ip地址为172.20.0.2;主机的3001端口映射到该容器的3306端口;用户名为root;密码为123456
[root@pxc-node1 ~]# docker run -d -p 3001:3306 -v v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=123456 --privileged --name=node1 -e TZ=Asia/Shanghai --net=net-renren --ip 172.18.0.2 mysql:5.7.20
4da45097ad477591a79de7ca5f7e098e9fb53b9146759f5a7d94489592f36b30
# 创建用户
mysql> select * from information_schema.user_privileges;
mysql> create user 'haproxy'@'%' identified by ''; FLUSH PRIVILEGES;
----------------------------------------------------------------------------------------
| GRANTEE | TABLE_CATALOG | PRIVILEGE_TYPE | IS_GRANTABLE |
+-----------------------------+---------------+-------------------------+--------------+
| 'root'@'localhost' | def | SELECT | YES |
| 'haproxy'@'%' | def | USAGE | NO |
+-----------------------------+---------------+-------------------------+--------------+
65 rows in set (0.09 sec)
# 创建名称为pxc-node2的pxc容器;该容器的ip地址为172.20.0.3;主机的3002端口映射到该容器的3306端口;用户名为root;密码为123456
[root@pxc-node1 ~]# docker run -d -p 3002:3306 -v v2:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=node1 -e TZ=Asia/Shanghai --privileged --name=node2 --net=net-renren --ip 172.18.0.3 mysql:5.7.20
1df3ab79997415d8261d1b0fbfe1f67c4903ba740d760d94a6714f342da66542
# 创建名称为pxc-node3的pxc容器;该容器的ip地址为172.20.0.4;主机的3003端口映射到该容器的3306端口;用户名为root;密码为123456
[root@pxc-node1 ~]# docker run -d -p 3003:3306 -v v3:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=node1 -e TZ=Asia/Shanghai --privileged --name=node3 --net=net-renren --ip 172.18.0.4 mysql:5.7.20
7eee541db0fe048a4d828a82c65dc6349f40b98e4b972f5aef3c7381d8753f45
命令 | 说明 |
-d | 代表创建的容器在后台运行 |
-p | 端口映射 宿主机端口:容器端口 |
-v | 路径映射 |
-e MYSQL_ROOT_PASSWORD=123456 | 指定mysql的root账号密码为123456 |
-e CLUSTER_NAME=PXC | 执行名称为PXC |
-e XTRABACKUP_PASSWORD=123456 | 指定mysql数据同步时用的密码为123456 |
–privileged | 给最高的权限 |
–name=node1 | 节点名称node1 |
–net=net1 | 使用的内部网段 |
–ip 172.18.0.2 | 分发的ip地址 |
percona-xtradb-cluster:5.7.20 | 镜像名称 |
PXC 镜像创建出 PXC 容器参数解释
docker exec -it pxc-node1 /bin/sh
sh-4.4$ mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 8.0.23-14.1 Percona XtraDB Cluster (GPL), Release rel14, Revision d3b9a1d, WSREP version 26.4.3
Copyright (c) 2009-2021 Percona LLC and/or its affiliates
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create user 'ley'@'%' identified WITH mysql_native_password by '123456';
Query OK, 0 rows affected (0.01 sec)
mysql> GRANT REPLICATION SLAVE ON *.* to 'ley'@'%' ;
Query OK, 0 rows affected (0.01 sec)
mysql> grant all privileges on bh.* to 'ley'@'%' with grant option;
Query OK, 0 rows affected (0.01 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.01 sec)
mysql>
查看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镜像;
[root@pxc-node1 ~]# docker pull haproxy:2.3.4
latest: Pulling from library/haproxy
33847f680f63: Pull complete
f76ba8605535: Pull complete
21b84ac40dfb: Pull complete
58843844a496: Pull complete
Digest: sha256:3f0167b035e8a3c8bf6df0b48fae1846ad8a08d627d20367b7ba2c67cd8abbf7
Status: Downloaded newer image for haproxy:latest
docker.io/library/haproxy:latest
3.2.3 创建haproxy配置
配置文件;在 /home/soft/config/pxc/haproxy/haproxy-node1 目录和 /home/soft/config/pxc/haproxy/haproxy-node2 目录下各创建一个haproxy.cfg配置文件;两个配置文件内容完全相同;文件内容如下所示。
[root@pxc-node1 ~]# mkdir -p /home/soft/config/pxc/haproxy/haproxy-node1
[root@pxc-node1 ~]# mkdir -p /home/soft/config/pxc/haproxy/haproxy-node2
[root@pxc-node1 ~]# mkdir -p /usr/local/etc/haproxy
# 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.18.0.2:3306 check weight 1 maxconn 2000 # 容器的IP地址,轮询策略时,权重>没有生效
server pxc-node2 172.18.0.3:3306 check weight 1 maxconn 2000
server pxc-node3 172.18.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节中在主机中创建的配置文件映射到容器内部。
# 创建名称为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目录
[root@pxc-node1 etc]# 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.18.0.11 haproxy:2.3.4
# 创建名称为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.18.0.12 haproxy:2.3.4
查看haproxy容器是否启动成功;执行 docker ps 命令可以查看已启动的容器列表;结果如下图所示;如果STATUS列显示为UP;则表示容器启动成功。
3.2.5 查看集群监控页面
访问集群监控页面;3.2.3小节中创建了两个负载均衡的PXC集群访问节点;其中主机的4001端口映射到了haproxy-pxc1节点的集群监控管理页面的8888端口;主机的4002端口映射到了haproxy-pxc2节点的集群监控管理页面的8888端口;
所以在浏览器中访问以下地址即可进入到haproxy的集群监控登录页面;登录后的页面如下图所示;# 登录名;
10.100.21.102:4001/dbs
admin 密码;123456
集群节点状态说明;从上图中可以看到;该集群中一共有pxc-node1、pxc-node2、pxc-node3这三个节点;但是这三个节点的Status列显示的都是DOWN;说明集群监控管理功能异常。这是因为haproxy默认需要使用一个名称为haproxy且密码为空的数据库用户来监控集群中各节点的心跳;而我们目前还没有在PXC集群中创建该心跳检测用户。
创建心跳检测用户;在Navicat for MySQL客户端中的任意一个集群节点上执行以下命令;即可在PXC集群中创建心跳检测用户。
mysql> create user 'haproxy'@'%' identified by ''; FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)
Query OK, 0 rows affected (0.00 sec)
mysql>
刷新集群监控页面;创建了心跳检测用户之后;再刷新集群监控后如下图所示;可见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容器内部。
[root@pxc-node1 ~]# docker exec -it haproxy-pxc1 bash
更新软件包列表;进入到haproxy-pxc1容器内部后;执行以下Linux命令先更新软件包列表。
root@8fff60003b32:/# cp /etc/apt/sources.list /etc/apt/sources.list.bak
root@8fff60003b32:/# cat <<EOF >/etc/apt/sources.list
deb http://mirrors.ustc.edu.cn/debian stable main contrib non-free
deb http://mirrors.ustc.edu.cn/debian stable-updates main contrib non-free
EOF
root@8fff60003b32:/# apt-get update
Get:1 http://security.debian.org jessie/updates InRelease [44.9 kB
Ign http://deb.debian.org jessie InRelease
Get:2 http://security.debian.org jessie/updates/main amd64 Packages [992 kB]
Get:3 http://deb.debian.org jessie-updates InRelease [16.3 kB]
Get:4 http://deb.debian.org jessie Release.gpg [1652 B]
Get:5 http://deb.debian.org jessie Release [77.3 kB]
Get:6 http://deb.debian.org jessie-updates/main amd64 Packages [20 B]
Get:7 http://deb.debian.org jessie/main amd64 Packages [9098 kB]
16% [7 Packages 467 kB/9098 kB 5%]
......
安装keepalived软件;软件包列表更新完毕后;执行以下Linux命令即可以安装keepalived软件。
root@8fff60003b32:/# apt-get install keepalived -y
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
iproute ipvsadm libnl-3-200 libnl-genl-3-200 libpci3 libperl5.20 libpopt0 libsensors4 libsnmp-base libsnmp30 libwrap0
perl-base tcpd
Suggested packages:
heartbeat ldirectord lm-sensors snmp-mibs-downloader perl
The following NEW packages will be installed:
iproute ipvsadm keepalived libnl-3-200 libnl-genl-3-200 libpci3 libperl5.20 libpopt0 libsensors4 libsnmp-base libsnmp30
libwrap0 tcpd
The following packages will be upgraded:
perl-base
1 upgraded, 13 newly installed, 0 to remove and 55 not upgraded.
Need to get 5493 kB of archives.
After this operation, 8343 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://deb.debian.org/debian/ jessie/main libpopt0 amd64 1.16-10 [49.2 kB]
Get:2 http://deb.debian.org/debian/ jessie/main libpci3 amd64 1:3.2.1-3 [53.9 kB]
Get:3 http://deb.debian.org/debian/ jessie/main libwrap0 amd64 7.6.q-25 [58.5 kB]
Get:4 http://security.debian.org/ jessie/updates/main perl-base amd64 5.20.2-3+deb8u12 [1231 kB]
Get:5 http://deb.debian.org/debian/ jessie/main libnl-3-200 amd64 3.2.24-2 [56.0 kB]
Get:6 http://deb.debian.org/debian/ jessie/main libnl-genl-3-200 amd64 3.2.24-2 [20.1 kB]
Get:7 http://deb.debian.org/debian/ jessie/main libsensors4 amd64 1:3.3.5-2 [51.5 kB]
Get:8 http://deb.debian.org/debian/ jessie/main tcpd amd64 7.6.q-25 [22.9 kB]
Get:9 http://deb.debian.org/debian/ jessie/main iproute all 1:3.16.0-2 [15.5 kB]
Get:10 http://deb.debian.org/debian/ jessie/main ipvsadm amd64 1:1.26-4 [35.5 kB]
Get:11 http://security.debian.org/ jessie/updates/main libperl5.20 amd64 5.20.2-3+deb8u12 [1352 B]
Get:12 http://security.debian.org/ jessie/updates/main libsnmp-base all 5.7.2.1+dfsg-1+deb8u2 [1544 kB]
Get:13 http://security.debian.org/ jessie/updates/main libsnmp30 amd64 5.7.2.1+dfsg-1+deb8u2 [2155 kB]
Get:14 http://security.debian.org/ jessie/updates/main libsnmp30 amd64 5.7.2.1+dfsg-1+deb8u2 [2155 kB]
Get:15 http://security.debian.org/ jessie/updates/main libsnmp30 amd64 5.7.2.1+dfsg-1+deb8u2 [2155 kB]
Get:16 http://security.debian.org/ jessie/updates/main keepalived amd64 1:1.2.13-1+deb8u1 [198 kB]
Fetched 5070 kB in 16min 9s (5230 B/s)
debconf: delaying package configuration, since apt-utils is not installed
(Reading database ... 7678 files and directories currently installed.)
......
特别说明;在haproxy-pxc1和haproxy-pxc2这两个容器内部都需要安装keepalived软件。
3.3.3 创建Keepalived配置
配置文件;keepalived软件的默认配置文件为/etc/keepalived目录下的keepalived.conf文件;所以需要在haproxy-pxc1、haproxy-pxc2容器内部的/etc/keepalived目录下分别创建一个keepalived.conf配置文件;
两个配置文件内容完全相同;文件内容如下所示;
root@d3721892d19f:/etc/keepalived# apt-get install vim -y
root@d3721892d19f:/etc/keepalived# vim 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.18.0.100
}
}
特别说明;keepalived.conf配置文件不能具有可执行的权限;否则keepalived会启动失败;可以将权限设置为644(rx-r- -r- -)。
[root@pxc-node1 ~]# 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。
启动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 的命令
root@8fff60003b32:/# 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。
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.18.0.100:8888/dbs
四、搭建高可用的Redis集群
4.1 集群方案选择
集群方案选择;本文使用的是Redis官方的主从模型的集群方案;搭建的Redis集群由6个Redis节点组成;其中3个主节点;3个备用节点;集群方案如下图所示;
4.2 拉取Docker镜像
拉取Docker镜像;
[root@redis-node1 ~]# docker pull redis:6.0.0
6.0.0: Pulling from library/redis
54fec2fa59d0: Pull complete
9c94e11103d9: Pull complete
04ab1bfc453f: Pull complete
444196580a10: Pull complete
712be9efca72: Pull complete
4c8b54d8d272: Pull complete
Digest: sha256:9c2d321d367c582fc103ad36b7326a0edd5b558e0c987d0bea3b58bac008b20f
Status: Downloaded newer image for redis:6.0.0
docker.io/library/redis:6.0.0
4.3 创建Docker数据卷
创建Docker数据卷;
[root@redis-node1 ~]# docker volume create --name redis1
redis1
[root@redis-node1 ~]# docker volume create --name redis2
redis2
[root@redis-node1 ~]# docker volume create --name redis3
redis3
[root@redis-node1 ~]# docker volume create --name redis4
redis4
[root@redis-node1 ~]# docker volume create --name redis5
redis5
[root@redis-node1 ~]# docker volume create --name redis6
redis6
4.4 创建Redis配置
配置文件;由于需要创建六个Redis节点;为了使得每个节点都拥有独立的配置;所以每个节点都需要拥有一个独立的配置文件。在/usr/local/redis/目录下创建redis-node1、redis-node2、redis-node3、redis-node4、redis-node5、redis-node6 这6个子目录;并在每个子目录下都创建一个名称为redis.conf文件的Redis配置文件;这6个配置文件的内容全都一样;内容如下所示;
[root@redis-node1 ~]# mkdir -p /usr/local/redis/
[root@pxc-node1 ~]# mkdir -p /usr/local/redis/{redis-node1,redis-node2,redis-node3,redis-node4,redis-node5,redis-node6}
[root@redis-node1 ~]# vim /usr/local/redis/redis-node1/redis.conf
[root@redis-node1 ~]# cp /usr/local/redis/redis-node1/redis.conf /usr/local/redis/redis-node2
[root@redis-node1 ~]# cp /usr/local/redis/redis-node1/redis.conf /usr/local/redis/redis-node3
[root@redis-node1 ~]# cp /usr/local/redis/redis-node1/redis.conf /usr/local/redis/redis-node4
[root@redis-node1 ~]# cp /usr/local/redis/redis-node1/redis.conf /usr/local/redis/redis-node5
[root@redis-node1 ~]# cp /usr/local/redis/redis-node1/redis.conf /usr/local/redis/redis-node6
# 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节点;各节点创建命令如下所示。# 创建名称为redis-node1的redis容器;该容器的ip地址为172.20.1.2;主机的5001端口映射到该容器的6379端口
# 主机中的/home/soft/config/redis/redis-node1目录映射到该容器中的/usr/local/etc/redis目录
[root@redis-node1 ~]# docker run -it -d -p 5001:6379 -v redis1:/data -v /usr/local/redis/redis-node1/:/usr/local/etc/redis --privileged --name=redis-node1 --net=net-renren --ip=172.18.1.2 redis:6.0.0 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目录
[root@redis-node1 ~]# docker run -it -d -p 5002:6379 -v redis2:/data -v /usr/local/redis/redis-node2/:/usr/local/etc/redis --privileged --name=redis-node2 --net=net-renren --ip=172.18.1.3 redis:6.0.0 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目录
[root@redis-node1 ~]# docker run -it -d -p 5003:6379 -v redis3:/data -v /usr/local/redis/redis-node3/:/usr/local/etc/redis --privileged --name=redis-node3 --net=net-renren --ip=172.18.1.4 redis:6.0.0 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目录
[root@redis-node1 ~]# docker run -it -d -p 5004:6379 -v redis4:/data -v /usr/local/redis/redis-node4/:/usr/local/etc/redis --privileged --name=redis-node4 --net=net-renren --ip=172.18.1.5 redis:6.0.0 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目录
[root@redis-node1 ~]# docker run -it -d -p 5005:6379 -v redis5:/data -v /usr/local/redis/redis-node5/:/usr/local/etc/redis --privileged --name=redis-node5 --net=net-renren --ip=172.18.1.6 redis:6.0.0 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目录
[root@redis-node1 ~]# docker run -it -d -p 5006:6379 -v redis6:/data -v /usr/local/redis/redis-node6/:/usr/local/etc/redis --privileged --name=redis-node6 --net=net-renren --ip=172.18.1.7 redis:6.0.0 redis-server /usr/local/etc/redis/redis.conf
查看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.18.1.2:6379 \
172.18.1.3:6379 \
172.18.1.4:6379 \
172.18.1.5:6379 \
172.18.1.6:6379 \
172.18.1.7:6379 \
--cluster-replicas 1
4.7 测试Redis集群
测试Redis集群;集群组建完成之后;可以先进入到 redis-node1 容器节点并设置一个键值对;然后再进入到另外一个容器节点中查看是否存在同名的键值对;如果存在则表示集群各节点之间同步成功;否则可能是集群没有配置成功。测试执行命令和执行过程如下所示。
# 进入到 redis-node1 容器内部,使用 redis-cli客户端工具连接redis
[root@redis-node1 ~]# docker exec -it redis-node1 bash
root@2c95ad94830b:/data# redis-cli -c -p 6379
127.0.0.1:6379> set 10691 cn
-> Redirected to slot [9260] located at 172.18.1.3:6379
OK
172.18.1.3:6379> get 10691
"cn"
172.18.1.3:6379>
# 进入到redis-node2容器内部,使用 redis-cli客户端工具连接redis
[root@redis-node1 ~]# docker exec -it redis-node3 bash
root@ce887c078e22:/data# redis-cli -c -p 6379
127.0.0.1:6379> get 10691
-> Redirected to slot [9260] located at 172.18.1.3:6379
"cn"
172.18.1.3:6379>
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集群;如下图所示。
url: jdbc:mysql://172.18.0.100:3306/renren_fast?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false
注意;这里需要指定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
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 目录下。
[root@pxc-node1 ~]# mkdir -p /usr/local/app/renren-fast/api
[root@pxc-node1 ~]# cd /usr/local/app/renren-fast/api
[root@pxc-node1 api]# touch Dockerfile
[root@pxc-node1 api]# vim Dockerfile
编写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文件所在目录下;并执行以下命令即可构建镜像;执行过程如下图所示
[root@pxc-node1 api]# docker build -t renren-fast-api:latest .
查看生成的镜像;使用 docker images 命令即可以查看本地已有的所有的镜像列表;本文中生成的API项目的Docker镜像的名称为 renren-fast-api;版本为 latest。
5.1.5 创建API容器
创建并启动API容器;执行以下命令即可使用构建的API镜像来创建API容器;以下命令创建了三个API容器;这是为了在后续章节中利用这三个API容器实现负载均衡和高可用的特性;如果读者不想实现负载均衡以及高可用的特性;则只需要创建一个API容器即可。
# 创建名称为api-node1的API容器,该容器的ip地址为172.18.2.2,主机的8001端口映射到该容器的8000端口,使用test环境配置文件
docker run -d -p 8001:8000 \
-e SPRING_PROFILES_ACTIVE=test \
--name=api-node1 \
--net=net-renren --ip=172.18.2.2 renren-fast-api:latest
# 创建名称为api-node2的API容器,该容器的ip地址为172.18.2.3,主机的8002端口映射到该容器的8000端口,使用test环境配置文件
docker run -d -p 8002:8000 \
-e SPRING_PROFILES_ACTIVE=test \
--name=api-node2 \
--net=net-renren --ip=172.18.2.3 renren-fast-api:latest
# 创建名称为api-node3的API容器,该容器的ip地址为172.18.2.4,主机的8003端口映射到该容器的8000端口,使用test环境配置文件
docker run -d -p 8003:8000 \
-e SPRING_PROFILES_ACTIVE=test \
--name=api-node3 \
--net=net-renren --ip=172.18.2.4 renren-fast-api:latest
查看API容器是否启动成功;执行 docker ps 命令可以查看已启动的容器列表;结果如下图所示;如果STATUS列显示为UP;则表示容器启动成功。
查看API容器启动日志;执行docker logs -f api-node1命令即可查看api-node1容器的启动日志;本文查看到的启动日志如下图所示;可知API服务启动时确实是使用的test环境的配置文件;使用的是8000端口;API服务启动成功无报错。
5.1.6 访问API服务
访问API服务;API容器启动成功后;即可通过浏览器访问API服务的swagger接口页面;如果访问成功;则说明API服务启动成功。在虚拟机中的浏览器中访问api-node1节点的API服务的swagger接口页面的URL和结果如下所示;
http://172.18.2.2:8000/renren-fast/swagger/index.html
5.2 实现集群负载均衡
5.2.1 集群负载均衡方案
集群负载均衡方案;本文通过nginx技术来实现API集群的负载均衡访问;创建的nginx容器节点会把对API集群的访问负载均衡到三个API节点上;默认选用了轮询的负载远程策略。负载均衡方案如下图所示;
5.2.2 拉取Docker镜像
拉取Docker容器;
[root@pxc-node1 ~]# docker pull nginx:1.18.0
[root@pxc-node1 ~]# mkdir -p /usr/local/app/nginx/nginx-node1
[root@pxc-node1 ~]# mkdir -p /usr/local/app/nginx/nginx-node2
[root@pxc-node1 ~]# vim /usr/local/app/nginx/nginx-node1/nginx.conf
[root@pxc-node1 ~]# cp /usr/local/app/nginx/nginx-node1/nginx.conf /usr/local/app/nginx/nginx-node2/
5.2.3 创建Nginx配置
配置文件;在/home/soft/config/api/nginx/nginx-node1 目录和 /home/soft/config/api/nginx/nginx-node2 目录下各创建一个nginx.conf配置文件;两个配置文件内容完全相同;文件内容如下所示;
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/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.18.2.2:8000;
server 172.18.2.3:8000;
server 172.18.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节中在主机中创建的配置文件映射到容器内部。
# 创建名称为nginx-api1的nginx容器,该容器的ip地址为172.18.2.11,主机的8101端口映射到该容器的8000端口
docker run -it -d -p 8101:8000 \
-v /usr/local/app/nginx/nginx-node1:/usr/local/etc/nginx \
-v /usr/local/app/nginx/nginx-node1/nginx.conf:/etc/nginx/nginx.conf \
--privileged --name=nginx-api1 --net=net-renren --ip=172.18.2.11 nginx:1.18.0
# 创建名称为nginx-api2的nginx容器,该容器的ip地址为172.18.2.12,主机的8102端口映射到该容器的8000端口
docker run -it -d -p 8102:8000 \
-v /usr/local/app/nginx/nginx-node2:/usr/local/etc/nginx \
-v /usr/local/app/nginx/nginx-node2/nginx.conf:/etc/nginx/nginx.conf \
--privileged --name=nginx-api2 --net=net-renren --ip=172.18.2.12 nginx:1.18.0
查看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.18.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就是为了实现高可用。
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.18.2.100
}
}
特别说明;keepalived.conf配置文件不能具有可执行的权限;否则keepalived会启动失败;可以将权限设置为644;rx-r- -r- -;。
root@87010eb2f78b:/# chmod 644 /etc/keepalived/keepalived.conf
root@da56d2cf69b8:/# chmod 644 /etc/keepalived/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服务集群有问题。
http://172.18.2.100:8000/renren-fast/swagger/index.html
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
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;
}
}
}
编写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文件所在目录下;并执行以下命令即可构建镜像;执行过程如下图所示。
[root@pxc-node1 web]# docker build -t renren-fast-web:latest .
[root@pxc-node1 web]# docker images
查看生成的镜像;使用 docker images 命令即可以查看本地已有的所有的镜像列表;本文中生成的API项目的Docker镜像的名称为 renren-fast-api;
6.1.4 创建Web容器
创建并启动Web容器;执行以下命令即可使用构建的Web镜像来创建Web容器;以下命令创建了三个Web容器;这是为了在后续章节中利用这三个Web容器实现负载均衡和高可用的特性;如果读者不想实现负载均衡以及高可用的特性;则只需要创建一个Web容器即可。
# 创建名称为web-node1的Web容器;该容器的ip地址为172.18.3.2;主机的8081端口映射到该容器的8080端口
[root@pxc-node1 web]# docker run -d -p 8081:8080 \
> --name=web-node1 \
> --net=net-renren --ip=172.18.3.2 renren-fast-web:latest
# 创建名称为web-node1的Web容器;该容器的ip地址为172.18.3.2;主机的8081端口映射到该容器的8080端口
[root@pxc-node1 web]# docker run -d -p 8082:8080 \
> --name=web-node2 \
> --net=net-renren --ip=172.18.3.3 renren-fast-web:latest
# 创建名称为web-node1的Web容器;该容器的ip地址为172.18.3.2;主机的8081端口映射到该容器的8080端口
[root@pxc-node1 web]# docker run -d -p 8083:8080 \
> --name=web-node3 \
> --net=net-renren --ip=172.18.3.4 renren-fast-web:latest
查看Web容器是否启动成功;执行 docker ps 命令可以查看已启动的容器列表;结果如下图所示;如果STATUS列显示为UP;则表示容器启动成功。
6.1.5 访问Web服务
访问Web服务;Web容器启动成功后;即可通过浏览器访问Web服务登录页面;如果访问成功;则说明Web服务启动成功。在虚拟机中的浏览器中访问web-node1节点的Web服务的登录页面的URL和结果如下所示;
http://172.18.3.2:8080/#/login
登录使用系统;使用 用户名 admin 和密码 admin登录
6.2 实现集群负载均衡
6.2.1 集群负载均衡方案
集群负载均衡方案;本文通过nginx技术来实现Web集群的负载均衡访问;创建的nginx容器节点会把对Web集群的访问负载均衡到三个Web节点上;默认选用了轮询的负载远程策略。负载均衡方案如下图所示;
6.2.2 拉取Docker镜像
拉取Docker容器;docker pull nginx:latest
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.18.3.2:8080;
server 172.18.3.3:8080;
server 172.18.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节中在主机中创建的配置文件映射到容器内部。
# 创建名称为nginx-web1的nginx容器,该容器的ip地址为172.20.3.11,主机的8201端口映射到该容器的8080端口
docker run -it -d -p 8201:8080 \
-v /usr/local/app/renren-fast/web/nginx/nginx-node1:/usr/local/etc/nginx \
-v /usr/local/app/renren-fast/web/nginx/nginx-node1/nginx.conf:/etc/nginx/nginx.conf \
--privileged --name=nginx-web1 --net=net-renren --ip=172.18.3.11 nginx:1.18.0
# 创建名称为nginx-web2的nginx容器,该容器的ip地址为172.20.3.12,主机的8202端口映射到该容器的8080端口
docker run -it -d -p 8202:8080 \
-v /usr/local/app/renren-fast/web/nginx/nginx-node2:/usr/local/etc/nginx \
-v /usr/local/app/renren-fast/web/nginx/nginx-node2/nginx.conf:/etc/nginx/nginx.conf \
--privileged --name=nginx-web2 --net=net-renren --ip=172.18.3.12 nginx:1.18.0
查看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.18.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就是为了实现高可用。
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.18.3.100
}
}
特别说明;keepalived.conf配置文件不能具有可执行的权限;否则keepalived会启动失败;可以将权限设置为644;rx-r- -r- -;。
[root@pxc-node1 ~]# docker exec -it nginx-web1 /bin/bash
[root@pxc-node1 ~]# docker exec -it nginx-web2 /bin/bash
root@784881170d83:/# chmod 644 /etc/keepalived/keepalived.conf
root@a89fcf04d754:/# chmod 644 /etc/keepalived/keepalived.conf
root@784881170d83:/# service keepalived start
root@a89fcf04d754:/# service keepalived start
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.18.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.18.3.100:8080/#/login
7 总结,Docker容器部署Java web这一篇干货文章终于完成了,心里还是蛮激动的。从在网上学习如何在Docker中部署高可用的前后端分离项目开始,一直到今天写完这篇文章,前前后后花了几个月的时间,其间遇到的种种问题不计其数,但是都被自己慢慢的解决了,为了总结记录整个过程,也是为了同大家一起分享,所以精心写了这篇文章,希望这篇文章能对大家有所帮助。文中使用到的命令。
## docker容器部署java web前后端分离,docker容器部署java web高可用完整启动命令
docker start node1 && docker start node2 && docker start node3
docker start haproxy-pxc1 && docker start haproxy-pxc2
docker exec -it haproxy-pxc1 /bin/bash
service keepalived start
docker exec -it haproxy-pxc2 /bin/bash
service keepalived start
docker start redis-node1 && docker start redis-node2 && docker start redis-node3 && docker start redis-node4 && docker start redis-node5 && docker start redis-node6
docker start api-node1 && docker start api-node2 && docker start api-node3
docker start nginx-api1 && docker start nginx-api2
docker exec -it nginx-api1 /bin/bash
service keepalived start
docker exec -it nginx-api2 /bin/bash
service keepalived start
docker start web-node1 && docker start web-node2 && docker start web-node3
docker start nginx-web1 && docker start nginx-web2
docker exec -it nginx-web2 /bin/bash
service keepalived start
docker exec -ti haproxy-pxc1
service keepalived start
docker中 启动所有的容器命令
docker start $(docker ps -a | awk '{ print $1}' | tail -n +2)
docker中 关闭所有的容器命令
docker stop $(docker ps -a | awk '{ print $1}' | tail -n +2)
docker中 删除所有的容器命令
docker rm $(docker ps -a | awk '{ print $1}' | tail -n +2)
docker中 删除所有的镜像
docker rmi $(docker images | awk '{print $3}' |tail -n +2)
## docker容器化部署导致/dev/mapper/centos-root、/dev/mapper/centos-home目录爆满解决方案
sudo tar cvf /run/home.tar /home
sudo fuser -km /home
sudo umount /home
sudo lvremove /dev/mapper/centos-home
sudo lvextend -L +30GB /dev/mapper/centos-root
sudo xfs_growfs /dev/mapper/centos-root
sudo lvcreate -L 16GB -n/dev/mapper/centos-home
sudo mkfs.xfs /dev/mapper/centos-home
sudo mount /dev/mapper/centos-home
sudo tar xvf /run/home.tar -C /
df -h
sudo rm -rf /run/home.tar
## 部署过程中因服务器重启等原因导致MySQL无法二次启动解决办法
docker rm node1 node2 node3
rm -rf /var/lib/docker/volumes/v1/_data/grastate.dat /var/lib/docker/volumes/v2/_data/grastate.dat /var/lib/docker/volumes/v3/_data/grastate.dat
docker run -d -p 3001:3306 -v v1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=123456 --privileged --name=node1 -e TZ=Asia/Shanghai --net=net-renren --ip 172.18.0.2 mysql:5.7.20
docker run -d -p 3002:3306 -v v2:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=node1 -e TZ=Asia/Shanghai --privileged --name=node2 --net=net-renren --ip 172.18.0.3 mysql:5.7.20
docker run -d -p 3003:3306 -v v3:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=PXC -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=node1 -e TZ=Asia/Shanghai --privileged --name=node3 --net=net-renren --ip 172.18.0.4 mysql:5.7.20
## 解决容器内部apt-get 拉取缓慢卡顿报错,替换国内有源完美解决
cp /etc/apt/sources.list /etc/apt/sources.list.bak
cat <<EOF >/etc/apt/sources.list
deb http://mirrors.ustc.edu.cn/debian stable main contrib non-free
deb http://mirrors.ustc.edu.cn/debian stable-updates main contrib non-free
EOF
apt-get update
apt-get install keepalived vim -y
## MySQL容器时间时差同步问题解决
从宿主机入手,复制宿主机里的文件到容器中
docker cp /usr/share/zoneinfo/Asia/Shanghai 容器ID或容器名:/usr/share/zoneinfo/Asia
从容器内部入手
docker exec -it <容器Id或容器名> bash
执行命令
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
验证
date
从MySQL内部SQL语句入手
查看数据库当前时间:SELECT NOW()
查看数据库当前时区:SHOW VARIABLES LIKE '%time_zone%';
# 修改全局的时区配置,但是重启后会失效
SET GLOBAL time_zone = 'Asia/Shanghai'
# 或
SET GLOBAL time_zone = '+8:00'
# 强制刷新 flush privileges
Docker容器部署Java web前后端分离,高可用完整教程(附图)完结!