当前位置:   article > 正文

Docker_docker rmi

docker rmi

Docker

一、介绍

docker是一种基于GO语言实现的容器虚拟化技术,能够保证系统平滑移植,即软件带环境安装,将代码和环境打包成一个镜像文件,消除环境不一致问题

容器和虚拟机的区别:

传统虚拟机基于安装在主操作系统上的虚拟机管理系统,如VirtualBox、VMVare等,在虚拟机上安装从操作系统,然后部署各种应用软件

在这里插入图片描述

虚拟机缺点:

  • 资源占用多
  • 安装配置繁琐
  • 启动慢

容器不是模拟一个完整的操作系统,运行于主操作系统之上,容器之间隔离,只需要软件工作所需的库和设置,更加轻量高效

在这里插入图片描述

Docker容器化优点:

  • 更快速地进行应用交付和部署
  • 更便捷地进行应用升级和扩缩容
  • 更简单地进行系统维护
  • 更高效地进行资源利用

docker官网:https://www.docker.com/

docker仓库:https://hub.docker.com/

docker的基本组成:

1.image(镜像)

镜像是一个只读的模版,通过镜像可以创建容器,同一个镜像可以创建多个容器。docker镜像相当于Java类

模版,而容器相当于创建出来的对象实例

UnionFS(联合文件系统),是一种分层、轻量级、高性能的文件系统,支持对文件系统的修改作为一次提交来

一层层的叠加,同时将不同的目录挂载到同一个虚拟文件系统之下。

联合文件系统是Docker镜像的基础,使得镜像可以分层进行继承,基于基础镜像制作出各种应用镜像

在这里插入图片描述

2.container(容器)

容器是用镜像创建的实例,可以看成一个Linux环境,包括root用户权限、进程空间、用户空间、网络空间和

运行的应用程序

3.repository(仓库)

集中存放镜像的位置

在这里插入图片描述

从docker仓库拉取相应的镜像到本地,将镜像构建成容器运行

二、安装docker

docker需要安装在64位、版本大于3.8的Linux系统之上,查看Linux版本

uname -r 
  • 1

在这里插入图片描述

安装指南:https://docs.docker.com/engine/install/centos/

1.卸载旧版本docker

sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这里插入图片描述

2.安装gcc

yum -y install gcc
yum -y install gcc-c++
  • 1
  • 2

在这里插入图片描述

3.安装设置存储库

sudo yum install -y yum-utils
//添加阿里云仓库
sudo yum-config-manager \
    --add-repo \
    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

在这里插入图片描述

4.更新yum软件包索引

yum makecache fast
  • 1

在这里插入图片描述

5.安装docker引擎

sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
  • 1

在这里插入图片描述

在这里插入图片描述

6.启动docker

sudo systemctl start docker
ps -ef | grep docker
docker version
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述

7.Hello world测试

sudo docker run hello-world
  • 1

在这里插入图片描述

8.配置阿里云镜像加速器

登录阿里云,点击容器镜像服务

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三、常用命令

1.启动类命令
systemctl start docker //启动docker
systemctl stop docker //关闭docker
systemctl restart docker //重启docker
systemctl status docker //查看docker状态
systemctl enable docker //开机自动启动docker
docker info //查看docker信息
docker 具体命令 --help //查看帮助文档
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.镜像命令
docker images //列出本地镜像
docker images -a //列出本地所有镜像(含历史版本)
docker images -q //只显示镜像id
  • 1
  • 2
  • 3

在这里插入图片描述
在这里插入图片描述

repository:仓库源

tag:镜像的标签(版本)

image id:镜像id

created:镜像创建时间

size:镜像大小

注意:

同一个仓库源可以有多个tag版本,使用repository:tag来表示不同版本的镜像,如果不指定版本,默认使用最新版本latest

docker search 镜像名称 //在远程仓库中查找镜像
docker search  --limit N  镜像名称 //在远程仓库中查找指定数量的镜像(默认为25个)
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

name:镜像名称

description:镜像介绍

starts:点赞数

official:是否是官方的

automated:是否是自动构建的

docker pull 镜像名称[:版本号] //从远程仓库拉取镜像(默认最新版)
  • 1

在这里插入图片描述

docker system df //查看镜像、容器、数据卷所占空间情况
  • 1

在这里插入图片描述

docker rmi 镜像名称/id [镜像名称/id]//删除镜像(多个)
docker rmi -f 镜像名称/id //强制删除镜像
docker rmi -f ${docker images -qa} //删除所有镜像
  • 1
  • 2
  • 3

在这里插入图片描述

3.容器命令
docker run [options] image //运行镜像
options:
--name	指定容器名称
-d		后台运行容器(守护线程)
-i		以交互模式运行容器,通常与-t同时使用
-t		启动交互容器,给容器分配一个伪终端等待交互
-P		随机端口映射(大写P)
-p		指定端口映射(小写p)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

直接运行没有任何显示:

在这里插入图片描述

交互模式运行 docker run -it ubuntu /bin/bash,可以输入一些核心命令,有些命令

无法使用(容器只包括Linux核心功能),exit退出终端

在这里插入图片描述

在这里插入图片描述

docker ps [options] //列出当前正在运行的容器
options:
-a		列出所有容器
-l		最新创建的容器
-n		最近n个创建的容器
-q		静默模式,只显示容器编号
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在这里插入图片描述

在这里插入图片描述

exit		//exit退出时,容器停止
ctrl + p + q //退出,容器不停止
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

docker restart 容器名称/id //重启容器
docker stop 容器名称/id //停止运行的容器
docker start 容器名称/id //启动停止的容器
docker kill 容器名称/id //强制停止容器
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

docker rm 容器名称/id //删除容器
docker rm -f 容器名称/id //强制删除容器
docker rm -f $(docker ps -aq) //删除所有容器
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述

docker logs 容器名称/id //查看容器日志
docker top 容器名称/id //查看容器内进程
docker inspect 容器名称/id //查看容器内部信息
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

docker exec -it 容器名称/id redis-cli //以交互模式进入运行中的容器(退出终端不会导致容器停止)
docker attach 容器名称/id //以交互模式进入运行中的容器(退出终端会导致容器停止) 
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

docker cp 容器名称/id:容器内路径 目的主机路径 //将容器中的文件拷贝到主机上
docker cp 目的主机路径 容器名称/id:容器内路径 //将主机上的文件拷贝到容器中
docker export 容器名称/id > 文件名.tar //导出容器
cat 文件名.tar | docker import - 用户名/镜像名:镜像版本号 //导入镜像
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

四、制作本地镜像并发布

1.制作镜像

给Ubuntu镜像添加vim:

进入Ubuntu容器备份下载源文件:

docker exec -it ubuntu /bin/bash
cp /etc/apt/sources.list /etc/apt/sources.list.bak
  • 1
  • 2

创建sources.list文件,修改下载源

