赞
踩
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需要安装在64位、版本大于3.8的Linux系统之上,查看Linux版本
uname -r
安装指南: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
2.安装gcc
yum -y install gcc
yum -y install gcc-c++
3.安装设置存储库
sudo yum install -y yum-utils
//添加阿里云仓库
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
4.更新yum软件包索引
yum makecache fast
5.安装docker引擎
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
6.启动docker
sudo systemctl start docker
ps -ef | grep docker
docker version
7.Hello world测试
sudo docker run hello-world
8.配置阿里云镜像加速器
登录阿里云,点击容器镜像服务
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 //查看帮助文档
docker images //列出本地镜像
docker images -a //列出本地所有镜像(含历史版本)
docker images -q //只显示镜像id
repository:仓库源
tag:镜像的标签(版本)
image id:镜像id
created:镜像创建时间
size:镜像大小
注意:
同一个仓库源可以有多个tag版本,使用repository:tag
来表示不同版本的镜像,如果不指定版本,默认使用最新版本latest
docker search 镜像名称 //在远程仓库中查找镜像
docker search --limit N 镜像名称 //在远程仓库中查找指定数量的镜像(默认为25个)
name:镜像名称
description:镜像介绍
starts:点赞数
official:是否是官方的
automated:是否是自动构建的
docker pull 镜像名称[:版本号] //从远程仓库拉取镜像(默认最新版)
docker system df //查看镜像、容器、数据卷所占空间情况
docker rmi 镜像名称/id [镜像名称/id]//删除镜像(多个)
docker rmi -f 镜像名称/id //强制删除镜像
docker rmi -f ${docker images -qa} //删除所有镜像
docker run [options] image //运行镜像
options:
--name 指定容器名称
-d 后台运行容器(守护线程)
-i 以交互模式运行容器,通常与-t同时使用
-t 启动交互容器,给容器分配一个伪终端等待交互
-P 随机端口映射(大写P)
-p 指定端口映射(小写p)
直接运行没有任何显示:
交互模式运行 docker run -it ubuntu /bin/bash,可以输入一些核心命令,有些命令
无法使用(容器只包括Linux核心功能),exit退出终端
docker ps [options] //列出当前正在运行的容器
options:
-a 列出所有容器
-l 最新创建的容器
-n 最近n个创建的容器
-q 静默模式,只显示容器编号
exit //exit退出时,容器停止
ctrl + p + q //退出,容器不停止
docker restart 容器名称/id //重启容器
docker stop 容器名称/id //停止运行的容器
docker start 容器名称/id //启动停止的容器
docker kill 容器名称/id //强制停止容器
docker rm 容器名称/id //删除容器
docker rm -f 容器名称/id //强制删除容器
docker rm -f $(docker ps -aq) //删除所有容器
docker logs 容器名称/id //查看容器日志
docker top 容器名称/id //查看容器内进程
docker inspect 容器名称/id //查看容器内部信息
docker exec -it 容器名称/id redis-cli //以交互模式进入运行中的容器(退出终端不会导致容器停止)
docker attach 容器名称/id //以交互模式进入运行中的容器(退出终端会导致容器停止)
docker cp 容器名称/id:容器内路径 目的主机路径 //将容器中的文件拷贝到主机上
docker cp 目的主机路径 容器名称/id:容器内路径 //将主机上的文件拷贝到容器中
docker export 容器名称/id > 文件名.tar //导出容器
cat 文件名.tar | docker import - 用户名/镜像名:镜像版本号 //导入镜像
给Ubuntu镜像添加vim:
进入Ubuntu容器备份下载源文件:
docker exec -it ubuntu /bin/bash
cp /etc/apt/sources.list /etc/apt/sources.list.bak
创建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
docker cp sources.list ubuntu:/etc/apt //覆盖下载源信息
安装vim:
apt-get update //更新包管理工具
apt-get install libtinfo5 //vim相关依赖
apt-get install libpython3.5 //vim相关依赖
apt-get install vim //下载vim
如果在更新包管理工具时报错没有公钥无法验证签名:
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)
测试vim:
vim 1.txt //编写txt文件(内容任意)
提交新的Ubuntu镜像:
docker commit -m="描述信息" -a="作者" 容器名称/id 镜像名称[:标签]
docker hub注册账号:https://registry.hub.docker.com/signup
docker login //登录
docker tag 镜像名称 仓库名称/镜像名称:版本号 //打标签
docker rmi -f 仓库名称/镜像名称:版本号 //删除标签
docker push 镜像名称:版本号 //推送到docker hub
测试:
由于docker hub外网访问较慢,可以将本地镜像推送到阿里云:
创建命名空间、镜像仓库
测试:
搭建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 //查看私有库镜像
测试:
数据卷就是目录文件,存在于一个或多个目录中,由docker挂在到容器,用于数据持久化和共享数据,完全独立于容器之外,容器删除时不能一起删除
在centos7中挂载目录默认为不安全行为,禁止该行为,可以使用--privileged=true
开启,扩大容器权限,使得容器内的root权限拥有主机的root权限
docker run -it --privileged=true -v /本机绝对路径:/容器内目录 镜像名
搭载数据卷后,容器内指定目录文件和本机指定目录文件实时同步(双向):
本机1.txt文件写入内容1.txt,容器同步更新:
停止容器后,主机对指定目录的更新,在容器启动后会全部同步
docker inspect 容器名称/id //查看容器挂载数据卷
默认搭载数据卷后主机和容器支持双向读写共享
docker run -it --privileged=true -v /本机绝对路径:/容器内目录[:rw] 镜像名
docker run -it --privileged=true -v /本机绝对路径:/容器内目录[:ro] 镜像名 //容器只能读不能写
容器中指定目录不能创建文件,不能对文件进行写操作:
主机目录更新依然能同步,但容器内只能进行读操作:
//继承父容器 搭载数据卷相同
docker run -it --privileged=true --volumes-from 父容器名称/id 子容器名称/id
任何一处修改,主机、父容器、子容器进行同步(父容器停止不会影响子容器):
docker search tomcat --limit 5 //搜索tomcat
docker pull tomcat //拉取tomcat
docker run -d -p 8080:8080 --name tomcat tomcat //启动tomcat
浏览器访问:
解决方法:
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容器
MySQL8以上版本的账户加密方式是caching_sha2_password
,Navicat不支持这种账户加密方式
use mysql;
select host,user,plugin from user;
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '密码'; //修改为原始加密方式
没有中文乱码
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; //显示主从复制信息
授予root用户权限
主库查看binlog:
从库配置主从复制:
从库开启主从复制:
查看主从复制信息:
注意:
主库和从库都需要配置账户加密方式为mysql_native_password
,以便Navicat连接
测试:
主库建库建表,从库同步:
主库插入数据:
从库同步:
从库执行写操作:
准备一个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容器
创建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}
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
**注意:**云服务器需要配置安全组规则,添加所有端口 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
//主节点为7000、7001、7002 每个主节点有一个从节点 所属从节点随机分配
redis-cli -a 密码 --cluster create --cluster-replicas 1 外网IP:7000 外网IP:7001 外网IP:7002 外网IP:7003 外网IP:7004 外网IP:7005
redis-cli -c -a root -p 7000
cluster info //查看集群状态
cluster nodes //查看节点信息
当前主从信息:
节点 | 槽位 | 从节点 |
---|---|---|
7000 | 0 - 5460 | 7004 |
7001 | 5461 - 10922 | 7005 |
7002 | 10923 - 16383 | 7003 |
redis-cli -a 密码 --cluster check 外网IP:7000 //查看节点存储key数量和主从配置信息
设置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
运行容器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
将redis7006节点加入集群:
docker exec -it redis7006 bash //进入新创建的容器redis7006
redis-cli -a 密码 --cluster add-node 外网IP:7006(自己) 外网IP:7000(集群中的一个主节点) //将自己加入集群
redis-cli -a 密码 --cluster check 外网IP:7006 //查看集群信息
重新分配槽位:
redis-cli -a 密码 --cluster reshard 外网IP:7000 //重新分配槽位
redis-cli -a 密码 --cluster check 外网IP:7006 //查看集群信息
重新分配成本太高,三个节点各自匀出来一部分槽位分给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
添加为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 //集群节点信息
减少redis节点:
先删除从节点redis7007:
redis-cli -a 密码 --cluster del-node 外网IP:7007 节点id
redis-cli -a 密码 --cluster check 外网:7000
将redis7006的槽位重新分配给redis7000
redis-cli -a 密码 --cluster reshard 外网IP:7000 //重新分配槽位
redis-cli -a 密码 --cluster check 外网IP:7006 //查看集群信息
删除节点redis7006:
redis-cli -a 密码 --cluster del-node 外网IP:7007 节点id
redis-cli -a 密码 --cluster check 外网:7000
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
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
docker exec -it elasticsearch bash
bin/elasticsearch-setup-passwords interactive //设置elasticsearch密码
浏览器访问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 //查看加载的插件
安装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
运行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');
编写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
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
浏览器访问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
重启容器即可
编写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" } }
编写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" } }
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 //复制文件到容器
**注:**云服务器需要配置安全组规则开启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;
修改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 = "密码" } }
docker restart seata-server //重启容器
docker logs seata-server //查看容器日志
查看nacos注册seata-server成功
最后显示load即为成功
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
使用原始密码(sentinel/sentinel)登录失败:
查看日志文件:
Dockerfile是用来构建docker镜像的文本文件,是由一条条构建镜像所需的指令和参数组成的脚本
官网:https://docs.docker.com/engine/reference/builder/
Dockerfile是独立于docker之外的文件:
Dockerfile需要遵循以下规则:
Docker执行Dockerfile步骤:
1.docker基于基础镜像运行一个容器
2.执行一条指令对容器作出修改
3.执行docker commit操作提交一个镜像层
4.然后基于提交的镜像运行一个容器
5.执行dockerfile的下一条指令直到所有指令都执行完
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传递参数,
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
docker build -t 镜像名称[版本号] . //在含有Dockerfile的目录执行build命令
仓库名、标签都是<none>
的镜像,称为虚悬镜像(dangling image),这些镜像是出现错误产生的,占据宿主
机空间需要进行删除
docker image ls -f dangling=true //查看虚悬镜像
docker image prune //删除所有虚悬镜像
创建Springboot项目,编写控制器:
@RestController
public class HelloController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/hello")
public String helloWorld(){
return "Hello World! serverPort=" + serverPort;
}
}
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>
打成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
构建镜像:
运行镜像:
访问测试:
docker网络用于容器间的互联通信以及端口映射,在容器IP变动时可以通过服务名进行网络通信
启动docker后,会产何时能一个名为docker0
的虚拟网桥
eth0:表示主机的以太网卡
lo:表示主机的回环地址,是本机用来测试的网络地址
docker network creat 网络名称//创建网络
docker network inspect 网络名称//展示网络信息
docker network ls //显示所有网络
docker rm 网络名称 //删除网络
网络模式 | 说明 |
---|---|
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 //正确
主机模式容器内网络配置和宿主机一致
使用默认端口8080访问:
none:
docker run -it --name alpine --network none alpine /bin/sh //none模式运行
只有回环地址
container:
docker run -it --name alpine1 alpine /bin/sh //运行容器alpine1
docker run -it --name alpine2 --network container:alpine1 alpine /bin/sh //container模式运行容器alpine2
alpine2和alpine1一个eth0
alpine1容器关闭,alpine2中网络配置消失:
**问题:**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
删除容器alpine2(模拟容器宕机),另外创建一个新的容器:
docker rm -f alpine2 // 删除容器alpine2
docker run -it --name alpine3 alpine /bin/sh //创建新的容器alpine3
docker inspect alpine3 | tail -n 20 //查看alpine3分配IP
总结:
容器当宕机后,后续创建的容器会继续使用其IP地址。对于固定IP地址进行通信,可能不会是同一个容器
没有使用自定义网络,无法使用容器名称进行通信:
使用自定义网络后,可以使用容器名称进行通信:
Docker Compose负责对Docker容器集群进行快速编排,需要定义一个docker-compose.yml
,声明多个容器
之间的调用关系,一条命令运行、停止多个容器
修改微服务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>
配置文件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
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()); } }
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; } }
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; } }
@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); } }
实体类:
@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; }
@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()); } }
@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; }
UserMapper:
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
UserService:
public interface UserService extends IService<User> {
int addUser(User user);
UserDTO findUserById(long id);
}
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; } }
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获取用户信息成功!"); } } }
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: # 创建网络
docker compose config -q //检查yaml文件是否存在语法错误
docker compose up -d //后台运行
docker compose down //停止所有服务,并删除所有相关容器
进入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;
外部访问8080端口,/swagger-ui路径:
停止所有服务:
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也会重启保证该容器一直运行进行监控]
浏览器访问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; # } #} }
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数据库密码
docker compose up -d
浏览器访问8080端口:
浏览器访问8083端口:
浏览器访问3000端口:
使用admin/admin登录
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。