docker--高级
案例--mysql一主一从
-
创建mysql3307
-
命令:
-
docker run -p 3307:3306 --name mysql-master -v /mydata/mysql-master/log:/var/log/mysql -v /mydata/mysql-master/data:/var/lib/mysql -v /mydata/mysql-master/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
-
创建目录----mkdir
-
创建/mydata/mysql-master/conf/my.cnf文件
-
[mysqld] ##设置server_id,同一局域网需要唯一 server_id=101 ##指定不需要同步的数据库名称 binlog-ignore-db=mysql #开启二进制日志功能 log-bin=mall-mysql-bin ##开启二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用二进制日志格式(mixed,startment,row) binlog_format=mixed ## 二进制日志过期清理时间,默认值为0,表示不自动清理 expire_logs_days=7 ##跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端赋值中断 slave_skip_errors=1062
-
进入mysql-master容器
-
使用mysql -uroot -proot命令进入mysql
-
创建用户--- create user 'slave' @'%' IDENTIFIED BY '123456';
-
执行GRANT REPLICATION SLAVE,REPLICATION CLIENT ON . TO 'slave'@'%';
-
创建从机
-
docker run -p 3308:3306 -name mysql-slave -v /mydata/mysql-master/log:/var/log/mysql -v /mydata/mysql-master/data:/var/lib/mysql -v /mydata/mysql-master/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
-
创建my.cnf文件
-
[mysqld] ##设置server_id,同一局域网需要唯一 server_id=102 ##指定不需要同步的数据库名称 binlog-ignore-db=mysql #开启二进制日志功能 log-bin=mall-mysql-bin ##开启二进制日志使用内存大小(事务) binlog_cache_size=1M ## 设置使用二进制日志格式(mixed,startment,row) binlog_format=mixed ## 二进制日志过期清理时间,默认值为0,表示不自动清理 expire_logs_days=7 ##跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端赋值中断 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
-
进入master使用show master status;命令
-
-
参数说明
-
-
change master to master_host='192.168.44.130', master_user='slave',master_password='123456',master_port=3307,master_log_file='mall-mysql-bin.000001',master_log_pos=154,master_connect_retry=30;
-
从机执行上面命令
-
-
没开始主从复制
-
在从数据库开启同步
-
start slave;
-
面试题:1~2亿条数据需要缓存,请问如何设计这个存储案例
回答单机单台100%不可能,肯定是分布式存储,用redis如何落地?
三种解决方案:
哈希取余分区
- 小厂--->哈希取余分区
优点:简单粗暴,直接有效,只需要预估好数据规划好节点,例如3台、8台、10台,就能保证在一段时间的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求)、起到负载均衡+分而治之的作用。
缺点:原来规划好的节点,进行扩容或者缩容就比较麻烦了,不管扩缩,每次数据变动导致节点有点变动,映射关系需要重新进行计算,在服务器个数固定不变时没有问题,如果需要弹性扩容或者故障停机的情况下,原来的取模公式就会发生变化;Hash(key)/3会变成Hash(key)/?。此时地址经过某个redis机器宕机了,由于台数数量变化,会导致hash取余全部数据重新洗牌
一致性Hash算法分区
- 中厂:一致性Hash算法分区
- 能干什么:提出一致性解决方案。目的是当服务器荷属发生变动时,将量减少影响客户端到服务器的映射关系
- 三大步骤:构建一致性hash环,服务器ip节点映射,key落到服务器的落键规则
- 优点
- 缺点:一致性hash算法的数据倾斜问题
- 总结:
哈希槽分区
3主3从redis集群配置
docker run -d --name redis-node-1 --net host --privileged=true -v /data/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 /data/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 /data/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 /data/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 /data/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 /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
-
进入容器内部
-
redis-cli --cluster create 192.168.44.130:6381 192.168.44.130:6382 192.168.44.130:6383 192.168.44.130:6384 192.168.44.130:6385 192.168.44.130:6386 --cluster-replicas 1
-
主从容错切换迁移案例
-
- 数据读写存储
- 原因通过hash算法当前key的槽不在6381
- 解决办法,连接时加上-c参数
- 检查集群:
- redis-cli --cluster check 192.168.44.130:6381
-
容错切换迁移
-
扩容,原来的6台机器变成8台
-
新增主机6387无槽号
-
docker run -d --name redis-node-7 --net host --privileged=true -v /data/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 /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
-
进入容器--docker exec -it redis-node-7 /bin/bash
-
将该节点加入集群----redis-cli --cluster add-node 192.168.44.130:6387 192.168.44.130:6381
-
6381是6388的领路人
-
-
-
重新分配卡槽
-
redis-cli --cluster reshard IP地址:端口号
-
redis-cli --cluster reshard 192.168.44.130: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.44.130:6388 192.168.44.130:6387 --cluster-slave --cluster-master-id 11bb4628607887d3a992221c5bccedd6b8c48f32
-
-
缩容
- 先删除从节点
- 重新分配槽点(原路返回,还是只给一个?)
- 删除主节点
- 恢复3主3从
删除从节点
命令:redis-cli --cluster del-node ip:从机端口 从机6388节点Id
redis-cli --cluster del-node 192.168.44.130:6388 f0e50b122664267465f157f5aa76f29a5383f938
重新分配槽点
redis-cli --cluster reshard 192.168.44.130:6381
检查情况---
删除主节点
查看结果
dockerfile
构建三步骤:编写dockerfile文件 ----->docker build 命令构建镜像 ------->docker run依镜像运行容器实例
- RUN
构建自己的helloworld镜像
scratch镜像和ADD指令
scratch镜像
在构建自己的镜像之前,首先要了解一个特殊的镜像 scratch。 scratch 镜像是一个空镜像,是所有镜像的 Base Image(相当于面向对象编程中的 Object 类)。scratch 镜像只能在 Dockerfile 中被继承,不能通过 pull 命令拉取,不能 run,也没有 tag。 并且它也不会生成镜像中的文件系统层。在 Docker 中,scratch 是一个保留字,用户不能作 为自己的镜像名称使用。
ADD镜像
【语法 1】ADD
【语法 2】ADD ["
【解析】该指令将复制当前宿主机中指定文件 src 到容器中的指定目录 dest 中。src 可以是
宿主机中的绝对路径,也可以时相对路径。但相对路径是相对于 docker build 命令所指定的
路径的。src 指定的文件可以是一个压缩文件,压缩文件复制到容器后会自动解压为目录;
src 也可以是一个 URL,此时的 ADD 指令相当于 wget 命令;src 最好不要是目录,其会将该
目录中所有内容复制到容器的指定目录中。dest 是一个绝对路径,其最后面的路径必须要加
上斜杠,否则系统会将最后的目录名称当做是文件名的。
构建centos镜像
·
#Dockerfile
FROM centos:7
MAINTAINER yhd 1451053372@qq.com
LABEL version="1.0" description="this is a centos7 image made in yhd" author="TOM" email="1451053372@qq.com"
ENV WORKPATH /usr/local
WORKDIR $WORKPATH
RUN yum install -y wget vim net-tools
CMD /bin/bash
悬虚镜像
发现出现悬虚镜像
如何删除悬虚镜像
docker rm -f 镜像id
docker system prune 删除四类无用文件,其中就包括悬虚镜像
docker image prune 用于删除悬虚镜像
CMD&ENTRYPOINT
CMD
-
CMD ["EXECUTABLE","PARAM1","PARAM2", ...]
-
在容器启动后,即在执行完 docker run 后会立即调用执行"EXECUTABLE"指定的可执行文件,并使用后面第二、三等参数作为应用程序的运行参数。
-
CMD command param1 param2, ...
-
这里的 command 就是 shell 命令。在容器启动后会立即运行指定的 shell 命令。
-
CMD ["PARAM1","PARAM2", ...]
-
提供给 ENTERYPOINT 的默认参数。
举例:
#Dockerfile
FROM centos:7
CMD cal
#Dockerfile2
FROM centos:7
CMD ["cal"]
#Dockerfile3
FROM centos:7
CMD ["/bin/bash","-c","cal"]
tips:当文件名不是Dockerfile时,docker build需要加上-f指定文件名
在build命令 .指定文件路径,.为当前路径可以替换
ENTRYPOINT
-
ENTRYPOINT ["EXECUTABLE","PARAM1","PARAM2", ...]
-
在容器启动过程中,即在执行 docker run 时,会调用执行"EXECUTABLE"指定的应用
程序,并使用后面第二、三等参数作为应用程序的运行参数
-
ENTRYPOINT command param1 param2, ...
-
这里的 command 就是 shell 命令。在容器启动过程中,即在执行 docker run 时,会
运行指定的 shell 命令。
#Dockerfile4
FROM centos:7
ENTRYPOINT cal
#Dockerfile4
FROM centos:7
ENTRYPOINT ["cal"]
FROM centos:7
ENTRYPOINT ["/bin/bash","-c","cal"]
CMD&ENTRYPOINT联用
FROM centos:7
CMD ["hello world"]
ENTRYPOINT ["echo"]
Dockerfile中的[command]或["EXECUTABLE"]如果是通过CMD指定的,则该镜像的启动命令docker run 中是不能添加参数[ARG]的,因为dockerfile中CMD是可以被[COMMAND]替代的,如果命令中的IMAGE后任有内容,此时对于docker daemon来说,其首先认为时替代用的[COMMAND],如果有两个或两个以上的内容,后面的内容才会认为时[ARG]。所以,添加的-y会报错,因为没有-y这个[COMMAND]
Dockerfile中的[command]或["EXECUTABLE"]如果是通过ENTRYPOINT指定的,则该镜像的启动命令docker run 中是可以添加参数[ARG]的,因为dockerfile中ENTRYPOINT不能被[COMMAND]替代的,如果命令中的IMAGE后任有内容,此时对于docker daemon来说,其只能是[ARG]。docker demon对于ENTRYPOINT指定的[command]与["ENTRYPOINT]的吃力方式是不同的,如果是shell,daemon会直接运行,而不会与docker run中的[ARG]拼接,如果是["EXECUTABLE"]指定的命令,daemon则会先与docker run中的[ARG]进行拼接然后再运行拼接后的结果。
结论:无论是CMD还是ENTRYPOINT,使用["EXECUTABLE"]方式的通用性会更强些。
ADD©
- ADD
- ADD ["
", " "] # 路径中存在空格时使用双引号引起来 - 该指令将复制当前宿主机中指定文件 src 到容器中的指定目录 dest 中。src 可以是宿主机中的绝对路径,也可以时相对路径。但相对路径是相对于 docker build 命令所指定的路径的。src 指定的文件可以是一个压缩文件,压缩文件复制到容器后会自动解压为目录;src 也可以是一个 URL,此时的 ADD 指令相当于 wget 命令;src 最好不要是目录,其会将该目录中所有内容复制到容器的指定目录中。dest 是一个绝对路径,其最后面的路径必须要加上斜杠,否则系统会将最后的目录名称当做是文件名的。
- COPY
- 【说明】功能与 ADD 指令相同,只不过 src 不能是 URL。若 src 为压缩文件,复制到容器后
- 不会自动解压.
onbuild
-
【语法】ONBUILD [INSTRUCTION]
-
【解析】该指令用于指定当前镜像的子镜像进行构建时要执行的指令。
#Dockerfile FROM centos:7 ENV WORKPATH /usr/local WORKDIR $WORKPATH ONBUILD RUN yum install -y wget CMD /bin/bash
#Dockerfile2 FROM parent:1.0
可以构建出新的镜像的方式有:
- docker build
- docker commit
- docker import(注意,docker load 并没有构建出新的镜像,其与原镜像是同一个镜像)
- docker compose
- docker hub 中完成 Automated Builds
制作自己项目的镜像
FROM openjdk:8u102
LABEL author="yhd" email="1451053372@qq.com" version="1.0"
#复制原jar包到根目录
COPY demo.jar hd.jar
#执行java-jar
ENTRYPOINT ["java","-jar","hd.jar"]
EXPOSE 8080
镜像生成过程
FROM centos:7
LABEL auth="Tom"
COPY hello.log /var/log/
RUN yum -y install vim
CMD /bin/bash
- 镜像的生成过程
- 为了了解什么是 build cache,理解镜像构建过程中 build cache 机制,需要先了解镜像的生成过程。Docker 镜像的构建过程,大量应用了镜像间的父子关系。即下层镜像是作为上层镜像的父镜像出现,下层镜像是作为上层镜像的输入出现;上层镜像是在下层镜像的基础之上变化而来。下面将针对上面的例子逐条指令的分析镜像的构建过程。
- 前提知识
- 每一个镜像都由镜像文件系统和json文件组成,镜像id由这两个通过sha256算法生成,也就是说如果产生新的镜像id,肯定是文件系统或者json发生该改变
- FROM centos:7
- FROM 指令是 Dockerfile 中唯一不可缺少的指令,它为最终构建出的镜像设定了一个基础镜像(Base Image)。该语句并不会产生新的镜像层,它是使用指定的镜像作为基础镜像层的。docker build 命令解析 Dockerfile 的 FROM 指令时,可以立即获悉在哪一个镜像基础上完成下一条指令镜像层构建。对于本例,Docker Daemon 首先从 centos:7 镜像的文件系统获取到该镜像的 ID,然后再根据镜像 ID 提取出该镜像的 json 文件内容,以备下一条指令镜像层构建时使用。
- LABEL auth="Tom"
- LABEL 指令仅修改上一步中提取出的镜像 json 文件内容,在 json 中添加 LABEL auth="Tom",无需更新镜像文件系统。但也会生成一个新的镜像层,只不过该镜像层中只记录了 json 文件内容的修改变化,没有文件系统的变化。如果该指令就是最后一条指令,那么此时形成的镜像的文件系统其实就是原来 FROM 后指定镜像的文件系统,只是 json 文件发生了变化。但由于 json 文件内容发生了变化,所以产生了新的镜像层。
- COPY hello.log /var/log/
- COPY 指令会将宿主机中的指定文件复制到容器中的指定目录,所以会改变该镜像层文件系统大小,并生成新的镜像层文件系统内容。所以 json 文件中的镜像 ID 也就发生了变化,产生了新的镜像层。
- RUN yum -y install vim
- RUN 指令本身并不会改变镜像层文件系统大小,但由于其 RUN 的命令是 yum install,而该命令运行的结果是下载并安装一个工具,所以导致 RUN 命令最终也改变了镜像层文件系统大小,所以也就生成了新的镜像层文件系统内容。所以 json 文件中的镜像 ID 也就发生了变化,产生了新的镜像层。
- CMD /bin/bash
- 对于 CMD 或 ENTRYPOINT 指令,其是不会改变镜像层文件系统大小的,因为其不会在docker build 过程中执行。所以该条指令没有改变镜像层文件系统大小。但对于 CMD 或 ENTRYPOINT 指令,由于其是将来容器启动后要执行的命令,所以会将该条指令写入到 json 文件中,会引发 json 文件的变化。所以 json 文件中的镜像 ID 也就发生了变化,产生了新的镜像层。
build cache
修改dockerfile
FROM centos:7
LABEL auth="Tom"
COPY hello.log /var/log/
RUN yum -y install vim
CMD /bin/bash
EXPOSE 9000
删除镜像时,只有当最后一个镜像被删除时,build cache才会被删除
-
build cache 机制
-
Docker Daemnon 通过 Dockerfile 构建镜像时,当发现即将新构建出的镜像(层)与本地已存在的某镜像(层)重复时,默认会复用已存在镜像(层)而不是重新构建新的镜像(层),这种机制称为 docker build cache 机制。该机制不仅加快了镜像的构建过程,同时也大量节省了Docker 宿主机的空间。docker build cache 并不是占用内存的 cache,而是一种对磁盘中相应镜像层的检索、复用机制。所以,无论是关闭 Docker 引擎,还是重启 Docker 宿主机,只要该镜像(层)存在于本地,那么就会复用。
-
build cache 失效
docker build cache 在以下几种情况下会失效。
Dockerfile 文件发生变化
当 Dockerfile 文件中某个指令内容发生变化,那么从发生变化的这个指令 层开始的所有镜像层 cache 全部失效。即从该指令行开始的镜像层将构建出新的镜像层,而不再使用 build cache,即使后面的指令并未发生化。因为镜像关系本质上是一种树状关系,只要其上层节点变了,那么该发生变化节点的所有下层节点也就全部变化了。
ADD 或 COPY 指令内容变化
Dockerfile 文件内容没有变化,但 ADD 或 COPY 指令所复制的文件内容发生了变化,同样会使从该指令镜像层开始的后面所有镜像层的 build cache 失效。
RUN 指令外部依赖变化
与 ADD/COPY 指令相似。Dockerfile 文件内容没有变化,但 RUN 命令的外部依赖发生了变化,例如本例中要安装的 vim 软件源发生了变更(版本变化、下载地址变化等),那么从发生变化的这个指令层开始的所有镜像层 cache 全部失效。
指定不使用 build cache
有些时候为了确保在镜像构建过程中使用到新的数据,在镜像构建 docker build 时,通
过--no-cache 选项指定不使用 build cache。
清理 dangling build cache
dangling build cache,即悬虚 build cache,指的是无法使用的 build cache。一般为悬虚镜像 dangling image 所产生的 build cache。通过 docker system prune 命令可以清除。
dockerfile持久化
#Dockerfile
FROM centos:7
VOLUME /opt/xxx /opt/ooo
CMD /bin/bash
构建镜像 build
使用 Dockerfile 构建镜像 volscon:latest。
有个疑问?我们没有指定宿主机的数据卷
概念:持久化中容器内叫做挂载点,宿主机叫数据卷
通过查看docker inspect发现数据卷时docker daemo自动生成的;
总结
定制镜像持久化
理解定制镜像持久化方式针对的应用场景:对 UnionFS 产生一次性变化,且这种变化易于持久化为镜像。不适合变更非常频繁的实时性场景。
数据卷持久化
需要理解两点:
数据卷属于宿主机文件系统,与 UnionFS 是挂载关系,与容器挂载点是硬链接关系,容器的存在与否与数据卷没有关系
数据卷持久化可以做到对容器变更的实时性持久化,不会出现数据丢失的情况
Dockerfile 持久化
理解 docker run –v 方式与 Dockerfile 的 VOLUME 指令方式指定数据卷的区别:
docker run –v 方式是针对已经存在的镜像的,而 Dockerfile 的 VOLUME 指令方式是针对
准备创建的镜像的。
docker run –v 方式可以指定宿主机中的数据卷目录,而 Dockerfile 的 VOLUME 指令方式无法指定宿主机中的数据卷目录,其是 Docker Daemon 自动分配的。所以对于用户来说,通过 docker run –v 方式来指定数据卷会更为清晰明了些
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?