# deb cdrom:[Ubuntu 16.04 LTS _Xenial Xerus_ - Release amd64 (20160420.1)]/ xenial main restricted
deb-src http://archive.ubuntu.com/ubuntu xenial main restricted #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
deb http://mirrors.aliyun.com/ubuntu/ xenial multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-updates multiverse
deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse #Added by software-properties
deb http://archive.canonical.com/ubuntu xenial partner
deb-src http://archive.canonical.com/ubuntu xenial partner
deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted
deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted multiverse universe #Added by software-properties
deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe
deb http://mirrors.aliyun.com/ubuntu/ xenial-security multiverse
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
docker cp sources.list ubuntu:/etc/apt //覆盖下载源信息
  • 1

安装vim:

apt-get update //更新包管理工具
apt-get install libtinfo5 //vim相关依赖
apt-get install libpython3.5 //vim相关依赖
apt-get install vim //下载vim
  • 1
  • 2
  • 3
  • 4

如果在更新包管理工具时报错没有公钥无法验证签名

GPG error: http://archive.canonical.com/ubuntu xenial InRelease: The following signatures couldn’t be verified because the public key is not available: NO_PUBKEY 40976EAF437D05B5 NO_PUBKEY 3B4FE6ACC0B21F32

apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 公钥(3B4FE6ACC0B21F32)
  • 1

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

测试vim:

vim 1.txt //编写txt文件(内容任意)
  • 1

在这里插入图片描述

提交新的Ubuntu镜像:

docker commit -m="描述信息" -a="作者" 容器名称/id 镜像名称[:标签] 
  • 1

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.发布到docker hub

docker hub注册账号:https://registry.hub.docker.com/signup

docker login //登录
docker tag 镜像名称 仓库名称/镜像名称:版本号 //打标签
docker rmi -f 仓库名称/镜像名称:版本号 //删除标签
docker push 镜像名称:版本号 //推送到docker hub
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

测试:

在这里插入图片描述

在这里插入图片描述

3.发布到阿里云

由于docker hub外网访问较慢,可以将本地镜像推送到阿里云

创建命名空间、镜像仓库

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

测试:

在这里插入图片描述

在这里插入图片描述

3.发布到私有库

搭建docker私有库

docker pull registry //拉取registry镜像
docker run -d -p 5000:5000 -v /registry:/tmp/registry --privileged=true registry //运行registry镜像
//需要开启http支持
vim /etc/docker/daemon.json 添加一行 "insecure-registries":["ip:port"]
docker tag qingsongxyz/ubuntu localhost:5000/ubuntu:v1.0 //打标签
docker push localhost:5000/ubuntu:v1.0 //推送到私有库
curl -XGET http://127.0.0.1:5000/v2/_catalog //查看私有库镜像
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

测试:

在这里插入图片描述

在这里插入图片描述

五、数据卷

数据卷就是目录文件,存在于一个或多个目录中,由docker挂在到容器,用于数据持久化和共享数据,完全独立于容器之外,容器删除时不能一起删除

在centos7中挂载目录默认为不安全行为,禁止该行为,可以使用--privileged=true开启,扩大容器权限,使得容器内的root权限拥有主机的root权限

docker run -it --privileged=true -v /本机绝对路径:/容器内目录 镜像名
  • 1

在这里插入图片描述

搭载数据卷后,容器内指定目录文件和本机指定目录文件实时同步(双向)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

本机1.txt文件写入内容1.txt,容器同步更新:
在这里插入图片描述

停止容器后,主机对指定目录的更新,在容器启动后会全部同步

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

docker inspect 容器名称/id //查看容器挂载数据卷
  • 1

在这里插入图片描述

默认搭载数据卷后主机和容器支持双向读写共享

docker run -it --privileged=true -v /本机绝对路径:/容器内目录[:rw] 镜像名 
docker run -it --privileged=true -v /本机绝对路径:/容器内目录[:ro] 镜像名 //容器只能读不能写 
  • 1
  • 2

容器中指定目录不能创建文件,不能对文件进行写操作:

在这里插入图片描述

主机目录更新依然能同步,但容器内只能进行读操作:
在这里插入图片描述

在这里插入图片描述

//继承父容器 搭载数据卷相同 
docker run -it --privileged=true --volumes-from 父容器名称/id 子容器名称/id
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

任何一处修改,主机、父容器、子容器进行同步(父容器停止不会影响子容器):

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

六、安装常用软件

1.tomcat
docker search tomcat --limit 5 //搜索tomcat
docker pull tomcat //拉取tomcat
docker run -d -p 8080:8080 --name tomcat tomcat //启动tomcat
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述

浏览器访问:

在这里插入图片描述

解决方法:
在这里插入图片描述

在这里插入图片描述

2.mysql
单机版
docker search mysql //搜索mysql
docker pull mysql:8.0.23 //拉取mysql
docker run -p 3306:3306 --name mysql 
--privileged=true 
-v /docker/registry/mysql/log:/var/log/mysql \ //挂载日志目录
-v /docker/registry/mysql/data:/var/lib/mysql \ //挂载数据目录
-v /docker/registry/mysql/conf:/etc/mysql/conf.d \ //挂载配置目录
-e MYSQL_ROOT_PASSWORD=密码 -d mysql:8.0.23 //运行 

----------------------------------------------------------------
创建配置文件my.cnf,修改编码:
[client]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

docker restart mysql //重启mysql
docker exec -it mysql /bin/bash //进入mysql容器
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

MySQL8以上版本的账户加密方式是caching_sha2_password,Navicat不支持这种账户加密方式

use mysql;
select host,user,plugin from user;
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '密码'; //修改为原始加密方式
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述

没有中文乱码

在这里插入图片描述

一主一从
docker run -p 3306:3306 --name mysql-master --privileged=true \
-v /docker/registry/mysql/mysql-master/log:/var/log/mysql \
-v /docker/registry/mysql/mysql-master/data:/var/lib/mysql \
-v /docker/registry/mysql/mysql-master/conf:/etc/mysql/conf.d \ 
-e MYSQL_ROOT_PASSWORD=密码 -d mysql:8.0.23 //运行主库3306

主库 my.cnf:
[client]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

##设置server id 唯一
server_id=101
##指定不需要同步的数据库名称
binlog-ignore-db=mysql
##开启binlog, 指定名称
log-bin=mysql-master-bin
##设置binlog 使用内存大小
binlog-cache-size=1M
##binlog 过期时间
expire_logs_days=7
##忽略主从复制中的错误,避免从库复制中断 1062错误指主键重复 1032错误指主从不一致
slave_skip_errors=1062

------------------------------------------------------------------------------
docker run -p 3307:3306 --name mysql-slave --privileged=true \
-v /docker/registry/mysql/mysql-slave/log:/var/log/mysql \
-v /docker/registry/mysql/mysql-slave/data:/var/lib/mysql \
-v /docker/registry/mysql/mysql-slave/conf:/etc/mysql/conf.d \ 
-e MYSQL_ROOT_PASSWORD=密码 -d mysql:8.0.23 //运行从库3307

