文章目录
docker软件的安装
一、容器数据卷
1.1 作用
将docker容器内的数据保存进宿主机的磁盘中,类似于redis中的rdb和aof文件
1.2 docker中的数据卷
原因:docker容器在使用过程中会产生数据,但是当容器实例删除后,容器内的数据自然也就没有了,为了保存这些数据,在docker中使用卷,具有以下特点:
- 数据卷在容器之间共享或重用数据。
- 卷中的数据如果更改会直接实时生效。
- 数据卷中的更改不会包含在镜像的更新中。
- 数据卷的声明周期一直持续到没有容器使用它为止。
案例
1.2.1:在宿主机和容器之间添加容器卷
# 添加命令
# docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
docker run -it --privileged=true -v /zpyl/myjuan:/tem/test myubuntu:1.1
# 查看数据卷是否挂载成功
# docker inspect 容器ID
docker inspect 17e5f69e2156
# 查看容器和宿主机之间的数据共享
# 1、docker修改,主机同步
# 2、主机修改,docker同步
# 3、docker容器stop,主机修改,docker容器重启数据同步
1.2.2:读写规则映射添加说明
# 默认情况下是rw,允许读和写
docker run -it --privileged=true -v /zpyl/myjuan:/tem/test:rw myubuntu:1.1
#容器实例内部被限制ro,只能读不能写
docker run -it --privileged=true -v /zpyl/myjuan:/tem/test:ro myubuntu:1.1
1.2.3:卷的继承和共享
# 容器1完成和宿主机的映射 宿主机 容器 别名 镜像名
docker run -it --privileged=true -v /mydocker/u:/tmp --name u1 ubuntu
# 容器2继承容器1的卷规则 父类容器id
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
docker run -it --privileged=true --volumes-from 9d3e48e9130d --name u2 ubuntu
二、常规安装软件
总体安装步骤:
1、搜索镜像 2、拉起镜像 3、查看镜像 4、启动镜像 - 服务器端口映射 5、停止容器 6、移除容器
2.1 安装Tomcat
# 搜索镜像:
# 在https://hub.docker.com/中搜到镜像
# 拉起镜像:
docker pull tomcat
# 查看镜像:
docker images
# 启动镜像
docker run -d -p 8080:8080 --name t1 tomcat
# 访问
127.0.0.1:8080
注意:访问的时候可能会出现404错误,这是由于新版的tomcat将原先的页面删除,需要做一下简单的配置
# 进入tomcat容器
docker exec -it cf213de62594 /bin/bash
# 进入tomcat文件夹
cd /usr/local/tomcat
# 删除webapps
rm -rf webapps
# 重命名webapps.dist
mv webapps.dist webapps
# 访问
127.0.0.1:8080
建议安装免修改版
docker pull billygoo/tomcat8-jdk8
2.2 安装mysql
2.2.1 安装单机版
# 下载
docker pull mysql:5.7
# 开启镜像
docker run -d -p 3306:3306 --privileged=true -v /zpyl/mysql/log:/var/log/mysql -v /zpyl/mysql/data:/var/lib/mysql -v /zpyl/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
# 在宿主机的conf.d中新建my.cnf文件,添加以下内容,通过容器数据卷同步给mysql容器
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
# 重启mysql容器
docker restart mysql
解析:
docker run -d -p 3306:3306 --privileged=true -v /zpyl/mysql/log:/var/log/mysql -v /zpyl/mysql/data:/var/lib/mysql -v /zpyl/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
做好数据库的备份,将mysql的日志、数据和配置在宿主机和容器之间添加数据卷
2.2.1 安装主从复制版
# 安装主机
docker run -d -p 3307:3306 --privileged=true -v /zpyl/mysql-master/log:/var/log/mysql -v /zpyl/mysql-master/data:/var/lib/mysql -v /zpyl/mysql-master/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-master mysql:5.7
# 在zpyl/mysql-master/conf 下新建my.cnf文件,添加以下信息
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=101
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=dblog-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
## 字符集
collation_server = utf8_general_ci
character_set_server = utf8
[client]
default_character_set=utf8
# 重启容器
docker restart mysql-master
# 查看服务是否正常启动
docker ps
# 如果出现服务未启动,查看日志
docker logs -f --tail 10 mysql-master
# 进入主机中创建数据同步的用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
# 为用户授予权限
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
# 安装从机
docker run -d -p 3308:3306 --privileged=true -v /zpyl/mysql-slave/log:/var/log/mysql -v /zpyl/mysql-slave/data:/var/lib/mysql -v /zpyl/mysql-slave/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-slave mysql:5.7
# 在zpyl/mysql-slave/conf 下新建my.cnf文件,添加以下信息
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
log-bin=dblog-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
## slave设置为只读(具有super权限的用户除外)
read_only=1
## 字符集
collation_server = utf8_general_ci
character_set_server = utf8
[client]
default_character_set=utf8
# 重启服务
docker start mysql-slave
# 在主数据库中查看主从同步状态,记录下file和position
show master status;
# 在从数据库中配置主从复制
change master to master_host='192.168.1.18', master_user='slave', master_password='123456', master_port=3307, master_log_file='dblog-bin.000001', master_log_pos=154, master_connect_retry=30;
##参数说明
# master_host:主数据库的IP地址; #master_port:主数据库的运行端口;
# master_user:在主数据库创建的用于同步数据的用户账号;
# master_password:在主数据库创建的用于同步数据的用户密码;
# master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
# master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
# master_connect_retry:连接失败重试的时间间隔,单位为秒。
# 在从数据库中查看主从同步状态 Slave_IO_Running和Slave_SQL_Running 此时都为No,表示没有开启
show slave status \G;
# 从从数据库中开启主从同步
start slave;
# 再次查看主从同步状态 可以看到Slave_IO_Running和Slave_SQL_Running 此时都为Yes,则表示同步成功
# 在主库中测试增删改查,在从库中看结果
2.3 安装redis
2.3.1 redis单机版
# 下载
docker pull redis:6.0.8
# 在宿主机上新建redis文件夹,作为容器数据卷,将官网下载的redis.conf文件放入其中 https://github.com/redis/redis/blob/6.0.8/redis.conf
mkdir /zpyl/redis
# 修改redis.conf文件的以下配置
# 1、开启redis验证
requirepass 123
# 2、允许redis外地连接 注释掉 # bind 127.0.0.1
# 3、daemonize no 将daemonize yes注释起来或者 daemonize no设置,因为该配置和docker run中-d参数冲突,会导致容器一直启动失败
# 4、开启redis数据持久化 appendonly yes
# 运行redis容器
docker run -p 6379:6379 --name redis --privileged=true -v /zpyl/redis/redis.conf:/etc/redis/redis.conf -v /zpyl/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
# 测试redis
docker exec -it redis redis-cli
2.3.2 redis集群版
题:1~2亿条数据需要缓存,请问如何设计这个存储案例?
答案:使用redis进行分布式存储,一般有三种解决方案
- 哈希取余分区
- 一致性哈希算法分区
- 哈希槽分区
2.3.2.1 哈希取余分区
借助公式hash(key) % N机器总数,计算出哈希值,用来决定数据映射到哪一个节点上。
优点:简单粗暴,直接有效
缺点:进行扩容或缩容比较麻烦,每次redis的总数发生变化时,整个数据的映射关系就需要重新计算,如果某一台机器出现问题,或导致hash取余全部重新洗牌。
2.3.2.2 一致性哈希算法分区
缘由:为了解决分布式缓存数据变动和映射的问题,不在依据机器总数进行取余,根据自然数进行取余,当服务器个数发生变化时,尽量减少客户端到服务器的映射关系。
概念:一致性hash算法是 2 32 2^{32} 232对进行取模,将产生的0~ 2 31 2^{31} 231-1的值,这些值构成一个hash空间,将它们按照顺序首尾相连,构成以环形空间,简称hash环。
然后将服务器映射到hash环上,通过对服务器的唯一标识进行hash取值,这样每台机器在环上就有一个位置了。
最后将要保存的数据进行哈希取值,找到环上的位置,从此位置顺时针走,找到最近的一台服务器,那么这就是目标服务器。
优点:具有容错性,假如服务器宕机时,只影响它本身存储的内容,不需要重新构建映射关系
具有扩展性,在A,B节点之间添加X服务器时,只影响后面的A到X之间的数据,只需要将A到X之间的数据复制到X上即可,不需要重新hash。
缺点:当服务器上的节点太少的时候,容易造成节点分布不均匀而造成的数据倾斜问题。
2.3.2.3 哈希槽分区
缘由:解决一致性哈希算法的数据倾斜问题
思路:在数据和节点之间又加了一层,这层称为哈希槽,用于管理数据和节点之间的关系,相当于节点上放的是槽,而槽里放的是数据。
hash槽:一个redis集群中只能有16384个槽,编号为0~ 2 14 − 1 2^{14}-1 214−1,redis会根据节点的数量大致均等的将hash槽映射到不同的节点,当需要放置一个key-value时, redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。
2.3.2.4 搭建redis集群
# 启动6个redis容器
docker run -d --name redis-node-1 --net host --privileged=true -v /zpyl/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /zpyl/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /zpyl/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /zpyl/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /zpyl/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /zpyl/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
## 解析
# --net host:使用宿主机的ip和端口
# --privileged=true 获取宿主机的root用户权限
# --cluster-enabled yes 开启redis集群
# --appendonly yes 开启持久化
# --port 6386 redis端口号
# 进入其中一台机器构建集群关系
docker exec -it redis-node-1 /bin/bash
# 构建主从关系
redis-cli --cluster create 192.168.1.18:6381 192.168.1.18:6382 192.168.1.18:6383 192.168.1.18:6384 192.168.1.18:6385 192.168.1.18:6386 --cluster-replicas 1
## 解析
# --cluster-replicas 1 表示为每一个master创建一个slave节点
# 如果输出:All nodes agree about slots configuration和All 16384 slots covered则表示3主3从构建完成
# 连接其中一台redis
redis-cli -p 6381
# 查看集群状态
cluster info
# 查看节点信息
cluster nodes
2.3.2.4.1 数据读写存储
当使用redis-cli -p 6381 直接对redis新增key-value时,可能会出现报错
使用-c来优化路由 redis-cli -p 6381 -c
然后在执行操作
查看集群信息:redis-cli --cluster check 192.168.1.18:6386
2.3.2.4.2 容错切换迁移
仔细查看节点的主从状态使用cluster nodes查看
主机6381,从机6386
将主机6381停止,在次查看
发现此前的6386变成主机继续工作了
在此启动6381,在此查看
此时6381则变成了从机
检查集群的状态
redis-cli --cluster check 192.168.1.18:6381
2.3.2.4.3 主从扩容
# 新建俩个节点6387和6388
docker run -d --name redis-node-7 --net host --privileged=true -v /zpyl/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
docker run -d --name redis-node-8 --net host --privileged=true -v /zpyl/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
# 进入6387节点作为master节点加入集群
# 新加入的主节点6387 原集群节点6381
redis-cli -cluster add-node 192.168.1.18:6387 192.168.1.18:6381
# 查看集群节点状态
redis-cli --cluster check 192.168.1.18:6381
# 发现哈希槽号为空,这是因为没有分配槽号
# 重新分配槽号 集群中的节点
redis-cli --cluster reshard 192.168.1.18:6381
# 重新分配时会询问你移动多少个节点到新的节点上,这里根据实际情况进行填写
How many slots do you want to move (from 1 to 16384)? 4096
# 询问你将这些节点分配到哪个节点,输入你新添加等的节点的id即可
What is the receiving node ID? de08089905620c891a9c790a2fe7e2ed9df6c747
# 会询问你从哪些节点进行转移,输入all表示从所有节点中随机抽取
Please enter all the source node IDs. all
# 重新查看集群节点状态
redis-cli --cluster check 192.168.1.18:6381
# 发现新添加的节点的哈希槽号并不是连续的,而之前分配的节点是连续的,这是因为重新分配的成本太高,所以是从前面节点中各自匀一点出来的
# 为6387分配从节点6388
# redis-cli --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID
redis-cli --cluster add-node 192.168.1.18:6388 192.168.1.18:6387 --cluster-slave --cluster-master-id de08089905620c891a9c790a2fe7e2ed9df6c747
# 重新查看集群节点状态
redis-cli --cluster check 192.168.1.18:6381
2.3.2.4.5 主机缩容
# 将6388删除(从机)
# redis-cli --cluster del-node ip:端口 节点ID
redis-cli --cluster del-node 192.168.1.18:6388 8c0eaf342c8befa8c51f2ecb3137281e17ff2ad9
# 将6387删除(主机)
# 将主机的的哈希槽清空,将清出来的槽位都给6386
redis-cli --cluster reshard 192.168.111.147:6386
# 重新分配时会询问你移动多少个节点到新的节点上,这里根据实际情况进行填写
How many slots do you want to move (from 1 to 16384)? 4096
# 询问你将这些节点分配到哪个节点,输入待分配的节点的id即可这里使用6386的
What is the receiving node ID? 0d1f2fbfa05044fcaaf415001220e9e752d70bea
# 输入提供的节点的id,这里选择6387的
Source node #1: de08089905620c891a9c790a2fe7e2ed9df6c747
# 然后输入done
Source node #2:done
# 将6387删除
redis-cli --cluster del-node 192.168.1.18:6387 de08089905620c891a9c790a2fe7e2ed9df6c747
# 重新查看集群节点状态
redis-cli --cluster check 192.168.1.18:6381