从库 my.cnf:
[client]
default-character-set = utf8mb4

[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

##设置server id 唯一
server_id=102
##指定不需要同步的数据库名称
binlog-ignore-db=mysql
##开启binlog, 指定名称
log-bin=mysql-slave-bin
##设置binlog 使用内存大小
binlog-cache-size=1M
##binlog 过期时间
expire_logs_days=7
##忽略主从复制中的错误,避免从库复制中断 1062错误指主键重复 1032错误指主从不一致
slave_skip_errors=1062
##relay_log中继日志
relay_log=mysql-slave-relay-bin
##slave将复制事件写入自己的binlog
log_slave_updates=1
##slave只读(具有super权限用户除外)
read_only=1
##super超级管理员只读
super_read_only=1

查看主库ip:
docker inspect --format '{{ .NetworkSettings.IPAddress }}' mysql-master
查看主库binlog信息:
show master status;

change master to master_host='172.17.0.2', master_user='root', master_password='密码', master_port=3306, master_log_file='mysql-master-bin.000001', master_log_pos=156, master_connect_retry=30; //从库配置主从复制

start slave; //开启主从复制
show slave status\G; //显示主从复制信息
  • 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
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

在这里插入图片描述

在这里插入图片描述

授予root用户权限
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

主库查看binlog:

在这里插入图片描述

在这里插入图片描述

从库配置主从复制:

在这里插入图片描述

从库开启主从复制:
在这里插入图片描述

查看主从复制信息:

在这里插入图片描述

注意:

主库和从库都需要配置账户加密方式为mysql_native_password,以便Navicat连接

测试:

在这里插入图片描述

主库建库建表,从库同步:

在这里插入图片描述

主库插入数据:

在这里插入图片描述

从库同步:

在这里插入图片描述

从库执行写操作:

在这里插入图片描述

3.redis
单机版

准备一个redis.conf配置文件,进行一下修改:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

docker run -p 6379:6379 --name redis6379 --privileged=true 
-v /docker/registry/redis/conf/redis.conf:/etc/redis/redis.conf //挂载redis配置文件 
-v /docker/registry/redis/data/:/data //挂载redis数据目录
-d redis:7.0.0 redis-server /etc/redis/redis.conf //运行redis
docker exec -it redis6379 redis-cli //进入redis容器
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

三主三从

创建redis-cluster.tmpl文件(用于创建redis.conf):

#节点端口
port ${PORT}
#开放端口访问
bind 0.0.0.0
#设置密码
requirepass 密码
masterauth 密码
#关闭保护模式
protected-mode no
#不以守护进程 后台运行
daemonize no
#开启aof持久化
appendonly yes
#启用集群
cluster-enabled yes
#集群配置文件
cluster-config-file nodes.conf
#连接超时时间
cluster-node-timeout 15000
#集群各节点IP地址
cluster-announce-ip 外网IP
#集群节点映射端口
cluster-announce-port ${PORT}
#集群通信端口 节点端口+10000
cluster-announce-bus-port 1${PORT}
  • 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
for port in `seq 7000 7005`; do \
  mkdir -p redis${port}/conf \
  && PORT=${port} envsubst < redis-cluster.tmpl > redis${port}/conf/redis.conf \
  && mkdir -p redis${port}/data;\
done
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

**注意:**云服务器需要配置安全组规则,添加所有端口 eg.(7000和17000 …)

for port in $(seq 7000 7005); do \  
	docker run -d --name redis${port} -p ${port}:${port} -p 1${port}:1${port}
	--privileged=true
    -v 				/docker/registry/redis/rediscluster/redis${port}/conf/redis.conf:/etc/redis/redis.conf
    -v /docker/registry/redis/redis-cluster/redis${port}/data:/data
    redis:7.0.0 redis-server /etc/redis/redis.conf; 
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

//主节点为7000、7001、7002 每个主节点有一个从节点 所属从节点随机分配
redis-cli -a 密码 --cluster create --cluster-replicas 1 外网IP:7000 外网IP:7001 外网IP:7002 外网IP:7003 外网IP:7004 外网IP:7005
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

redis-cli -c -a root  -p 7000
cluster info //查看集群状态
cluster nodes //查看节点信息
  • 1
  • 2
  • 3

在这里插入图片描述

当前主从信息:

节点槽位从节点
70000 - 54607004
70015461 - 109227005
700210923 - 163837003
redis-cli -a 密码 --cluster check 外网IP:7000	//查看节点存储key数量和主从配置信息
  • 1

设置key获取key时,如果该key所在的槽位不在当前节点上会重定向到对应的节点

在这里插入图片描述

在这里插入图片描述

主从切换:

当主节点宕机后,对应的从节点会变成主节点

在这里插入图片描述

停止redis7000容器让其宕机,节点7004变成主节点

在这里插入图片描述

在这里插入图片描述

启动redis7000容器使其恢复后,变为从节点

在这里插入图片描述

在这里插入图片描述

集群扩缩容:

添加redis节点:

创建配置文件:

port 7006
#开放端口访问
bind 0.0.0.0
#设置密码
requirepass 密码
masterauth 密码
protected-mode no
daemonize no
appendonly yes
#打开集群
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
cluster-announce-ip 外网IP
cluster-announce-port 7006
#集群通信端口
cluster-announce-bus-port 17006
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

运行容器redis7006:

docker run -d --name redis7006 -p 7006:7006 -p 17006:17006 --privileged=true
-v /docker/registry/redis/redis-cluster/redis7006/conf/redis.conf:/etc/redis/redis.conf
-v /docker/registry/redis/redis-cluster/redis7006/data:/data
redis:7.0.0 redis-server /etc/redis/redis.conf
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

将redis7006节点加入集群:

docker exec -it redis7006 bash //进入新创建的容器redis7006
redis-cli -a 密码 --cluster add-node 外网IP:7006(自己) 外网IP:7000(集群中的一个主节点) //将自己加入集群
redis-cli -a 密码 --cluster check 外网IP:7006 //查看集群信息
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述

重新分配槽位:

redis-cli -a 密码 --cluster reshard 外网IP:7000 //重新分配槽位
redis-cli -a 密码 --cluster check 外网IP:7006 //查看集群信息
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

重新分配成本太高,三个节点各自匀出来一部分槽位分给redis7006节点

在这里插入图片描述

给redis7006添加从节点redis7007:

docker run -d --name redis7007 -p 7007:7007 -p 17007:17007 --privileged=true
-v /docker/registry/redis/redis-cluster/redis7007/conf/redis.conf:/etc/redis/redis.conf
-v /docker/registry/redis/redis-cluster/redis7007/data:/data
redis:7.0.0 redis-server /etc/redis/redis.conf
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

添加为redis7006的从节点

redis-cli -a 密码 --cluster add-node 外网IP:7007 外网IP:7006 --cluster-slave --cluster-master-id 主节点id 

redis-cli -a 密码 -c -p 7007
cluster nodes //集群节点信息
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

在这里插入图片描述

减少redis节点:

先删除从节点redis7007:

redis-cli -a 密码 --cluster del-node 外网IP:7007 节点id
redis-cli -a 密码 --cluster check 外网:7000
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

将redis7006的槽位重新分配给redis7000

redis-cli -a 密码 --cluster reshard 外网IP:7000 //重新分配槽位
redis-cli -a 密码 --cluster check 外网IP:7006 //查看集群信息
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

删除节点redis7006:

redis-cli -a 密码 --cluster del-node 外网IP:7007 节点id
redis-cli -a 密码 --cluster check 外网:7000
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

4.elasticsearch
单机版
chmod -R 777 elasticsearch //修改文件夹授权 所有用户均可读写、执行

elasticsearch.yml:
cluster.name: "docker-cluster"
network.host: 0.0.0.0
#设置允许跨域请求访问
http.cors.enabled: true
http.cors.allow-origin: "*"
# 开启账户密码验证
http.cors.allow-headers: Authorization,X-Requested-With,Content-Length,Content-Type
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

在这里插入图片描述

docker run  --name elasticsearch --net es-net -p 9200:9200 -p 9300:9300 
-e "discovery.type=single-node" 
-e ES_JAVA_OPTS="-Xms64m -Xmx256m" //设置最大可用内存256m
--privileged=true
-v /docker/registry/elasticsearch/conf/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml 
-v /docker/registry/elasticsearch/data:/usr/share/elasticsearch/data 
-v /docker/registry/elasticsearch/logs:/usr/share/elasticsearch/logs 
-v /docker/registry/elasticsearch/plugins:/usr/share/elasticsearch/plugins 
-d elasticsearch:7.9.2 //运行elasticsearch
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

docker exec -it elasticsearch bash
bin/elasticsearch-setup-passwords interactive //设置elasticsearch密码
  • 1
  • 2

在这里插入图片描述

浏览器访问9200端口:

在这里插入图片描述

在这里插入图片描述

安装ik分词器:

官网下载对应版本ik分词器zip:https://github.com/medcl/elasticsearch-analysis-ik/releases?after=v5.6.3

unzip 解压到plugins目录下
docker restart elasticsearch //重启elasticsearch容器
docker logs elasticsearch
docker exec -it elasticsearch bash //进入容器
bin/elasticsearch-plugin list //查看加载的插件
  • 1
  • 2
  • 3
  • 4
  • 5

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

安装elasticsearch-head插件:

docker run --name elasticsearch-head -p 9100:9100 -d mobz/elasticsearch-head:5

docker cp elasticsearch-head:/usr/src/app/_site/vendor.js ./vendor.js
# 修改6886、7574行( application/x-www-form-urlencoded 改成 application/json;charset=UTF-8 )
sed -i 's#application/x-www-form-urlencoded#application/json;charset=UTF-8#g' vendor.js

docker rm -f -d elasticsearch-head

docker run --name elasticsearch-head --net es-net  -p 9100:9100 --privileged=true -v /docker/registry/elasticsearch-head/vendor.js:/usr/src/app/_site/vendor.js -d mobz/elasticsearch-head:5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

在这里插入图片描述

5.nacos
单机版

运行sql脚本:

CREATE DATABASE nacos_config;
USE nacos_config;
/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info   */
/******************************************/
CREATE TABLE `config_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) DEFAULT NULL,
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  `c_desc` varchar(256) DEFAULT NULL,
  `c_use` varchar(64) DEFAULT NULL,
  `effect` varchar(64) DEFAULT NULL,
  `type` varchar(64) DEFAULT NULL,
  `c_schema` text,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_aggr   */
/******************************************/
CREATE TABLE `config_info_aggr` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(255) NOT NULL COMMENT 'group_id',
  `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
  `content` longtext NOT NULL COMMENT '内容',
  `gmt_modified` datetime NOT NULL COMMENT '修改时间',
  `app_name` varchar(128) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_beta   */
/******************************************/
CREATE TABLE `config_info_beta` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info_tag   */
/******************************************/
CREATE TABLE `config_info_tag` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL COMMENT 'content',
  `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) DEFAULT NULL COMMENT 'source ip',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_tags_relation   */
/******************************************/
CREATE TABLE `config_tags_relation` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
  `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
  `data_id` varchar(255) NOT NULL COMMENT 'data_id',
  `group_id` varchar(128) NOT NULL COMMENT 'group_id',
  `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
  `nid` bigint(20) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`nid`),
  UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = group_capacity   */
/******************************************/
CREATE TABLE `group_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_group_id` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = his_config_info   */
/******************************************/
CREATE TABLE `his_config_info` (
  `id` bigint(64) unsigned NOT NULL,
  `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `data_id` varchar(255) NOT NULL,
  `group_id` varchar(128) NOT NULL,
  `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
  `content` longtext NOT NULL,
  `md5` varchar(32) DEFAULT NULL,
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00',
  `src_user` text,
  `src_ip` varchar(20) DEFAULT NULL,
  `op_type` char(10) DEFAULT NULL,
  `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
  PRIMARY KEY (`nid`),
  KEY `idx_gmt_create` (`gmt_create`),
  KEY `idx_gmt_modified` (`gmt_modified`),
  KEY `idx_did` (`data_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';


/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = tenant_capacity   */
/******************************************/
CREATE TABLE `tenant_capacity` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
  `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
  `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
  `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
  `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
  `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
  `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
  `gmt_create` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';


CREATE TABLE `tenant_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `kp` varchar(128) NOT NULL COMMENT 'kp',
  `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
  `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
  `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
  `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
  `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
  `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
  KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

CREATE TABLE users (
	username varchar(50) NOT NULL PRIMARY KEY,
	password varchar(500) NOT NULL,
	enabled boolean NOT NULL
);

CREATE TABLE roles (
	username varchar(50) NOT NULL,
	role varchar(50) NOT NULL
);

INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE); 

INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
  • 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
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196

编写application.properties:

# spring
server.servlet.contextPath=${SERVER_SERVLET_CONTEXTPATH:/nacos}
server.contextPath=/nacos
server.port=8848
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://IP:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=用户名
db.password=密码
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
docker  run --name nacos -p 8848:8848 \
--privileged=true \
-e JVM_XMS=64m \
-e JVM_XMX=64m \
-e MODE=standalone \
-e PREFER_HOST_MODE=外网IP \
-v /docker/registry/nacos/logs:/home/nacos/logs \
-v /docker/registry/nacos/conf/application.properties:/home/nacos/conf/application.properties \
-d nacos/nacos-server:1.1.4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述

浏览器访问8848端口,默认用户名密码均为nacos

在这里插入图片描述

修改用户名密码:

修改nacos_config数据库user表

在这里插入图片描述

默认用户名nacos,密码$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu(Bcrypt加密,明

文为nacos),直接修改即可,密码需要进行Bcrypt加密

Bcrypt加密网站:https://www.jisuan.mobi/p163u3BN66Hm6JWx.html

注意:

如果连接mysql8需要添加相应的驱动,进入容器创建/plugins/mysql目录,放在其中

下载地址:https://mvnrepository.com/artifact/mysql/mysql-connector-java

在这里插入图片描述

重启容器即可

6.seata

编写file.conf:

service {
  #transaction service group mapping
  vgroup_mapping.my_test_tx_group = "qingsongxyz" # 随便起一个名称 作为事务组名称
  #only support when registry.type=file, please don't set multiple addresses
  default.grouplist = "127.0.0.1:8091"
  #disable seata
  disableGlobalTransaction = false
}

## transaction log store, only used in seata-server
store {
  ## store mode: file、db
  mode = "file"

  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
  }

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "dbcp"
    ## mysql/oracle/h2/oceanbase etc.
    db-type = "mysql"
    driver-class-name = "com.mysql.jdbc.Driver"
    url = "jdbc:mysql://127.0.0.1:3306/seata"
    user = "mysql"
    password = "mysql"
  }
}
  • 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

编写registry.conf:

registry {
  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
  type = "nacos" # 将seata-server注册到nacos中

  nacos {
    application = "seata-server"
    serverAddr = "外网IP:8848" # nacos IP端口
    namespace = ""
    cluster = "default"
    username = "nacos" # 用户名
    password = "nacos" # 密码
  }
  eureka {
    serviceUrl = "http://localhost:8761/eureka"
    application = "default"
    weight = "1"
  }
  redis {
    serverAddr = "localhost:6379"
    db = "0"
  }
  zk {
    cluster = "default"
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }
  consul {
    cluster = "default"
    serverAddr = "127.0.0.1:8500"
  }
  etcd3 {
    cluster = "default"
    serverAddr = "http://localhost:2379"
  }
  sofa {
    serverAddr = "127.0.0.1:9603"
    application = "default"
    region = "DEFAULT_ZONE"
    datacenter = "DefaultDataCenter"
    cluster = "default"
    group = "SEATA_GROUP"
    addressWaitTime = "3000"
  }
  file {
    name = "file.conf"
  }
}

config {
  # file、nacos 、apollo、zk、consul、etcd3
  type = "file"

  nacos {
    serverAddr = "localhost"
    namespace = ""
  }
  consul {
    serverAddr = "127.0.0.1:8500"
  }
  apollo {
    app.id = "seata-server"
    apollo.meta = "http://192.168.1.204:8801"
  }
  zk {
    serverAddr = "127.0.0.1:2181"
    session.timeout = 6000
    connect.timeout = 2000
  }
  etcd3 {
    serverAddr = "http://localhost:2379"
  }
  file {
    name = "file.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
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
docker run --name seata-server \
-p 8091:8091 -p 7091:7091 \ 
-e SEATA_IP=外网IP \
-v /docker/registry/seata/file.conf:/seata-server/resources/file.conf \
-v /docker/registry/seata/registry.conf:/seata-server/resources/registry.conf \
-d seataio/seata-server:1.0.0 //运行seata-server1.0.0(选择对应的版本) 

docker exec -it seata-server sh //进入容器seata-server

docker cp mysql-connector-java-8.0.30.jar seata-server:/seata-server/libs //复制文件到容器
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

**注:**云服务器需要配置安全组规则开启8091、7091端口

在这里插入图片描述

在这里插入图片描述

默认Connector/J 5.1.30连接mysql5版本,如果连接mysql8版本需要使用Connector/J 8.0.30

下载地址:https://mvnrepository.com/artifact/mysql/mysql-connector-java

在这里插入图片描述

在此使用mysql8版本,删除Connector/J 5.1.30以免出错
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

mysql创建seata数据库和所需表

Seata1.0.0版本Sql脚本:https://github.com/seata/seata/blob/1.0.0/script/server/db/mysql.sql

-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME,
    `gmt_modified`      DATETIME,
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(96),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;
  • 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

修改file.conf:

service {
  #transaction service group mapping
  vgroup_mapping.my_test_tx_group = "qingsongxyz"
  #only support when registry.type=file, please don't set multiple addresses
  default.grouplist = "127.0.0.1:8091"
  #disable seata
  disableGlobalTransaction = false
}

## transaction log store, only used in seata-server
store {
  ## store mode: file、db
  mode = "db" # 存储到数据库

  ## file store property
  file {
    ## store location dir
    dir = "sessionStore"
  }

  ## database store property
  db {
    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
    datasource = "druid"
    ## mysql/oracle/h2/oceanbase etc.
    db-type = "mysql"
    driver-class-name = "com.mysql.cj.jdbc.Driver" # mysql8版本驱动
    url = "jdbc:mysql://外网IP:3306/seata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false"
    user = "用户名"
    password = "密码"
  }
}
  • 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
docker restart seata-server //重启容器
docker logs seata-server //查看容器日志
  • 1
  • 2

查看nacos注册seata-server成功

在这里插入图片描述

最后显示load即为成功
在这里插入图片描述

7.sentinel

docker仓库:https://registry.hub.docker.com/r/bladex/sentinel-dashboard

docker run --name sentinel  -d -p 8858:8858 -d  bladex/sentinel-dashboard:1.7.0

docker run --name sentinel -d -p 8858:8858 -d 
-v /root/docker/sentinel/log/:/Users/sczyh30/logs/csp //挂在日志目录
-e sentinel.dashboard.auth.username=用户名
-e sentinel.dashboard.auth.password=密码 
bladex/sentinel-dashboard:1.7.0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

使用原始密码(sentinel/sentinel)登录失败:

在这里插入图片描述

在这里插入图片描述

查看日志文件:

在这里插入图片描述

在这里插入图片描述

七、Dockerfile

1.介绍

Dockerfile是用来构建docker镜像的文本文件,是由一条条构建镜像所需的指令和参数组成的脚本

官网:https://docs.docker.com/engine/reference/builder/

Dockerfile是独立于docker之外的文件:

在这里插入图片描述

Dockerfile需要遵循以下规则:

  • 每个保留字指令都必须为大写字母且后面要跟随至少一个参数
  • 指令按照从上到下,顺序执行
  • 使用 # 进行注释
  • 每条指令都会创建一个新的镜像层并对镜像进行提交

Docker执行Dockerfile步骤:

1.docker基于基础镜像运行一个容器

2.执行一条指令对容器作出修改

3.执行docker commit操作提交一个镜像层

4.然后基于提交的镜像运行一个容器

5.执行dockerfile的下一条指令直到所有指令都执行完

2.保留字

FROM:

指定当前镜像基于哪一个基础镜像,Dockerfile第一条语句必须是FROM

MAINTAINER:

表示镜像维护者的姓名和邮箱地址

RUN:

容器构建时(docker build)需要运行的命令,有两种格式shell和exec

EXPOSE:

表示当前容器对外暴露的端口

WORKDIR:

指定创建容器后,终端登录后默认工作目录

USER:

指定该镜像由哪个用户执行,默认为root

ENV:

在构建镜像过程中设置环境变量

VOLUME:

指定容器数据卷,用于持久化数据

ADD:

将宿主机目录下的文件拷贝进镜像且会自动处理URL和tar压缩包

COPE:

CMD:

指定容器运行时(docker run)执行的操作,Dockerfile可以有多个CMD指令,但只有最后一个生效,CMD会被

之后的参数替换

ENTRYPOINT:

指定容器运行时执行的操作,类似CMD,但是不会被docker run后面的参数覆盖,而是将这些参数传递给

ENTRYPOINT指令指定的程序

ENTRYPOINT可以和CMD一起使用,此时CMD将给ENTRYPOINT传递参数,

3.构建centosplus镜像

Dockerfile构建镜像步骤:

1.编写Dockerfile

2.docker build命令构建镜像

3.docker run运行镜像实例

centosplus:在centos镜像的基础上下载vim编辑器、ifconfig命令、jdk1.8环境

下载jdk压缩包,编写Dockerfile:

FROM centos:7
MAINTAINER qingsongxyz<1351117125@qq.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

##安装vim
RUN yum -y install vim
##安装ifconfig
RUN yum -y install net-tools
##安装jdk8和lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
##添加jdk压缩包
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java

##配置java环境变量
ENV JAVA_HOME=/usr/local/java/jdk1.8.0_171
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH=$JAVA_HOME/bin:$PATH

EXPOSE 80

CMD echo $MYPATH
CMD echo 'success...'
CMD /bin/bash
  • 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

在这里插入图片描述

docker build -t 镜像名称[版本号] . //在含有Dockerfile的目录执行build命令
  • 1

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.虚悬镜像

仓库名、标签都是<none>的镜像,称为虚悬镜像(dangling image),这些镜像是出现错误产生的,占据宿主

机空间需要进行删除

docker image ls -f dangling=true //查看虚悬镜像
docker image prune //删除所有虚悬镜像
  • 1
  • 2

在这里插入图片描述

5.构建微服务镜像

创建Springboot项目,编写控制器:

@RestController
public class HelloController {

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/hello")
    public String helloWorld(){
        return "Hello World! serverPort=" + serverPort;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

POM.xml:

<build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>

            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <includeSystemScope>true</includeSystemScope>
                <!-- 填写启动类全限定名 -->
                <mainClass>com.qingsongxyz.HelloWorldApplication</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

打成jar包:
在这里插入图片描述

将jar包上传到服务器,编写Dockerfile:

FROM java:8

VOLUME /tmp

ADD HelloWorld.jar HelloWorld.jar

RUN bash -c 'touch HelloWorld.jar'

ENTRYPOINT ["java", "-jar", "HelloWorld.jar"]

EXPOSE 8080
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这里插入图片描述

构建镜像:

在这里插入图片描述

运行镜像:

在这里插入图片描述

访问测试:

在这里插入图片描述

八、Network

1.介绍

docker网络用于容器间的互联通信以及端口映射,在容器IP变动时可以通过服务名进行网络通信

启动docker后,会产何时能一个名为docker0的虚拟网桥

在这里插入图片描述

eth0:表示主机的以太网卡

lo:表示主机的回环地址,是本机用来测试的网络地址

2.命令
docker network creat 网络名称//创建网络
docker network inspect 网络名称//展示网络信息
docker network ls //显示所有网络
docker rm 网络名称 //删除网络
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.网络模式
网络模式说明
bridge(默认)为每一个容器分配IP,将容器连接到名为docker0的虚拟网桥
host容器不会虚拟出自己的网卡、配置IP,而是使用宿主机的IP和端口
none容器有独立的Network namespace,但没有配置任何网络设置
container和指定的容器共享IP和端口

bridge:

在这里插入图片描述

宿主机有一个网桥docker0,docker0上有一系列的虚拟接口veth,每个容器实例内部有一块网卡eth0

docker0上面的每一个veth和容器实例内部的eth0一一匹配。宿主机和容器、容器与容器之间都需要通过网桥

docker0进行通信

测试docker0中的veth和容器中eth0一一匹配:

宿主机查看网络配置:

在这里插入图片描述

容器内部查看网络配置:

在这里插入图片描述

在这里插入图片描述

host:

在这里插入图片描述

docker run -d -p 8080:8080 --network host --name tomcat tomcat //无需指定端口映射
docker run -d --network host --name tomcat tomcat //正确
  • 1
  • 2

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

主机模式容器内网络配置和宿主机一致

在这里插入图片描述

使用默认端口8080访问:

在这里插入图片描述

none:

docker run -it --name alpine --network none alpine /bin/sh //none模式运行
  • 1

只有回环地址

在这里插入图片描述

在这里插入图片描述

container:

在这里插入图片描述

docker run -it --name alpine1 alpine /bin/sh //运行容器alpine1
docker run -it --name alpine2 --network container:alpine1 alpine /bin/sh //container模式运行容器alpine2
  • 1
  • 2

alpine2和alpine1一个eth0

在这里插入图片描述

在这里插入图片描述

alpine1容器关闭,alpine2中网络配置消失:

在这里插入图片描述

4.自定义网络

**问题:**docker容器内部ip可能发生变化

// 运行两个容器
docker run -it --name alpine1 alpine /bin/sh
docker run -it --name alpine2 alpine /bin/sh

// 查看两个容器分配的ip
docker inspect alpine1 | tail -n 20
docker inspect alpine2 | tail -n 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

在这里插入图片描述

删除容器alpine2(模拟容器宕机),另外创建一个新的容器:

docker rm -f alpine2 // 删除容器alpine2
docker run -it --name alpine3 alpine /bin/sh //创建新的容器alpine3
docker inspect alpine3 | tail -n 20 //查看alpine3分配IP
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结:

容器当宕机后,后续创建的容器会继续使用其IP地址。对于固定IP地址进行通信,可能不会是同一个容器

没有使用自定义网络,无法使用容器名称进行通信:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

使用自定义网络后,可以使用容器名称进行通信:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

九、Compose

1.介绍

Docker Compose负责对Docker容器集群进行快速编排,需要定义一个docker-compose.yml,声明多个容器

之间的调用关系,一条命令运行、停止多个容器

2.修改微服务

修改微服务helloworld:

导入依赖:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.8</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3.4</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.4</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.80</version>
</dependency>
  • 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

配置文件yaml(redis、mysql使用docker 容器名称连接):

server:
  port: 8080
# 应用名称
spring:
  application:
    name: HelloWorld

# swagger和springboot整合问题
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

# 数据源
  datasource:
    username: root
    password: 密码
    url: jdbc:mysql://helloworld_mysql:3306/test
    driver-class-name: com.mysql.cj.jdbc.Driver

    druid:
      aop-patterns: com.qingsongxyz.* #  配置Spring监控
      filters: 'stat,wall'
      stat-view-servlet:
        enabled: true # 打开监控统计功能
        login-username: admin
        login-password: admin
        reset-enable: true
      web-stat-filter:
        enabled: true # Web关联监控配置
      filter:
        stat:
          enabled: true # 开启sql监控
        wall:
          enabled: true # 开启防火墙
          db-type: mysql
          config:
            delete-allow: false
            drop-table-allow: false

# 单点redis配置
  redis:
    host: helloworld_redis
    port: 6379
    password: 密码
    client-type: lettuce

# mybatis-plus
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 配置日志
  type-aliases-package: com.qingsongxyz.pojo
  mapper-locations: classpath*:mapper/**/*.xml

# redis日志
logging:
  level:
    io:
      letture:
        core: debug
  pattern:
    dateformat: MM-dd HH:mm:ss:SSS
  • 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
  • 58
  • 59
  • 60
  • 61

swagger配置文件:

@Configuration
public class SwaggerConfig {

    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.OAS_30)
                .groupName("开发1组")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.qingsongxyz.controller"))
                .build()
                .apiInfo(createApiInfo())
                .enable(true);
    }

    @Bean
    public ApiInfo createApiInfo() {
        return new ApiInfo("qingsongxyz Swagger",
                "qingsongxyz Api Documentation",
                "3.0",
                "xxx",
                new Contact("qingsongxyz", "xxx", "xxx@qq.com"),
                "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList());
    }
}
  • 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

Redis配置文件:

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        //方法已过时
        //objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);

        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);

        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);

        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        template.afterPropertiesSet();

        return template;
    }
}
  • 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

mybatis-plus配置文件:

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        //乐观锁
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

        //分表
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());

        //阻止恶意的全表更新删除
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());

        return interceptor;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
        this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
        this.setFieldValByName("deleted", 0, metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

实体类:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("`user`")
@ApiModel(description = "用户实体类")
public class User implements Serializable {

    @ApiModelProperty("用户id")
    @TableId(type = IdType.AUTO)
    private Long id;

    @ApiModelProperty("用户名")
    private String username;

    @ApiModelProperty("密码")
    private String password;

    @ApiModelProperty("性别")
    private String gender;

    @ApiModelProperty("逻辑删除字段")
    @TableLogic
    @TableField(fill = FieldFill.INSERT)
    private Integer deleted;

    @ApiModelProperty("创建时间")
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @ApiModelProperty("修改时间")
    @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @ApiModelProperty("版本号")
    @Version
    private Long version;
}
  • 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
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(description = "响应实体类")
public class CommonResult {

    private String code;

    private Object data;

    private String message;

    public static CommonResult ok(){
        return new CommonResult("200", null, null);
    }

    public static CommonResult ok(String message){
        return new CommonResult("200", null, message);
    }

    public static CommonResult ok(Object data, String message){
        return new CommonResult("200", data, message);
    }

    public static CommonResult failure(String code, String message){
        return new CommonResult(code, null, message);
    }

    public static CommonResult failure(String code, List<ObjectError> error){

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("参数校验失败");
        for (ObjectError objectError : error) {
            stringBuilder.append(",");
            stringBuilder.append(objectError.getDefaultMessage());
        }
        return new CommonResult(code, null, stringBuilder.toString());
    }
}
  • 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
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("用户实体传输类")
public class UserDTO {

    @ApiModelProperty("用户id")
    private Long id;

    @ApiModelProperty("用户名")
    private String username;

    @ApiModelProperty("性别")
    private String gender;

    @ApiModelProperty("逻辑删除字段")
    private Integer deleted;

    @ApiModelProperty("创建时间")
    private LocalDateTime createTime;

    @ApiModelProperty("修改时间")
    private LocalDateTime updateTime;

    @ApiModelProperty("版本号")
    private Long version;
}
  • 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

UserMapper:

@Mapper
public interface UserMapper extends BaseMapper<User> {

}
  • 1
  • 2
  • 3
  • 4

UserService:

public interface UserService extends IService<User> {

    int addUser(User user);

    UserDTO findUserById(long id);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

UserServiceImpl:

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final String USER_KEY = "user:";

    @Override
    public int addUser(User user) {

        log.info("user:{}", user);

        //1.插入mysql数据库
        int insert = userMapper.insert(user);

        if (insert > 0) {

            //查询出刚添加的用户信息
            User u = userMapper.selectById(user.getId());

            //转换为userDTO
            UserDTO userDTO = new UserDTO();
            BeanUtil.copyProperties(u, userDTO, false);


            Map<String, Object> map = BeanUtil.beanToMap(userDTO, new HashMap(), CopyOptions.create()
                    .ignoreNullValue()
                    .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString())
            );

            //2.如果mysql插入成功,写入redis缓存
            stringRedisTemplate.opsForHash().putAll(USER_KEY + user.getId(), map);

            //设置过期时间1分钟
            stringRedisTemplate.expire(USER_KEY + user.getId(), 1, TimeUnit.MINUTES);
        }

        return insert;
    }

    @Override
    public UserDTO findUserById(long id) {
        UserDTO result = new UserDTO();

        //1.根据id从redis中获取用户信息
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(USER_KEY + id);

        log.info("redis:entries={}", entries);

        if (ObjectUtil.isEmpty(entries)) {
            //2.如果缓存中没有,查询mysql
            User user = userMapper.selectById(id);

            log.info("mysql:user={}", user);

            //3.将mysql中查询到的用户信息进行缓存
            if (!ObjectUtil.isEmpty(user)) {
                //转换为userDTO
                BeanUtil.copyProperties(user, result, CopyOptions.create());

                Map<String, Object> map = BeanUtil.beanToMap(result, new HashMap(), CopyOptions.create()
                        .ignoreNullValue()
                        .setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString())
                );

                //4.存入redis
                stringRedisTemplate.opsForHash().putAll(USER_KEY + id, map);

                //设置过期时间1分钟
                stringRedisTemplate.expire(USER_KEY + user.getId(), 1, TimeUnit.MINUTES);
            }
        } else {
            //转换为userDTO
            result = BeanUtil.fillBeanWithMap(entries, result, true);
        }

        log.info("result:{}", result);

        return result;
    }
}
  • 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
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86

UserController:

@RestController
@Slf4j
@Api(tags = "用户类测试")
public class UserController {

    @Resource
    private UserService userService;

    @ApiOperation("测试添加用户")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "用户名", required = true, paramType = "query", dataTypeClass = String.class),
            @ApiImplicitParam(name = "password", value = "密码", required = true, paramType = "query", dataTypeClass = String.class),
            @ApiImplicitParam(name = "gender", value = "性别", required = true, paramType = "query", dataTypeClass = String.class)
    })
    @ApiResponses({
            @ApiResponse(code = 400, message = "参数有误"),
            @ApiResponse(code = 401, message = "没有认证"),
            @ApiResponse(code = 403, message = "没有权限")
    })
    @PostMapping("/user/u")
    public CommonResult addUser(User user) {
        int insert = userService.addUser(user);
        if (insert > 0) {
            return CommonResult.ok("添加用户成功!");
        } else {
            return CommonResult.failure("500", "添加用户失败!!!");
        }
    }

    @ApiOperation("测试通过id查询用户信息")
    @ApiImplicitParam(name = "id", value = "用户id", required = true, paramType = "path", dataTypeClass = Long.class)
    @ApiResponses({
            @ApiResponse(code = 400, message = "参数有误"),
            @ApiResponse(code = 401, message = "没有认证"),
            @ApiResponse(code = 403, message = "没有权限")
    })
    @GetMapping("/user/{id}")
    public CommonResult findUserById(@PathVariable("id") long id) {
        UserDTO userDTO = userService.findUserById(id);
        if(ObjectUtil.isEmpty(userDTO))
        {
            return CommonResult.failure("500","通过id获取用户信息失败!!!");
        }else {
            return CommonResult.ok(userDTO,"通过id获取用户信息成功!");
        }
    }
}
  • 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
3.打包生成镜像

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4.编写docker-compose.yaml
version: "3.9"
services:
  helloworld: # 服务名称
    image: helloworld # 镜像名称
    container_name: helloworld # 容器名称
    ports: # 端口映射
      - "8080:8080"
    volumes: # 挂载数据卷
      - /root/helloworld/app:/data
    networks: # 连接网络
      - helloworld_net
    depends_on: # 依赖于redis、mysql服务,在它们运行后才运行
      - redis
      - mysql

  redis:
    image: redis:7.0.0
    container_name: helloworld_redis
    ports:
      - "6379:6379"
    networks:
      - helloworld_net
    volumes:
      - /root/helloworld/redis/conf/redis.conf:/etc/redis/redis.conf
      - /root/helloworld/redis/data/:/data
    command: redis-server /etc/redis/redis.conf # 指定配置文件运行

  mysql:
    image: mysql:8.0.23
    container_name: helloworld_mysql
    ports:
      - "3306:3306"
    environment: # 配置root密码, 数据库
      MYSQL_ROOT_PASSWORD: '密码'
      MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
      MYSQL_DATABASE: 'test'
    volumes:
      - /root/helloworld/mysql/init:/docker-entrypoint-initdb.d
      - /root/helloworld/mysql/data:/var/lib/mysql
      - /root/helloworld/mysql/conf:/etc/my.cnf
    networks:
      - helloworld_net
    command: --default-authentication-plugin=mysql_native_password # 外部访问

networks:
  helloworld_net: # 创建网络
  • 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
docker compose config -q //检查yaml文件是否存在语法错误
docker compose up -d //后台运行
docker compose down //停止所有服务,并删除所有相关容器
  • 1
  • 2
  • 3

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

进入mysql容器内部建表:

USE test;

CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
  `password` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
  `gender` char(2) NOT NULL COMMENT '性别',
  `deleted` int unsigned NOT NULL COMMENT '逻辑删除字段',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `update_time` datetime NOT NULL COMMENT '修改时间',
  `version` bigint NOT NULL DEFAULT '1' COMMENT '版本号',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在这里插入图片描述

在这里插入图片描述

外部访问8080端口,/swagger-ui路径:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

停止所有服务:
在这里插入图片描述

十、容器监控

1.portainer

portainer是一款轻量级的应用,提供图形化界面,方便管理Docker环境

官网:https://www.portainer.io/

拉取镜像,portainer/portainer已经弃用了,推荐使用portainer/portainer-ce

官方镜像:https://registry.hub.docker.com/r/portainer/portainer-ce

汉化版镜像:https://registry.hub.docker.com/r/6053537/portainer-ce

下面使用汉化版镜像测试:

docker pull 6053537/portainer-ce //拉取镜像 
docker run -d --restart=always 
--name="portainer" -p 9000:9000 
-v /var/run/docker.sock:/var/run/docker.sock 
-v portainer_data:/data 
6053537/portainer-ce 
[--restart=always:docker重启portainer也会重启保证该容器一直运行进行监控]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

浏览器访问9000端口:

在这里插入图片描述

测试运行nginx容器:

在这里插入图片描述
编写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       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  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/share/nginx/html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
}
  • 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
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.CIG

CIG:CAdvisor(监控收集) + Influxdb(存储数据) + Granfana(图标展示)

CAdvisor是一个容器资源监控工具,包括内存、CPU、网络IO、磁盘IO,提供页面查看容器实时状态,默认

存储2分钟的数据,且只针对单机,支持Influxdb(推荐)、Redis、Kafka、ElasticSearch等软件对数据进行存

Influxdb:用Go语言编写的分布式时序、事件和指标数据库,适合存储CAdvisor中时序相关的数据

Granfana:数据监控分析可视化平台,支持多种数据源配置、丰富的插件、图标和报警

CAdvisor官网:https://github.com/google/cadvisor

Influxdb官网:https://www.influxdata.com/

Granfana官网:https://grafana.com/

docker-compose安装CIG:

version: '3.9'

volumes:
  grafana_data: {}

services:
 influxdb:
  image: tutum/influxdb
  container_name: influxdb
  restart: always
  environment:
    - PRE_CREATE_DB=cadvisor # 预先创建数据库cadvisor
  ports:
    - "8083:8083"
    - "8086:8086"
  volumes:
    - ./data/influxdb:/data

 cadvisor:
  image: google/cadvisor
  container_name: cadvisor
  links:
    - influxdb:influxsrv
  command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
  restart: always
  ports:
    - "8080:8080"
  volumes:
    - /:/rootfs:ro
    - /var/run:/var/run:rw
    - /sys:/sys:ro
    - /var/lib/docker/:/var/lib/docker:ro

 grafana:
  user: "104"
  image: grafana/grafana
  container_name: grafana
  restart: always
  links:
    - influxdb:influxsrv
  ports:
    - "3000:3000"
  volumes:
    - grafana_data:/var/lib/grafana
  environment:
    - HTTP_USER=admin #	默认登录用户名
    - HTTP_PASS=admin #	默认登录密码
    - INFLUXDB_HOST=influxsrv
    - INFLUXDB_PORT=8086
    - INFLUXDB_NAME=cadvisor # 连接influxdb数据库名称
    - INFLUXDB_USER=root # influxdb数据库用户名
    - INFLUXDB_PASS=root # influxdb数据库密码
  • 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
docker compose up -d
  • 1

在这里插入图片描述

在这里插入图片描述

浏览器访问8080端口:

在这里插入图片描述

在这里插入图片描述

浏览器访问8083端口:

在这里插入图片描述

浏览器访问3000端口:

使用admin/admin登录

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

闽ICP备14008679号