Docker

简介

由于docker网站国内访问受限制,所以本文使用的的docker资源下载源自于阿里云的镜像服务。本文只是简单介绍下docker的来源历史以及使用,主要侧重于理解docker是什么,为什么使用,对于docker内核并没有过多讲解,只是简单介绍了一部分。适合人群:有一定的网络基础,对linux操作系统有简单的了解。

docker是什么

什么是虚拟化、容器化

虚拟化:通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上同时运行多个逻辑计算机。

容器化:一种虚拟化技术,将操作系统虚拟化,又称操作系统层虚拟化。容器技术是虚拟化的一种,docker是现今容器技术的行业标准。

虚拟机,对硬件层的虚拟化。

为什么需要虚拟化、容器化

资源利用率提高

差异化环境提供方便

沙箱安全,减少程序死机造成一系列的连锁反应风险

容器比虚拟机启动更快,不需要整个内核启动,相当于一个进程启动

维护和扩展更容易,docker的镜像技术大大减少了运维人员的麻烦

成本有效压缩,比如云服务器

虚拟化的实现方式

模拟计算机中的某一层,供给给上层使用,使用更少的资源。容器就是对操作系统的模拟,而虚拟机是对硬件层的模拟,像JVM之类的虚拟机是对函数层和软件层之间的模拟

主机虚拟化

主机虚拟化就是在一台计算机上安装一个虚拟化层,有两种类型:一种是直接在硬件之上,另一种是直接在操作系统之上。两种类型都通过Hypevisior(一种系统软件)来控制虚拟化。主机虚拟化的代表就是虚拟机,

容器虚拟化

Namespace(命名空间),Linux内核一种隔离资源的方式。控制进程看到的资源,让进程误以为就是操作系统,实际上一个容器就是一个进程,每个进程都可以有自己的操作系统,互相隔离,但实际上底层共享内核。

总结

上述只是简单介绍了docker来源,对docker有一个模糊概念即可,不需要一下子就完全搞懂一个东西,这是不太现实的,接下来我们会学习docker的命令,通过实战来帮助你理解docker究竟是干啥的。

docker容器命令学习

  1. docker create 创建容器 容器状态为Created

    示例:

docker create --name mywebsite5 -p 8083:80 nginx
  1. docker logs 查看容器日志 界面会输出日志 搭配-f 持久输出

    示例:

docker logs mywebsite4 -f
  1. docker attach 把你的终端直接连到容器的主进程(PID 1)的输入输出管道上,查看实时日志、发送信号,但操作会直接影响容器生命周期。搭配–sig-proxy=false 可取消ctrl + c对容器的终止,而只是断开管道连接

    示例:

    docker attach mywebsite4 --sig-proxy=false
    
  2. docker exec 在正在运行的容器里,新开一个独立的命令行终端,执行命令 / 操作容器,完全不影响容器主进程

    示例:

    docker exec -it -u nginx -w /etc mywebsite4 bash
    

    -u 指定用户名 -w 指定工作目录 如果指定用户默认是root

  3. docker start 启动容器 docker stop 暂停容器 docker restart 重启容器

    示例:

    docker start mywebsite4
    

    示例:

    docker stop mywebsite4
    

    示例:

    docker restart mywebsite4
    

    docker start 和 docker restart 都可以搭配-s 发送信号,比如发送9信号,直接杀死进程,可能会导致容器资源没有释放的问题,很少使用。

  4. docker kill 直接杀死容器

    示例:

    docker kill mywebsite4
    

    docker kill 发送的是SIGKILL信号,而docker stop 发送的是SIGTREM信号。前者是直接杀死进程,后者会给进程时间释放资源,比较缓和。

  5. docker top 查询容器的进程信息

    示例:

    docker top mywebsite4
    

    可搭配ps选项使用:

    docker top mywebsite4 aux
    
  6. docker stats 查询容器cpu,内存等使用情况

    docker stats mywebsite4
    

    搭配–no-stream可输出容器信息

  7. docker container inspect 查询容器详细信息

    示例:

    docker container inspect mywebsite4
    

    搭配-s 显示文件大小 搭配 -f json 回显json格式

  8. docker port 查看容器使用的端口号

    示例:

    docker port mywebsite4
    
  9. docker cp 容器与宿主机之间拷贝文件

    示例:

    docker cp ./index.html mywebsite4:/usr/share/nginx/html/
    
  10. docker diff 查看容器文件信息,新增 改动等等

    示例:

    docker diff mywebsite4
    
    
  11. docker commit 将容器提交为镜像

​ -a 指定提交镜像的作者

​ -m 指定提交的记录

​ -c 搭配Dockerfile指令创建镜像,可以修改启动指令

​ -p 在commit时,将容器停止,目的保持数据一致性,即使不添加,默认也会使用

​ 示例:

docker commit -a 'qhx' -m "create by qhx" -p mywebsite4forcommit mywebsite4:v3.0
  1. docker pause 暂停容器的所有进程 docker unpause 恢复容器中的所有进程 docker rm 删除容器

    示例:

    docker pause mywebsite5
    

    示例:

    docker unpause mywebsite5
    

    docker rm 并不会直接强制删除一个正在运行的容器,而是通过一个-f参数来控制,发送SIGKILL信号,从而强制删除一个正在运行的容器。但是不推荐!

  2. docker export 将容器导入为一个.tar文件,搭配 -o 选项写入到一个文件中;docker import 从归档文件中创建镜像

    示例:

    docker export -o mywebsite1.tar mywebsite1
    

    示例:

    docker import mywebsite1.tar mywebsite1:v1.0
    

    docker export 导入的是一个快照文件,会缺失一些元数据,所以一般很少使用export 和 import

  3. docker wait 阻塞一个容器直到被停止,然后输出他的退出码

    示例:

    docker wait 49a0f4398a4a
    
  4. docker rename 重命名容器

    示例:

    docker rename  mywebsite1 mywebsite1.0
    
  5. docker container prune 删除所有已经停止的容器,搭配-f选项,停止提示确认是否

    示例:

    docker container prune
    
  6. docker update 修改容器的配置,如内存使用限制,cpu使用等 但是很少会使用这个指令,基本在规划的时候就定好了这些配置,很少会变动

docker 容器命令实战

容器的批量搜索技巧

-a 显示所有的容器,包括退出的

-q 只显示容器id

-f 过滤的简写

-f name=xxx 筛选出容器名字为xxx的容器

-f status=xxx 筛选出容器状态为xxx的容器

-f ancestor=xxx 筛选出镜像名字为xxx或者镜像id为xxx的容器

示例:过滤出所有的容器id

docker ps -aq

示例:过滤出运行状态的容器

docker ps -f status=running

示例:过滤出退出状态的容器

docker ps -f status=exited

示例:过滤出镜像名字为nginx:1.21.0的容器

docker ps -f ancestor=nginx:1.21.0

示例:过滤出镜像id为4f380adfc10f的容器

docker ps -f ancestor=4f380adfc10f

容器批量操作技巧

命令替换语法: 反引号`` 和 $() ,用于将命令的输出结果作为值插入到命令行或赋值给变量。

两种形式功能相同,但推荐使用*$()*,因为它更清晰且支持嵌套,而反引号在嵌套时容易混淆。

示例:

docker stop `docker ps -q`

示例:

docker start $(docker ps -aq)

docker stop 、docker start 、docker restart 、docker rm 等操作搭配命令替换语法可以实现容器批量操作,不用像以前只能一次操作一个容器,而是一次操作多个容器,提高效率

容器的交互模式

attached模式:

前台运行容器。用于开发环境的调试,不能用于生产环境

示例:

docker run --name mywebsite5 -p 8080:80 nginx
detached模式:

后台运行容器。用于生产环境的上线。

示例:

docker run -d --name mywebsite1 -p 8080:80  nginx

使用docker attach 会把容器detached模式变成attached模式

interactive模式:

前台运行容器。用于开发环境的调试,不能用于生产环境

示例:

docker run -it --name mywebsite3 -p 8083:80 nginx bash

启动交互模式创建容器后,nginx服务并没有打开,需要再次输入nginx启动nginx服务

interactive模式与后台容器交互

示例:

docker exec -it  mywebsite1 bash

执行上述命令后,即使退出,也不会影响容器的运行,容器依然是在后台运行

容器的自动删除和自动重启

–rm 选项 容器停止运行后,就会自动删除

示例:

docker run -it --rm --name mywebsite2 -p 8081:80 nginx bash

–restart=always 选项,容器退出时重启,但是如果直接stop容器不会重启;默认情况下容器的退出策略是no,就是不重启

示例:

docker run -d --name mywebsite2 --restart=always -p 8081:80 nginx
docker exec -it  mywebsite2 bash
nginx -s quit

执行完上述命令,容器就会自动重启,但是如果你只执行stop命令,容器就直接退出了,不会重启

容器的多个环境变量设置:

-e 变量名=变量值 只能一个个的添加环境变量

示例:

docker run -d --name mywebsite3 -p 8083:80 -e MYTEST=1 -e  MYTEST=2 -e MYTEST=3 nginx

–env-file=文件路径 快捷实现添加多个环境变量

示例:

docker run -it --name mywebsite4 -p 8084:80 --env-file=./testenv nginx bash

借助容器完成特殊任务

当我们的宿主机只一个极简版本的时候,连一些基本的命令都没有,这时候我们就需要借助容器来完成操作。

示例:

docker run --net host --rm busybox ifconfig

借用容器的命令查询本机网络,–net host 指定查询宿主机网络

容器日志查看

docker logs 容器名/容器ID 

日志打印存储到文件中

docker logs mynginx01 > info.log 2> err.log

注意2> 这里不能有空格,2 > 这样是错误的语法,把错误流打印到err.log文件中

在/data/var/lib/docker/containers目录中,会有以容器id为名字的目录,进入相应的容器目录后,会有一个.log文件,格式为json,里面是容器的日志相关信息

容器资源查看

查看容器的总资源使用情况,比如cpu,IO等资源使用情况

docker stats 容器名/容器id

查看容器各进程信息

docker top mynginx01 aux

综合实战

操作容器化MySql

操作容器化Redis

制作c++ 镜像

制作springBoot镜像 springBpot使用2.xx系列,jdk使用1.8,java使用8

存储卷

是什么

存储卷是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上 的某一目录建立绑定关系。在宿主机上的这个与容器形成绑定关系的目录被称作存储卷。卷的本质是文件或者目录,它可以绕过默认的联合文件系统,直接以文件或目录的形式存在于宿主机上。

宿主机的/data/web 目录与容器中的/container/data/web 目录绑定关系,然后容器中的 进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿 主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器 直接访问宿主机中的内容,也可以宿主机向容器写入内容,容器和宿主机的数据读写 是同步的。

为什么需要存储卷

提高性能,卷能绕过联层文件系统,直接写入数据。

防止数据丢失,存储卷的本质是宿主机的一个目录,与容器的目录进行映射。即使删除容器,默认情况下数据还是在宿主机上,做到持久化存储数据。因此,方便容器与宿主机,容器与容器之间在进行互相访问时变得方便,有利于我们操作,毕竟容器和容器之间并没有指令可以做到拷贝。

上面实际上是存储卷给我们带来的优势,但并不是真正需要实现存储卷的要点。对于数据而言,可分为无状态的和有状态的,对于有状态的数据,如果你删除了容器,数据就真的丢失了,那一后期的维护和升级这么办,数据都没有了,我的应用是需要大量的数据进行计算判定的。对于无状态的数据,倒是没什么。所以,为了实现两个需求,docker就设计了存储卷,两个都能满足,一劳永逸。但是有一个致命缺点,就是数据会一直保存在宿主机的磁盘上,因此你需要自己做管理,否则就相当于内存泄漏一样。

存储卷的分类

存储卷的英文名为type of count 直译就是挂载的类型,因此他是有分类的。

可分为三种,volume docker 管理卷,bind mount 绑定数据卷,tmpfs mount 临时数据卷

volume docker 管理卷:

默认映射到宿主机的/var/lib/docker/volumes 目录 下,只需要在容器内指定容器的挂载点是什么,而被绑定宿主机下的那个目录,是由 容器引擎 daemon 自行创建一个空的目录,或者使用一个已经存在的目录,与存储卷 建立存储关系,这种方式极大解脱用户在使用卷时的耦合关系,缺陷是用户无法指定 那些使用目录,临时存储比较适合;

bind mount 绑定数据卷(使用最多):

映射到宿主机指定路径下,在宿主机上的路径要人工的 指定一个特定的路径,在容器中也需要指定一个特定的路径,两个已知的路径建立关 联关系。容器使用的目录用户来指定和创建。

tmpfs mount 临时数据卷

映射到于宿主机内存中,一旦容器停止运行,tmpfs mounts 会被移除,数据就会丢失,用于高性能的临时数据存储

存储卷指令
docker volume create
docker volume create myvoltest03

–label 指定描述信息

docker volume create --label AUTHO=QHX myvoltest04

-v指定参数创建卷

docker run -v name:directory[:options]

第一个参数:卷名称

第二个参数:卷映射到容器的目录

第三个参数:选项,如ro表示readonly

示例:

docker run -d --name myvolnginx -v volnginx1:/usr/share/nginx/html nginx
docker run -d --name myvolnginx2 -v volnginx2:/usr/share/nginx/html/:ro nginx

–mount 指定参数创建卷

--mount '<key>=<value>,<key>=<value>'

关键参数:

type : 类型支持所有的存储卷

src : 对于命名卷是卷的名称,对于匿名卷,可省略

dst : 文件或目录挂载在容器的路径

ro : 只读方式挂载

示例:

docker run -d --name myvolnginx3 --mount "src=volnginx3,dst=/usr/share/nginx/html" nginx
docker volume inspect
docker volume inspect myvoltest03

docker volume inspect 可以详细查看每个卷的信息,可以指定多个卷,而docker volume ls则是主要查看所有卷的名字

docker volume ls
docker volume ls -f label=AUTHOR

-f 指定过滤 label=AUTHOR 是要过滤的内容

docker volume ls --format json

–format json 指定json格式返回

docker volume rm

可以删除多个卷,会相应删除所创建的管理卷

docker volume rm myvoltest05 myvoltest06

-f 选项 强制删除

docker volume prune
docker volume prune

删除不使用的匿名卷,会进行提示,使用-f 选项则不会提示是否删除

docker卷的生命周期独立于容器,删除需要使用docker volume rm指令;docker 卷共享数据,多个容器绑定一个卷,数据是共享的,改变宿主机,还是改变三个容器的任意映射的目录,三个容器都会相应改变。

创建bind卷

使用-v参数

docker run -d --name mynginx1 -p 8080:80 -v /data/maxqhx/testbind:/usr/share/nginx/html nginx

需要在宿主机手动创建目录来用于映射容器的数据,这种方式创建的docker卷,不会自动映射里面的文件,需要你手动映射

–mount参数创建

docker run -d --name mynginx2 --mount type=bind,src=/data/maxqhx/testmindbind,dst=/usr/share/nginx/html nginx

必须指定type类型为bind才行,默认是volume,如果不指定则会报错

创建tmpfs卷

–tmpfs指定参数创建

docker run -d --name mynginx3 --tmpfs /test1 nginx

其中/test1 路径不是宿主机目录 而是要指定容器的目录,因为是内存,所以宿主机不会指定目录

–mount指定参数创建

docker run -d --name mynginx4 --mount type=tmpfs,dst=/test1 nginx

type类型必须指定,否则报错;src不用写,可选参数tmpfs-size指定大小

无论是–mount还是–tmpfs创建临时卷,如果指定的目录是容器中有内容的目录,容器中原有的内容会被覆盖,直接变空

临时卷里创建的内容,即使是宿主机使用find也会查不到,具有隐蔽性

存储卷的常见问题

什么时候用 Volume,什么时候用 bind、tmpfs?

volume: volume是docker的宿主机文件系统一部分,用于不需要规划具体目录的场景

bind: bind mount完全依赖于主机的目录结构和操作系统,用于目录需要提前规划,比如 mysql 的目录需要个空间大的,其他服务有不占用的时候,用 volume 就不太合 适了

tmpfs:用于敏感文件存储,文件不想存储的宿主机和容器的可写层之中

扩展思考

跨主机使用:

docker 存储卷是使用其所在的宿主机上的本地文件系统目录,也就是宿主机有一块磁 盘,这块磁盘并没有共享给其他的 docker 主机,容器在这宿主机上停止或删除,是可 以重新再创建的,但是不能调度到其他的主机上,这也是 docker 本身没有解决的问题, 所以 docker 存储卷默认就是 docker 所在主机的本地,但是自己搭建一个共享的 NFS 来存储 docker 存储的数据,也可以实现,但是这个过程强依赖于运维人员的能力。 所以未来应用的存储和数据往往分离,越来越多的分布式存储方案出现,如 s3 系列, nfs 等。

启动参数未知:

容器有一个问题,一般与进程的启动不太一样,就是容器启动时选项比较多,如果下 次再启动时,很容器会忘记它启动时的选项,所以最好有一个文件来保存容器的启动, 这就是容器编排工具的作用。 一般情况下,是使用命令来启动操作 docker,但是可以通过文件来读,也就读文件来启 动,读所需要的存储卷等,但是它也只是操作一个容器,如果要几十上百个容器操作, 就需要专业的容器编排工具 这种一般像开源的 k8s,各个云厂商也有自己的企业版编排软件。

复杂场景仍然需要运维:

对于有状态要持久的集群化组件,如 mysql 的主从。部署维护一个 Mysql 主从需要运 维知识、经验整合进去才能实现所谓的部署,扩展或缩容,出现问题后修复,必须要 了解集群的规模有多大,有多少个主节点,有多少个从节点,主节点上有多少个库, 这些都要一清二楚,才能修复故障,这些就强依赖于运维经验 这种复杂的场景往往还是需要人力,很难有完美的工具出现。

Docker network

docker 网络架构简介

Docker 容器网络是为应用程序所创造的虚拟环境的一部分,它能让应用从宿主机操作 系统的网络环境中独立出来,形成容器自有的网络设备、IP 协议栈、端口套接字、IP 路由表、防火墙等等与网络相关的模块。 Docker 为实现容器网络,主要采用的架构由三部分组成:CNM、Libnetwork 和驱动。

CNM

Sandbox:提供了容器的虚拟网络栈,也即端口、套接字、IP 路由表、防火墙、 DNS 配置等内容。主要用于隔离容器网络与宿主机网络,形成了完全独立的容器网络 环境。

Network:Docker 内部的虚拟子网,使得网络内的参与者能够进行通讯。

Endpoint:就是虚拟网络的接口,就像普通网络接口一样,Endpoint 的主要职责 是负责创建连接。Endpoint 类似于常见的网络适配器,那也就意味着一个 Endpoint 只 能接入某一个网络, 当容器需要接入到多个网络,就需要多个 Endpoint。

Libnetwork

Libnetwork 是 CNM 的一个标准实现。Libnetwork 是开源库,采用 Go 语言编写(跨 平台的),也是 Docker 所使用的库,Docker 网络架构的核心代码都在这个库中。 Libnetwork 实现了 CNM 中定义的全部三个组件,此外它还实现了本地服务发现、基 于 Ingress 的容器负载均衡,以及网络控制层和管理层等功能。

驱动

驱动主要负责实现数据层相关内容,例如网络的连通性和隔离性是由驱动来处理的。 驱动通过实现特定网络类型的方式扩展了 Docker 网络栈,例如桥接网络和覆盖网络。 Docker 内置了若干驱动,通常被称作原生驱动或者本地驱动。例如 Bridge Driver、 Host Driver、Overlay Driver、MacVLan Driver、IPVLan Driver、None Driver 等 等。每个驱动负责创建其上所有网络资源的创建和管理。

常见网络类型

bridge 网络

bridge 驱动会在 Docker 管理的主机上创建一个 Linux 网桥。默认情况下,网桥上的容器可以相互通信。也可以通过 bridge 驱动程序配置,实现对外部容器的访问。 Docker容器的默认网络驱动是bridge。当我们需要多个容器在同一个 Docker 主机上通信时,桥接网络是一个很好的选择。

host 网络

对于独立容器,移除容器和 Docker 主机之间的网络隔离,并直接使用主机的网络。 当网络堆栈不应该与 Docker 主机隔离,但是希望容器的其他资源被隔离时,主机网络 是最佳选择。

container 网络

这个模式指定新创建的容器和引进存在的一个容器共享一个网络 ,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 ip,而是和一个指定的容器 共享 ip,端口等,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离 的。两个容器的进程可以通过 lo 网卡设备通信

none 网络

Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任 何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。容器完全网络 隔离。

overlay 网络

借助 Docker 集群模块 Docker Swarm 搭建的跨 Docker Daemon 网络。将多个 Docker 守护进程连接在一起,使集群服务能够相互通信。当我们需要运行在不同 Docker 主机上的容器进行通信时,或者当多个应用程序使用集群服务协同工作时,覆 盖网络是最佳选择。

docker 网络管理命令
命令 别名 功能
docker network create 创建网络
docker network connect 连接网络
docker network disconnect 断开网络
docker network ls docker network list 列出网络
docker network prune 删除不使用的网络
docker network inspect 查看网络详情
docker network rm docker network remove 删除 1 个或者多个网络
网络详解
docker Bridge 网络

Docker Bridge 网络采用内置的 bridge 驱动,bridge 驱动底层采用的是 Linux 内核中 Linux bridge 技术。就网络而言,bridge 网络是在网络段之间转发流量的链路层设备, 而网桥可以是在主机内核中运行的硬件设备或软件设备;就 Docker 而言,桥接网络使 用软件网桥 docker0,它允许连接到同一网桥网络的容器进行通信,同时提供与未连 接到该网桥网络容器的隔离。

默认情况下,创建的容器在没有使用–network 参数指定要加入的 docker 网络时, 默认都是加入 Docker 默认的单机桥接网络
在这里插入图片描述

默认的 bridge 网络会被映射到内核中为 docker0 的网桥上。 Docker 默认的 bridge 网络和 Linux 内核中的 docker0 网桥是一一对应的关系。 bridge 是 Docker 对网络的命名,而 docker0 是内核中网桥的名字。

对于自定义的bridge网络,可以使用容器名作为DNS服务名去进行网络通信,而默认的bridge网络是不支持DNS服务的

docker Host 网络

Docker 容器运行默认都会分配独立的 Network Namespace 隔离子系统, 但是如果基 于 host 网络模式,容器将不会获得一个独立的 Network Namespace,而是和宿主机 共用同一个 Network Namespace,容器将不会虚拟出自己的网卡,IP 等,而是直接使 用宿主机的 IP 和端口。

连接到 host 网络的容器共享宿主机的网络栈,容器的网络配置与宿主机完全一样。我 们可以通过 --network=host 指定使用 host 网络。

docker Container 网络

Docker compose

是什么

docker-compose 是 Docker 官方的开源项目,使用 python 编写,实现上调用了 Docker 服务的 API 进行容器管理及编排,其官方定义为定义和运行多个 Docker 容器 比特就业课 的应用。

docker-compose 中有两个非常重要的概念:

服务 ( service ):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。

项目( project ):由一组关联的应用容器组成的一个完整业务单元,在 dockercompose.yml 文件中定义, 整个 docker-compose.yml 定义一个项目。

Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周 期管理。

为什么要 Docker Compose

Docker 是一个轻量化的应用程序,Docker 官方推荐每个 Docker 容器中只运行一 个进程。

如果一个应用需要涉及到 MySQL、nginx 等环境, 那么我们需要分别为应用、数 据库和 nginx 创建单独的 docker 容器,然后分别启动容器。

想象一下,当我们构建好 Docker 之后,每次启动应用,都至少需要 docker run 三次, 或者写一些脚本来实现, 这样会比较繁琐。

另外,这些 docker 容器都是分散独立的,也不方便镜像管理。那既然这些 docker 容器 都是为了同一个应用服务,我们就应该把它们放到一起,这就引出了 docker compose 来解决这类型的问题。

文件常见指令

默认情况下docker compose 会把最近一级的父目录当作项目名

image

docker-compose.yml 内容:

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0

然后执行

docker compose up -d

docker compose 就会自动帮你创建项目,并创建和启动容器

执行

docker compose down

docker compose 就会自动帮你删除项目,并删除容器

docker compose 会自动帮你创建单独的网络,默认是桥接网络。可以使用docker compose ps 查看自己的创建的容器。注意docker compose up -d 和 docker compose down 需要在项目的目录里执行

command

docker-compose.yml 内容:

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    command: ["tail","-f","/etc/hosts"]

tail:查看文件末尾内容
-f:持续监听,文件有内容就实时显示
/etc/hosts:Linux 系统里的**主机名映射文件

总结起来就是,实时监听 /etc/hosts 文件的末尾,一直保持运行,不自动结束

entrypoint

docker-compose.yml 内容:

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    entrypoint:
      - tail
      - -f
      - /etc/os-release

entrypoint和command可以简单理解认为就是启动指令,一般是command使用entrypoint的选项

environment

docker-compose.yml 内容:

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    environment:
      TEST: 1

配置环境变量,TEST值为1

networks

docker-compose.yml 内容:

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    networks:
      - mywebnet1
      - mywebnet2

networks:
  mywebnet1:
  mywebnet2:

配置多个网络,默认是桥接网络

volumes

docker-compose.yml 内容:

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    volumes:
      - /data/maxqhx/vol1:/usr/share/nginx/html/

配置存储卷,这是一种简写方式

ports

docker-compose.yml 内容:

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    ports:
      - 8080:80

配置端口

expose

暴露端口,但不映射到宿主机,只被连接的服务访问,相同网络的容器可以访问。

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    expose:
      - 80

depends_on

设置依赖关系。

docker compose up :以依赖性顺序启动服务。在以下示例中,先启动 db 和 redis ,才会启动 web。

docker compose up SERVICE :自动包含 SERVICE 的依赖项。在以下示例中, docker compose up web 还将创建并启动 db 和 redis。

docker compose stop :按依赖关系顺序停止服务。在以下示例中,web 在 db 和 redis 之前停止

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    depends_on:
      mysql:
        condition: service_healthy
  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 123456
    healthcheck:
      test: mysql -u root -p123456 -e "select 1;"
      interval: 10s
      timeout: 5s
      retries: 10

env_file

从文件添加环境变量。可以是单个值或列表的多个值。

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    env_file:
      - ./commenv
      - ./webenv
Docker Compose 命令清单

如下命令不愿单独学习,和容器命令差不多

命令 功能
docker compose build 构建服务
docker compose config 规范的格式来显示服务配置
docker compose cp 在本地系统和服务容器直接拷贝文 件
docker compose create 创建服务的容器
docker compose down 停止所有容器,并删除容器
docker compose events 从服务器获取实时事件
docker compose exec 在容器中执行命令
docker compose images 列出所有容器使用的镜像
docker compose kill 强制停止服务的容器
docker compose logs 显示日志
docker compose ls 显示所有项目
docker compose pause 暂停服务
docker compose port 列出所有的端口映射
docker compose ps 该命令可以列出项目中目前的所有 容器
docker compose pull 拉取服务镜像
docker compose push 推送服务镜像
docker compose restart 重启或者重启某个服务
docker compose rm 删除服务停止的容器
docker compose run 在指定服务容器上执行相关的命令
docker compose start 启动当前停止的某个容器
docker compose stop 停止当前运行的某个容器
docker compose top 显示运行的进程
docker compose unpause 恢复服务
docker compose up up 命令会构建,(重新)创建,启 动,链接一个服务相关的容器。默 认情况下如果容器已经存在,将会 停止并尝试重新创建他们。并使用 之前挂载的卷。–no-recreate 参数 可以让容器不被停止或者重新创 建,-d 表示后台运行
docker compose version 查看版本
docker compose 命令通用选项
通用选项

-f 指定配置文件 -p 指定项目名 不在使用默认的父级目录,而是自己手动指定,这样创建的容器,使用查看的命令也需要在compose 后跟着选项,指定项目名,因为docker compose本质是查找最近一级的父目录的配置文件,如果你没有这个配置文件,那就会报错。

示例:

docker compose -f ./prj9/docker-compose.txt -p prj92 up -d

手动指定配置文件和项目名,创建容器

示例:

docker compose -p prj92  ps

手动指定项目名,使用当前最近父级目录的配置文件。创建的容器,依然拥有独立的网络,而不是复用别人的网络

up命令

该命令的作用十分强大,它会尝试自动完成包括构建镜像、(重新)创建服务、启动服 务并关联服务相关容器的一系列操作,可以直接通过该命令来启动一个项目。

-d 在后台运行服务容器, 推荐在生产环境下使用该选项

–force-recreate 强制重新创建容器,不能与 --no-recreate 同时使用

–no-recreate 如果容器已经存在了,则不重新创建,不能与 --forcerecreate 同时使用

示例:

docker compose up

前台启动容器

示例:

docker compose up -d

后台启动容器

示例:

docker compose up -d --force-recreate

强制重新启动容器

示例:

docker compose up -d --no-recreate

如果容器存在,则不重启

down命令

停止所有容器,并删除容器和网络

-v, --volumes 删除容器同时删除目录映射

示例:

docker compose down -v
run命令

该命令可以在指定服务容器上执行相关的命令,官方推荐执行一次性的命令

示例:

docker compose  run --name mynginx1 web curl www.baidu.com
实战操作案例

配置一个拓扑,web(nginx镜像)服务依赖redis和mysql,web服务需要配置端口、网络、存储卷

docker-compose.yml 内容:

version: "5.1"
services: 
  web: 
    image: nginx:1.21.0
    environment:
      TEST: 5
    ports:
      - 8081:80
    networks:
      - mytestnetwork
    volumes:
      - ./nginxhome:/usr/share/nginx/html/
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
  mysql:
    image: mysql:5.7
    networks:
      - mytestnetwork
    volumes:
      - ./mysqllib:/var/lib/mysql/
    environment:
      MYSQL_ROOT_PASSWORD: 123456
    healthcheck:
      test: mysql -u root -p123456 -e "select 1;"
      interval: 10s
      timeout: 5s
      retries: 10
  redis:
    image: redis:7.0
    networks:
      - mytestnetwork
    healthcheck:
      test: redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10
networks:
  mytestnetwork:
综合案例1 docker compose 部署SpringBoot项目
  1. 数据库初始化脚本(需要实时维护)
drop database if exists test;
CREATE DATABASE `test` DEFAULT CHARACTER SET utf8mb4 ;
use `test`;
CREATE TABLE `users` (
 `sno` int(11) DEFAULT NULL,
`sname` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO users (sno,sname) VALUES
 (1,'pony'),
(2,'maxhou');
  1. 简单springBoot项目

    本地测试好之后,上传到你的linux机器上

  2. 配置文件编写

    version: "5.1"
    services: 
      web: 
        image: nginx:1.21.0
        environment:
          TEST: 5
        volumes:
          - ./nginxconf/:/etc/nginx/conf.d
        depends_on:
          backend:
            condition: service_started
        ports:
          - 8082:80
      backend:
        image: java:8
        command: java -jar ./app/testmymysql-0.0.1-SNAPSHOT.jar
        volumes:
          - ./app:/app/
        depends_on:
          mysql:
            condition: service_healthy
      mysql:
        image: mysql:5.7
        environment:
          MYSQL_ROOT_PASSWORD: 157211
        volumes:
          - ./mysql/var/lib:/var/lib/mysql
          - ./mysql/initdb/:/docker-entrypoint-initdb.d/
        healthcheck:
          test: mysql -u root -p157211 -e "select 1;"
          interval: 10s
          timeout: 5s
          retries: 10
    
    
综合案例2 docker compose 部署 WordPress
什么是WordPress

WordPress 是使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据 库的服务器上架设属于自己的网站。也可以把 WordPress 当作一个内容管理系统 (CMS)来使用。

WordPress 是一款个人博客系统,并逐步演化成一款内容管理系统软件,它是使用 PHP 语言和 MySQL 数据库开发的,用户可以在支持 PHP 和 MySQL 数据库的服务器 上使用自己的博客。

WordPress 有许多第三方开发的免费模板,安装方式简单易用。不过要做一个自己的 模板,则需要你有一定的专业知识。比如你至少要懂的标准通用标记语言下的一个应 用 HTML 代码、CSS、PHP 等相关知识。

WordPress 官方支持中文版,同时有爱好者开发的第三方中文语言包,如 wopus 中文 语言包。WordPress 拥有成千上万个各式插件和不计其数的主题模板样式。

部署 WordPress

docker-compose.yml 内容:

version: "3.8"
services:
  wordpress:
    image: wordpress
    restart: always
    depends_on:
      db:
        condition: service_healthy
    ports:
      - 8083:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: mywordpressuser
      WORDPRESS_DB_PASSWORD: mywordpresspass
      WORDPRESS_DB_NAME: wordpress
    volumes: 
      - ./wordpress:/var/www/html
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wordpress
      MYSQL_USER: mywordpressuser
      MYSQL_PASSWORD: mywordpresspass
    volumes:
      - ./mysqlvarlib:/var/lib/mysql
    healthcheck:
      test: mysql -u root -proot -e "select 1;"
      interval: 10s
      timeout: 5s
      retries: 10

然后首次访问该网站,需要填写基本信息进行登录,然后就可以进入后台。

制作镜像
Docker Commit

创建并启动一个容器

docker run -it --name testmycommitimgcpp centos:7 bash

配置gcc软件源(中科大)

sed -i.bak \
  -e 's|^mirrorlist=|#mirrorlist=|g' \
  -e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.ustc.edu.cn/centos-vault/centos|g' \
  /etc/yum.repos.d/CentOS-Base.repo
yum makecache
gcc -v
yum install gcc

创建并进入/src/目录,然后创建并打开demo.c文件

vi demo.c

demo.c 内容:

#include "stdio.h"
int main()
{
	printf("hello world\n");
	return 0;
}
gcc demo.c -o demo

退出容器,执行如下命令

docker commit testmycommitimgcpp testmycommitimgcpp:v1.0

检查镜像

docker images testmycommitimgcpp

测试镜像

docker run -it testmycommitimgcpp:v1.0 /src/demo
DockerFile
Dockerfile 是什么

镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层 修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,这个 脚本就是 Dockerfile。 Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令 构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

Dockerfile 格式
# Comment
INSTRUCTION arguments

该指令不区分大小写。然而,约定是它们是大写的,以便更容易地将它们与参数区分 开来。

Docker 按顺序运行指令 Dockerfile 比特就业课 Docker 将以开头的行视为#注释,行中其他任何地方的标记#都被视为参数。

为什么需要 Dockerfile

可以按照需求自定义镜像

很方便的自动化构建,重复执行

维护修改方便,不再是黑箱操作

更加标准化,体积可以做的更小

FROM指令

Docerfile内容:

简单创建一个ubuntu镜像

FROM   ubuntu:22.04

创建一个系统架构为arm64的ubuntu镜像

FROM --platform=linux/arm64  ubuntu:18.04

x86机器上是不能直接运行arm64架构的镜像的,需要使用虚拟化技术,感兴趣的可以自行了解

as NAME 指定多个镜像

FROM  ubuntu:22.04 as buildstage1

FROM  ubuntu:18.04 as buildstage2

使用以下指令 可以实现一个文件创建多个镜像

docker build -t myweb:0.3  --target buildstage1 .
docker build -t myweb:0.4  --target buildstage2 .

-t 指定镜像名字

MAINTAINER指令

指定作者信息,该功能已经废弃,由 label 替代

MAINTAINER qhx
LABEL指令

指定镜像元数据,使用kv形式

LABEL version="0.6" desc="create by qhx" author="qhx"
COPY指令

从宿主机拷贝文件到镜像中

COPY  ./index.html /data/web/html/

拷贝宿主机当前目录的index.html到镜像的/data/web/html/目录中,如果该目录不存在,会自动创建

–chown 指定用户和用户组

FROM  ubuntu:22.04 as buildstage1
LABEL version="0.6" desc="create by qhx" author="qhx"
COPY --chown=news:news ./index.html /data/web/html/
ENV指令

用于为镜像定义所需的环境变量,并可被 Dockerfile 文件中位于其后的其它指 令(如 ENV、ADD、COPY 等)所调用。

定义形式为键值对

ENV MYTEST1=1 MYTEST2=2
WORKDIR指令

为 Dockerfile 中所有的 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指定设 定工作目录

WORKDIR /data/src

如果指定的工作目录不存在,WORKDIR指令会自动创建

ADD指令

ADD 指令类似于 COPY 指令,ADD 支持使用 TAR 文件和 URL 路径,会自动 完成解压和下载。

当从网址下载一个tar包,ADD指令不会解压;当从宿主机把tar包拷贝到镜像中,会自动解压。

ADD ./nginx-1.30.2.tar.gz .

ADD指令与COPY指令区别:

ADD指令会自动解压,从网址中下载文件。而COPY指令只能拷贝文件,不能解压和从网址下载文件,强行使用网址,会直接报错

RUN指令

用于指定 docker build 过程中运行的程序,其可以是任何命令

shell 形式

RUN cd /data/src && tar zxvf nginx-1.30.2.tar.gz

exec 形式

RUN ["sh","-c","mkdir -p /data/src3 && cd /data/src3 && touch new.txt"]

其中前两个参数必须写,sh 和 -c

CMD指令

类似于 RUN 指令,CMD 指令也可用于运行任何命令或应用程序,不过,二 者的运行时间点不同

RUN 指令运行于映像文件构建过程中,而 CMD 指令运行于基于 Dockerfile 构建出的新映像文件启动一个容器时 比特就业课

CMD 指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结 束后,容器也将终止;不过,CMD 指定的命令其可以被 docker run 的命令行选 项所覆盖

在 Dockerfile 中可以存在多个 CMD 指令,但仅最后一个会生效

CMD指令可以被前台bash的手动指令覆盖;有exec和shell两种语法形式

JSON形式:

CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
EXPOSE指令

用于为容器声明打开指定要监听的端口以实现与外部通信

该 EXPOSE 指令实际上并不发布端口。它充当构建图像的人和运行容器的人之 间的一种文档,关于要发布哪些端口。要在运行容器时实际发布端口,使用-p 参 数发布和映射一个或多个端口,或者使用-Pflag 发布所有暴露的端口并将它们映 射宿主机端口。

EXPOSE 80/tcp
ENTRYPOINT

用于指定容器的启动入口,和CMD指令差不多,都有exec和shell两种语法形式,该指令会把前台bash的指令当作参数上传,不会覆盖,除非使用 --entrypoint string 选项指定

示例:

docker run -it --entrypoint echo myweb:1.9 "hello bit"
ENTRYPOINT ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
ARG指令

ARG指令用于定义变量,与ENV指令区别是只能在dockerfile中生效使用,容器中根本不存在,并且可以在前台bash中赋值;ENV 和 ARG 同时存在,ENV 会覆盖 ARG。

Dockerfile 可以包含一个或多个 ARG 指令

ARG SYSVERSION=22.04
FROM  ubuntu:${SYSVERSION} as buildstage1
VOLUME指令
VOLUME ["/data1"]
SHELL指令
FROM ubuntu:20.04
RUN ls -l > /test1.txt
SHELL ["/bin/bash","-cvx"]
RUN ls -l > /test2.txt

-c执行命令,-v打印原始命令,-x 打印执行细节(变量展开后的命令)

docker build -t shell:v0.1 --no-cache --progress=plain .

–no-cache 不使用缓存

–progress=plain 打印步骤

USER指令

用于指定运行 image 时的或运行 Dockerfile 中任何 RUN、CMD 或 ENTRYPOINT 指令定的程序时的用户名或 UID。默认情况下,container 的运行身份为 root 用户

FROM ubuntu:22.04 as buildbase
RUN groupadd nginx
RUN useradd nginx -g nginx
USER nginx:nginx
RUN whoami > /tmp/user1.txt
USER root:root
RUN groupadd mysql
RUN useradd mysql -g mysql
USER mysql:mysql
RUN whoami > /tmp/user2.txt
HEALTHCHECK

HEALTHCHECK 指令告诉 Docker 如何测试容器以检查它是否仍在工作。

即使服务器进程仍在运行,这也可以检测出陷入无限循环且无法处理新连接 的 Web 服务器等情况。

HEALTHCHECK [OPTIONS] CMD command

OPTIONS 选项有:

–interval=DURATION (default: 30s):每隔多长时间探测一次,默认 30 秒

– timeout= DURATION (default: 30s):服务响应超时时长,默认 30 秒

–start-period= DURATION (default: 0s):服务启动多久后开始探测,默 认 0 秒

–retries=N (default: 3):认为检测失败几次为宕机,默认 3 次

返回值

0:容器成功是健康的,随时可以使用

1:不健康的容器无法正常工作

2:保留不使用此退出代码

示例1:

FROM nginx:1.24.0
HEALTHCHECK --interval=5s --timeout=3s \
CMD curl -f http://localhost/ || exit 1

每隔5s发一次请求,超时时间为3s。默认监听80端口

示例2:

FROM nginx:1.24.0
HEALTHCHECK --interval=5s --timeout=3s \
CMD curl -f http://localhost:8088/ || exit 1

监听8088端口

ONBUILD

用于在 Dockerfile 中定义一个触发器

以该 Dockerfile 中的作为基础镜像由 FROM 指令在 build 过程中被执行时, 将会“触发”创建其 base image 的 Dockerfile 文件中的 ONBUILD 指令定义的触 发器

基础镜像:

ONBUILD RUN echo "create by byte version 1.0 " > /tmp/version.txt
docker build -t myweb:2.2 .

新镜像:

FROM myweb:2.2
RUN echo "hello world" > /test1.txt
docker build -t ob:v0.1 .

打印信息:

[+] Building 0.9s (7/7) FINISHED                                                                                                              docker:default
 => [internal] load build definition from Dockerfile                                                                                                    0.0s
 => => transferring dockerfile: 88B                                                                                                                     0.0s
 => [internal] load metadata for docker.io/library/myweb:2.2                                                                                            0.0s
 => [internal] load .dockerignore                                                                                                                       0.0s
 => => transferring context: 2B                                                                                                                         0.0s
 => [1/2] FROM docker.io/library/myweb:2.2                                                                                                              0.1s
 => [2/3] ONBUILD RUN echo "create by byte version 1.0 " > /tmp/version.txt                                                                             0.3s
 => [3/3] RUN echo "hello world" > /test1.txt                                                                                                           0.3s
 => exporting to image                                                                                                                                  0.1s
 => => exporting layers                                                                                                                                 0.0s
 => => writing image sha256:7fec92e496a52dbc5de7cd4aeafe7c66a0ff607e29d6b2531da2a796a5406906                                                            0.0s
 => => naming to docker.io/library/ob:v0.1    
STOPSIGNAL

STOPSIGNAL 指令设置将发送到容器的系统调用信号。

此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如 9, 或者 SIGNAME 格式的信号名,例如 SIGKILL。

FROM nginx:1.24.0
STOPSIGNAL 9
docker build

docker build 命令用于使用 Dockerfile 创建镜像。

docker build [OPTIONS] PATH | URL | -

关键参数

–build-arg=[] :设置镜像创建时的变量;

-f :指定要使用的 Dockerfile 路径; 比特就业课

–label=[] :设置镜像使用的元数据;

–no-cache :创建镜像的过程不使用缓存;

–pull :尝试去更新镜像的新版本;

–quiet, -q :安静模式,成功后只输出镜像 ID;

–tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构 建中为一个镜像设置多个标签。

–network: 默认 default。在构建期间设置 RUN 指令的网络模式

示例1:

docker build -t build:v0.1 /data/maxqhx/build/

示例2:

docker build -t build:v0.2 http://127.0.0.1/myDockerfile.txt

示例3:

docker build -t build:v0.3 - < Dockerfile

选项参数:

Dockerfile:

FROM ubuntu:22.04
RUN echo "version 1.0" > /version.txt
ARG NGINX_VERSION=1.30.2
ADD https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz .

–build-arg

docker build -t build:0.5 --build-arg NGINX_VERSION=1.24.0 .

-f

docker build -t build:v0.6 -f ./Dockerfile2  .

–label

docker build -t build:v0.7 --label autho=qhx .

–no-cache

docker build -t build:v0.8 --no-cache .

–pull

docker build -t build:v1.0 --pull --no-cache  .

–quiet, -q

docker build -t build:v1.1 -q  .

–network

docker build -t build:v1.2 --network host  .

docker buildx 了解 todo

Dockerfile 实战

C++ HelloWorld 镜像制作
FROM centos:7
RUN sed -i.bak \
  -e 's|^mirrorlist=|#mirrorlist=|g' \
  -e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.ustc.edu.cn/centos-vault/centos|g' \
  /etc/yum.repos.d/CentOS-Base.repo
RUN yum makecache
WORKDIR /src
COPY ./demo.c .
RUN yum install gcc -y
RUN gcc demo.c -o demo && \
rm -f demo.c && \
yum remove -y gcc
CMD ["/src/demo"]
docker run --rm -it cpp:v0.1
Springboot 镜像制作
FROM openjdk:8
COPY ./dockerDemo-0.0.1-SNAPSHOT.jar /app.jar
CMD ["java","-jar","/app.jar"]

docker run -d --name springboot1 -p 8082:8080 springboot:v0.1
CMD与ENTRYPOINT区别

CMD指令与ENTRYPOINT指令都有shell和exec两种形式,那这两种形式有什么区别呢?

shell形式下,你的容器是sh(PID=1)的一个子进程,sh相当于一个中间人,一个秘书。

exec形式下,你的容器就是主程序,没有中间人,你直接执行

所以更推荐,exec形式

ENTRYPOINT覆盖:

docker run --rm -it --entrypoint "/bin/sh" cmd:v0.2 -c "echo hello byte2!"
部分 含义
/bin/sh Shell 解释器程序(类似 Windows 的 cmd.exe
-c 选项(c = command),意思是"把下一个参数作为命令来执行"
"echo hello byte2!" 要执行的命令字符串

混合模式使用:

CMD写参数,ENTRYPOINT写命令

FROM ubuntu:22.04
RUN apt-get update -y && apt install -y iputils-ping
ENTRYPOINT ["ping","-c","3"]
CMD ["127.0.0.1"]
docker run --rm -it cmd:v0.6

覆盖CMD参数,ping 百度网站

docker run --rm -it cmd:v0.6 www.baidu.com
.dockerignore 文件

和gitte的ignore文件一样,用来忽略某些文件的上传。

只需要在Dockerfile坐在的目录,创建一个.dockerignore文件

Dockerfile内容:

FROM centos:7
COPY ./* /

示例:

*.txt

镜像就会自动屏蔽.txt的文件上传

多阶段构建

dockerfile内容:

FROM centos:7 as buildstage1
RUN sed -i.bak \
  -e 's|^mirrorlist=|#mirrorlist=|g' \
  -e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.ustc.edu.cn/centos-vault/centos|g' \
  /etc/yum.repos.d/CentOS-Base.repo
RUN yum makecache
WORKDIR /src
COPY ./demo.c .
RUN yum install gcc -y
RUN gcc demo.c -o demo && \
rm -f demo.c && \
yum remove -y gcc
CMD ["/src/demo"]

FROM centos
COPY --from=buildstage1 /src/demo /src/
CMD ["/src/demo"]
合理使用缓存

尽量把安装编译的指令集中在一起,优化指令,合理使用缓存加速开发。

但是我测试发现差异不是很大,可能和文件大小有关系,当文件大到一定阈值,这回非常明显吧。

Dockerfile搭建mysql主从集群
docker compose build 构建参数
services:
 # 格式一
 frontend:
 image: awesome/webapp
 build: ./webapp
 # 格式二
 backend:
 image: awesome/database
 build:
 #构建上下文目录
 context: ./backend
 dockerfile: ./backend.Dockerfile

docker-compose.yml内容:

version: "3.8"
services:
   mynginx:
     image: mytestimagebuild:v1.0
     build: ./mynginx

   mynginx2:
     image: mytestimagebuild:v2.0
     build:
       context: ./mynginx2
       dockerfile: dockerfile2
主从同步的架构图

在主从复制的过程中,会基于三个线程来操作,一个是 binlog dump 线程,位于 master 节点上,另外两个线程分别是 I/O 线程和 SQL 线程,它们都分别位于 slave 节 点上。

当 master 节点接收到一个写请求时,这个写请求可能是增删改操作,此时会把写 请求的更新操作都记录到 binlog 日志中。

master 节点会把数据复制给 slave 节点,如图中的 slave01 节点和 slave02 节点, 这个过程,首先得要每个 slave 节点连接到 master 节点上,当 slave 节点连接到 master 节点上时,master 节点会为每一个 slave 节点分别创建一个 binlog dump 线程, 用于向各个 slave 节点发送 binlog 日志。

binlog dump 线程会读取 master 节点上的 binlog 日志,然后将 binlog 日志发送给 slave 节点上的 I/O 线程。当主库读取事件的时候,会在 Binglog 上加锁,读取完成之 后,再将锁释放掉。

slave 节点上的 I/O 线程接收到 binlog 日志后,会将 binlog 日志先写入到本地的 relaylog 中,relaylog 中就保存了 binlog 日志。

slave 节点上的 SQL 线程,会来读取 relaylog 中的 binlog 日志,将其解析成具体 的增删改操作,把这些在 master 节点上进行过的操作,重新在 slave 节点上也重做一 遍,达到数据还原的效果,这样就可以保证 master 节点和 slave 节点的数据一致性了。 主从同步的数据内容其实是二进制日志(Binlog),它虽然叫二进制日志,实际上存储 的是一个又一个的事件(Event),这些事件分别对应着数据库的更新操作,比如 INSERT、UPDATE、DELETE 等。

什么是 binlog

主库每提交一次事务,都会把数据变更,记录到一个二进制文件中,这个二进制文件 就叫 binlog。

需注意:只有写操作才会记录至 binlog,只读操作是不会的(如 select、 show 语句)。 Bin Log 共有三种日志格式,可以 binlog_format 配置参数指定。

参数 值 含义
Stat eme nt 记录原始 SQL 语句,会导致更新时间与原库不一致。 比如 update_time=now()
Row 记录每行数据的变化,保证了数据与原库一致,缺点是数据量较大。
Mixe d Mixe d Statement 和 Row 的混合模式,默认采用 Statement 模式,涉及日期、函 数相关的时候采用 Row 模式,既减少了数据量,又保证了数据一致性。
实战搭建

/data/maxqhx/mydockerfile/mysqlcluster/docker-compose.yml

version: "3"
services:
  mysql-master:
    build:
      context: ./
      dockerfile: ./master/Dockerfile-master
    image: mysqlmaster:v1.0
    restart: always
    container_name: mysql-master
    volumes:
      - ./mastervarlib:/var/lib/mysql
    ports:
      - "9306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
    privileged: true
    command:
      - --server-id=1
      - --log-bin=master-bin
      - --binlog-ignore-db=mysql
      - --binlog_cache_size=256M
      - --binlog_format=mixed
      - --lower_case_table_names=1
      - --character-set-server=utf8
      - --collation-server=utf8_general_ci
    networks:
      - mysql-cluster

  mysql-slave:
    build:
      context: ./
      dockerfile: ./slave/Dockerfile-slave
    image: mysqlslave:v1.0
    restart: always
    container_name: mysql-slave
    volumes:
      - ./slavevarlib:/var/lib/mysql
    ports:
      - "9307:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
    privileged: true
    command:
      - --server-id=2
      - --relay-log=slave-relay-bin
      - --read-only=1
      - --log-slave-updates=1
      - --lower_case_table_names=1
      - --character-set-server=utf8
      - --collation-server=utf8_general_ci
    depends_on:
      - mysql-master
    networks:
      - mysql-cluster

  mysql-slave2:
    build:
      context: ./
      dockerfile: ./slave/Dockerfile-slave
    image: mysqlslave:v1.0
    restart: always
    container_name: mysql-slave2
    volumes:
      - ./slavevarlib2:/var/lib/mysql
    ports:
      - "9308:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
    privileged: true
    command:
      - --server-id=3
      - --relay-log=slave-relay-bin
      - --read-only=1
      - --log-slave-updates=1
      - --lower_case_table_names=1
      - --character-set-server=utf8
      - --collation-server=utf8_general_ci
    depends_on:
      - mysql-master
    networks:
      - mysql-cluster

networks:
  mysql-cluster:
    driver: bridge

/data/maxqhx/mydockerfile/mysqlcluster/master/Dockerfile-master

FROM mysql:5.7
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY ./master/master.sql /docker-entrypoint-initdb.d

/data/maxqhx/mydockerfile/mysqlcluster/master/master.sql

CREATE USER 'root'@'%' IDENTIFIED BY 'root';
grant replication slave, replication client on *.* to 'root'@'%';
flush privileges;

/data/maxqhx/mydockerfile/mysqlcluster/slave/Dockerfile-slave

FROM mysql:5.7.36
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY ./slave/slave.sql /docker-entrypoint-initdb.d

/data/maxqhx/mydockerfile/mysqlcluster/slave/slave.sql

change master to master_host='mysql-master',master_user='root',master_password='root',master_port=3306;
start slave;
Dockerfile 构建 Redis 集群
下载redis

打开 redis 官网 https://redis.io/,找到下载 https://redis.io/download/,下载 7.0.x 对应的版本的源码文件,无法下载的话使用 http://download.redis.io/releases/redis7.0.11.tar.gz 替换对应版本进行下载。

然后把tar包拷贝到/data/maxqhx/mydockerfile/myrediscluster/redis/

实战

/data/maxqhx/mydockerfile/myrediscluster/docker-compose.yml

version: "3"
services:
  redis01:
    image: myredis:v1.0
    build: ./redis
    ports:
      - 6379:6379
    container_name: redis01
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis02:
    image: myredis:v1.0
    container_name: redis02
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis03:
    image: myredis:v1.0
    container_name: redis03
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis04:
    image: myredis:v1.0
    container_name: redis04
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis05:
    image: myredis:v1.0
    container_name: redis05
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis06:
    image: myredis:v1.0
    container_name: redis06
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis07:
    image: myredis:v1.0
    container_name: redis07
    entrypoint: ["/redis/redis-cli","--cluster","create","redis01:6379","redis02:6379","redis03:6379","redis04:6379","redis05:6379","redis06:6379","--cluster-replicas","1","-a","123456","--cluster-yes"]
    depends_on:
      redis01:
        condition: service_healthy
      redis02:
        condition: service_healthy
      redis03:
        condition: service_healthy
      redis04:
        condition: service_healthy
      redis05:
        condition: service_healthy
      redis06:
        condition: service_healthy

/data/maxqhx/mydockerfile/myrediscluster/redis/redis.conf

# Redis configuration file example.
#
# Note that in order to read the configuration file, Redis must be
# started with the file path as first argument:
#
# ./redis-server /path/to/redis.conf

# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.

################################## INCLUDES ###################################

# Include one or more other config files here.  This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings.  Include files can include
# other files, so use this wisely.
#
# Note that option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# Included paths may contain wildcards. All files matching the wildcards will
# be included in alphabetical order.
# Note that if an include path contains a wildcards but no files match it when
# the server is started, the include statement will be ignored and no error will
# be emitted.  It is safe, therefore, to include wildcard files from empty
# directories.
#
# include /path/to/local.conf
# include /path/to/other.conf
# include /path/to/fragments/*.conf
#

################################## MODULES #####################################

# Load modules at startup. If the server is not able to load modules
# it will abort. It is possible to use multiple loadmodule directives.
#
# loadmodule /path/to/my_module.so
# loadmodule /path/to/other_module.so

################################## NETWORK #####################################

# By default, if no "bind" configuration directive is specified, Redis listens
# for connections from all available network interfaces on the host machine.
# It is possible to listen to just one or multiple selected interfaces using
# the "bind" configuration directive, followed by one or more IP addresses.
# Each address can be prefixed by "-", which means that redis will not fail to
# start if the address is not available. Being not available only refers to
# addresses that does not correspond to any network interface. Addresses that
# are already in use will always fail, and unsupported protocols will always BE
# silently skipped.
#
# Examples:
#
# bind 192.168.1.100 10.0.0.1     # listens on two specific IPv4 addresses
# bind 127.0.0.1 ::1              # listens on loopback IPv4 and IPv6
# bind * -::*                     # like the default, all available interfaces
#
# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the
# internet, binding to all the interfaces is dangerous and will expose the
# instance to everybody on the internet. So by default we uncomment the
# following bind directive, that will force Redis to listen only on the
# IPv4 and IPv6 (if available) loopback interface addresses (this means Redis
# will only be able to accept client connections from the same host that it is
# running on).
#
# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES
# COMMENT OUT THE FOLLOWING LINE.
#
# You will also need to set a password unless you explicitly disable protected
# mode.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bind * -::*  

# By default, outgoing connections (from replica to master, from Sentinel to
# instances, cluster bus, etc.) are not bound to a specific local address. In
# most cases, this means the operating system will handle that based on routing
# and the interface through which the connection goes out.
#
# Using bind-source-addr it is possible to configure a specific address to bind
# to, which may also affect how the connection gets routed.
#
# Example:
#
# bind-source-addr 10.0.0.1

# Protected mode is a layer of security protection, in order to avoid that
# Redis instances left open on the internet are accessed and exploited.
#
# When protected mode is on and the default user has no password, the server
# only accepts local connections from the IPv4 address (127.0.0.1), IPv6 address
# (::1) or Unix domain sockets.
#
# By default protected mode is enabled. You should disable it only if
# you are sure you want clients from other hosts to connect to Redis
# even if no authentication is configured.
protected-mode yes

# Redis uses default hardened security configuration directives to reduce the
# attack surface on innocent users. Therefore, several sensitive configuration
# directives are immutable, and some potentially-dangerous commands are blocked.
#
# Configuration directives that control files that Redis writes to (e.g., 'dir'
# and 'dbfilename') and that aren't usually modified during runtime
# are protected by making them immutable.
#
# Commands that can increase the attack surface of Redis and that aren't usually
# called by users are blocked by default.
#
# These can be exposed to either all connections or just local ones by setting
# each of the configs listed below to either of these values:
#
# no    - Block for any connection (remain immutable)
# yes   - Allow for any connection (no protection)
# local - Allow only for local connections. Ones originating from the
#         IPv4 address (127.0.0.1), IPv6 address (::1) or Unix domain sockets.
#
# enable-protected-configs no
# enable-debug-command no
# enable-module-command no

# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379

# TCP listen() backlog.
#
# In high requests-per-second environments you need a high backlog in order
# to avoid slow clients connection issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
# in order to get the desired effect.
tcp-backlog 511

# Unix socket.
#
# Specify the path for the Unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
# unixsocket /run/redis.sock
# unixsocketperm 700

# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0

# TCP keepalive.
#
# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence
# of communication. This is useful for two reasons:
#
# 1) Detect dead peers.
# 2) Force network equipment in the middle to consider the connection to be
#    alive.
#
# On Linux, the specified value (in seconds) is the period used to send ACKs.
# Note that to close the connection the double of the time is needed.
# On other kernels the period depends on the kernel configuration.
#
# A reasonable value for this option is 300 seconds, which is the new
# Redis default starting with Redis 3.2.1.
tcp-keepalive 300

# Apply OS-specific mechanism to mark the listening socket with the specified
# ID, to support advanced routing and filtering capabilities.
#
# On Linux, the ID represents a connection mark.
# On FreeBSD, the ID represents a socket cookie ID.
# On OpenBSD, the ID represents a route table ID.
#
# The default value is 0, which implies no marking is required.
# socket-mark-id 0

################################# TLS/SSL #####################################

# By default, TLS/SSL is disabled. To enable it, the "tls-port" configuration
# directive can be used to define TLS-listening ports. To enable TLS on the
# default port, use:
#
# port 0
# tls-port 6379

# Configure a X.509 certificate and private key to use for authenticating the
# server to connected clients, masters or cluster peers.  These files should be
# PEM formatted.
#
# tls-cert-file redis.crt
# tls-key-file redis.key
#
# If the key file is encrypted using a passphrase, it can be included here
# as well.
#
# tls-key-file-pass secret

# Normally Redis uses the same certificate for both server functions (accepting
# connections) and client functions (replicating from a master, establishing
# cluster bus connections, etc.).
#
# Sometimes certificates are issued with attributes that designate them as
# client-only or server-only certificates. In that case it may be desired to use
# different certificates for incoming (server) and outgoing (client)
# connections. To do that, use the following directives:
#
# tls-client-cert-file client.crt
# tls-client-key-file client.key
#
# If the key file is encrypted using a passphrase, it can be included here
# as well.
#
# tls-client-key-file-pass secret

# Configure a DH parameters file to enable Diffie-Hellman (DH) key exchange,
# required by older versions of OpenSSL (<3.0). Newer versions do not require
# this configuration and recommend against it.
#
# tls-dh-params-file redis.dh

# Configure a CA certificate(s) bundle or directory to authenticate TLS/SSL
# clients and peers.  Redis requires an explicit configuration of at least one
# of these, and will not implicitly use the system wide configuration.
#
# tls-ca-cert-file ca.crt
# tls-ca-cert-dir /etc/ssl/certs

# By default, clients (including replica servers) on a TLS port are required
# to authenticate using valid client side certificates.
#
# If "no" is specified, client certificates are not required and not accepted.
# If "optional" is specified, client certificates are accepted and must be
# valid if provided, but are not required.
#
# tls-auth-clients no
# tls-auth-clients optional

# By default, a Redis replica does not attempt to establish a TLS connection
# with its master.
#
# Use the following directive to enable TLS on replication links.
#
# tls-replication yes

# By default, the Redis Cluster bus uses a plain TCP connection. To enable
# TLS for the bus protocol, use the following directive:
#
# tls-cluster yes

# By default, only TLSv1.2 and TLSv1.3 are enabled and it is highly recommended
# that older formally deprecated versions are kept disabled to reduce the attack surface.
# You can explicitly specify TLS versions to support.
# Allowed values are case insensitive and include "TLSv1", "TLSv1.1", "TLSv1.2",
# "TLSv1.3" (OpenSSL >= 1.1.1) or any combination.
# To enable only TLSv1.2 and TLSv1.3, use:
#
# tls-protocols "TLSv1.2 TLSv1.3"

# Configure allowed ciphers.  See the ciphers(1ssl) manpage for more information
# about the syntax of this string.
#
# Note: this configuration applies only to <= TLSv1.2.
#
# tls-ciphers DEFAULT:!MEDIUM

# Configure allowed TLSv1.3 ciphersuites.  See the ciphers(1ssl) manpage for more
# information about the syntax of this string, and specifically for TLSv1.3
# ciphersuites.
#
# tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256

# When choosing a cipher, use the server's preference instead of the client
# preference. By default, the server follows the client's preference.
#
# tls-prefer-server-ciphers yes

# By default, TLS session caching is enabled to allow faster and less expensive
# reconnections by clients that support it. Use the following directive to disable
# caching.
#
# tls-session-caching no

# Change the default number of TLS sessions cached. A zero value sets the cache
# to unlimited size. The default size is 20480.
#
# tls-session-cache-size 5000

# Change the default timeout of cached TLS sessions. The default timeout is 300
# seconds.
#
# tls-session-cache-timeout 60

################################# GENERAL #####################################

# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
# When Redis is supervised by upstart or systemd, this parameter has no impact.
daemonize no

# If you run Redis from upstart or systemd, Redis can interact with your
# supervision tree. Options:
#   supervised no      - no supervision interaction
#   supervised upstart - signal upstart by putting Redis into SIGSTOP mode
#                        requires "expect stop" in your upstart job config
#   supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET
#                        on startup, and updating Redis status on a regular
#                        basis.
#   supervised auto    - detect upstart or systemd method based on
#                        UPSTART_JOB or NOTIFY_SOCKET environment variables
# Note: these supervision methods only signal "process is ready."
#       They do not enable continuous pings back to your supervisor.
#
# The default is "no". To run under upstart/systemd, you can simply uncomment
# the line below:
#
# supervised auto

# If a pid file is specified, Redis writes it where specified at startup
# and removes it at exit.
#
# When the server runs non daemonized, no pid file is created if none is
# specified in the configuration. When the server is daemonized, the pid file
# is used even if not specified, defaulting to "/var/run/redis.pid".
#
# Creating a pid file is best effort: if Redis is not able to create it
# nothing bad happens, the server will start and run normally.
#
# Note that on modern Linux systems "/run/redis.pid" is more conforming
# and should be used instead.
pidfile /var/run/redis_6379.pid

# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice

# Specify the log file name. Also the empty string can be used to force
# Redis to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile ""

# To enable logging to the system logger, just set 'syslog-enabled' to yes,
# and optionally update the other syslog parameters to suit your needs.
# syslog-enabled no

# Specify the syslog identity.
# syslog-ident redis

# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7.
# syslog-facility local0

# To disable the built in crash log, which will possibly produce cleaner core
# dumps when they are needed, uncomment the following:
#
# crash-log-enabled no

# To disable the fast memory check that's run as part of the crash log, which
# will possibly let redis terminate sooner, uncomment the following:
#
# crash-memcheck-enabled no

# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16

# By default Redis shows an ASCII art logo only when started to log to the
# standard output and if the standard output is a TTY and syslog logging is
# disabled. Basically this means that normally a logo is displayed only in
# interactive sessions.
#
# However it is possible to force the pre-4.0 behavior and always show a
# ASCII art logo in startup logs by setting the following option to yes.
always-show-logo no

# By default, Redis modifies the process title (as seen in 'top' and 'ps') to
# provide some runtime information. It is possible to disable this and leave
# the process name as executed by setting the following to no.
set-proc-title yes

# When changing the process title, Redis uses the following template to construct
# the modified title.
#
# Template variables are specified in curly brackets. The following variables are
# supported:
#
# {title}           Name of process as executed if parent, or type of child process.
# {listen-addr}     Bind address or '*' followed by TCP or TLS port listening on, or
#                   Unix socket if only that's available.
# {server-mode}     Special mode, i.e. "[sentinel]" or "[cluster]".
# {port}            TCP port listening on, or 0.
# {tls-port}        TLS port listening on, or 0.
# {unixsocket}      Unix domain socket listening on, or "".
# {config-file}     Name of configuration file used.
#
proc-title-template "{title} {listen-addr} {server-mode}"

################################ SNAPSHOTTING  ################################

# Save the DB to disk.
#
# save <seconds> <changes> [<seconds> <changes> ...]
#
# Redis will save the DB if the given number of seconds elapsed and it
# surpassed the given number of write operations against the DB.
#
# Snapshotting can be completely disabled with a single empty string argument
# as in following example:
#
# save ""
#
# Unless specified otherwise, by default Redis will save the DB:
#   * After 3600 seconds (an hour) if at least 1 change was performed
#   * After 300 seconds (5 minutes) if at least 100 changes were performed
#   * After 60 seconds if at least 10000 changes were performed
#
# You can set these explicitly by uncommenting the following line.
#
# save 3600 1 300 100 60 10000

# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# This will make the user aware (in a hard way) that data is not persisting
# on disk properly, otherwise chances are that no one will notice and some
# disaster will happen.
#
# If the background saving process will start working again Redis will
# automatically allow writes again.
#
# However if you have setup your proper monitoring of the Redis server
# and persistence, you may want to disable this feature so that Redis will
# continue to work as usual even if there are problems with disk,
# permissions, and so forth.
stop-writes-on-bgsave-error yes

# Compress string objects using LZF when dump .rdb databases?
# By default compression is enabled as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
rdbcompression yes

# Since version 5 of RDB a CRC64 checksum is placed at the end of the file.
# This makes the format more resistant to corruption but there is a performance
# hit to pay (around 10%) when saving and loading RDB files, so you can disable it
# for maximum performances.
#
# RDB files created with checksum disabled have a checksum of zero that will
# tell the loading code to skip the check.
rdbchecksum yes

# Enables or disables full sanitization checks for ziplist and listpack etc when
# loading an RDB or RESTORE payload. This reduces the chances of a assertion or
# crash later on while processing commands.
# Options:
#   no         - Never perform full sanitization
#   yes        - Always perform full sanitization
#   clients    - Perform full sanitization only for user connections.
#                Excludes: RDB files, RESTORE commands received from the master
#                connection, and client connections which have the
#                skip-sanitize-payload ACL flag.
# The default should be 'clients' but since it currently affects cluster
# resharding via MIGRATE, it is temporarily set to 'no' by default.
#
# sanitize-dump-payload no

# The filename where to dump the DB
dbfilename dump.rdb

# Remove RDB files used by replication in instances without persistence
# enabled. By default this option is disabled, however there are environments
# where for regulations or other security concerns, RDB files persisted on
# disk by masters in order to feed replicas, or stored on disk by replicas
# in order to load them for the initial synchronization, should be deleted
# ASAP. Note that this option ONLY WORKS in instances that have both AOF
# and RDB persistence disabled, otherwise is completely ignored.
#
# An alternative (and sometimes better) way to obtain the same effect is
# to use diskless replication on both master and replicas instances. However
# in the case of replicas, diskless is not always an option.
rdb-del-sync-files no

# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir /data/redis/

################################# REPLICATION #################################

# Master-Replica replication. Use replicaof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
#
#   +------------------+      +---------------+
#   |      Master      | ---> |    Replica    |
#   | (receive writes) |      |  (exact copy) |
#   +------------------+      +---------------+
#
# 1) Redis replication is asynchronous, but you can configure a master to
#    stop accepting writes if it appears to be not connected with at least
#    a given number of replicas.
# 2) Redis replicas are able to perform a partial resynchronization with the
#    master if the replication link is lost for a relatively small amount of
#    time. You may want to configure the replication backlog size (see the next
#    sections of this file) with a sensible value depending on your needs.
# 3) Replication is automatic and does not need user intervention. After a
#    network partition replicas automatically try to reconnect to masters
#    and resynchronize with them.
#
# replicaof <masterip> <masterport>

# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the replica to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the replica request.
#
# masterauth <master-password>
masterauth 123456
# However this is not enough if you are using Redis ACLs (for Redis version
# 6 or greater), and the default user is not capable of running the PSYNC
# command and/or other commands needed for replication. In this case it's
# better to configure a special user to use with replication, and specify the
# masteruser configuration as such:
#
# masteruser <username>
#
# When masteruser is specified, the replica will authenticate against its
# master using the new AUTH form: AUTH <username> <password>.

# When a replica loses its connection with the master, or when the replication
# is still in progress, the replica can act in two different ways:
#
# 1) if replica-serve-stale-data is set to 'yes' (the default) the replica will
#    still reply to client requests, possibly with out of date data, or the
#    data set may just be empty if this is the first synchronization.
#
# 2) If replica-serve-stale-data is set to 'no' the replica will reply with error
#    "MASTERDOWN Link with MASTER is down and replica-serve-stale-data is set to 'no'"
#    to all data access commands, excluding commands such as:
#    INFO, REPLICAOF, AUTH, SHUTDOWN, REPLCONF, ROLE, CONFIG, SUBSCRIBE,
#    UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, PUBSUB, COMMAND, POST,
#    HOST and LATENCY.
#
replica-serve-stale-data yes

# You can configure a replica instance to accept writes or not. Writing against
# a replica instance may be useful to store some ephemeral data (because data
# written on a replica will be easily deleted after resync with the master) but
# may also cause problems if clients are writing to it because of a
# misconfiguration.
#
# Since Redis 2.6 by default replicas are read-only.
#
# Note: read only replicas are not designed to be exposed to untrusted clients
# on the internet. It's just a protection layer against misuse of the instance.
# Still a read only replica exports by default all the administrative commands
# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve
# security of read only replicas using 'rename-command' to shadow all the
# administrative / dangerous commands.
replica-read-only yes

# Replication SYNC strategy: disk or socket.
#
# New replicas and reconnecting replicas that are not able to continue the
# replication process just receiving differences, need to do what is called a
# "full synchronization". An RDB file is transmitted from the master to the
# replicas.
#
# The transmission can happen in two different ways:
#
# 1) Disk-backed: The Redis master creates a new process that writes the RDB
#                 file on disk. Later the file is transferred by the parent
#                 process to the replicas incrementally.
# 2) Diskless: The Redis master creates a new process that directly writes the
#              RDB file to replica sockets, without touching the disk at all.
#
# With disk-backed replication, while the RDB file is generated, more replicas
# can be queued and served with the RDB file as soon as the current child
# producing the RDB file finishes its work. With diskless replication instead
# once the transfer starts, new replicas arriving will be queued and a new
# transfer will start when the current one terminates.
#
# When diskless replication is used, the master waits a configurable amount of
# time (in seconds) before starting the transfer in the hope that multiple
# replicas will arrive and the transfer can be parallelized.
#
# With slow disks and fast (large bandwidth) networks, diskless replication
# works better.
repl-diskless-sync yes

# When diskless replication is enabled, it is possible to configure the delay
# the server waits in order to spawn the child that transfers the RDB via socket
# to the replicas.
#
# This is important since once the transfer starts, it is not possible to serve
# new replicas arriving, that will be queued for the next RDB transfer, so the
# server waits a delay in order to let more replicas arrive.
#
# The delay is specified in seconds, and by default is 5 seconds. To disable
# it entirely just set it to 0 seconds and the transfer will start ASAP.
repl-diskless-sync-delay 5

# When diskless replication is enabled with a delay, it is possible to let
# the replication start before the maximum delay is reached if the maximum
# number of replicas expected have connected. Default of 0 means that the
# maximum is not defined and Redis will wait the full delay.
repl-diskless-sync-max-replicas 0

# -----------------------------------------------------------------------------
# WARNING: RDB diskless load is experimental. Since in this setup the replica
# does not immediately store an RDB on disk, it may cause data loss during
# failovers. RDB diskless load + Redis modules not handling I/O reads may also
# cause Redis to abort in case of I/O errors during the initial synchronization
# stage with the master. Use only if you know what you are doing.
# -----------------------------------------------------------------------------
#
# Replica can load the RDB it reads from the replication link directly from the
# socket, or store the RDB to a file and read that file after it was completely
# received from the master.
#
# In many cases the disk is slower than the network, and storing and loading
# the RDB file may increase replication time (and even increase the master's
# Copy on Write memory and replica buffers).
# However, parsing the RDB file directly from the socket may mean that we have
# to flush the contents of the current database before the full rdb was
# received. For this reason we have the following options:
#
# "disabled"    - Don't use diskless load (store the rdb file to the disk first)
# "on-empty-db" - Use diskless load only when it is completely safe.
# "swapdb"      - Keep current db contents in RAM while parsing the data directly
#                 from the socket. Replicas in this mode can keep serving current
#                 data set while replication is in progress, except for cases where
#                 they can't recognize master as having a data set from same
#                 replication history.
#                 Note that this requires sufficient memory, if you don't have it,
#                 you risk an OOM kill.
repl-diskless-load disabled

# Master send PINGs to its replicas in a predefined interval. It's possible to
# change this interval with the repl_ping_replica_period option. The default
# value is 10 seconds.
#
# repl-ping-replica-period 10

# The following option sets the replication timeout for:
#
# 1) Bulk transfer I/O during SYNC, from the point of view of replica.
# 2) Master timeout from the point of view of replicas (data, pings).
# 3) Replica timeout from the point of view of masters (REPLCONF ACK pings).
#
# It is important to make sure that this value is greater than the value
# specified for repl-ping-replica-period otherwise a timeout will be detected
# every time there is low traffic between the master and the replica. The default
# value is 60 seconds.
#
# repl-timeout 60

# Disable TCP_NODELAY on the replica socket after SYNC?
#
# If you select "yes" Redis will use a smaller number of TCP packets and
# less bandwidth to send data to replicas. But this can add a delay for
# the data to appear on the replica side, up to 40 milliseconds with
# Linux kernels using a default configuration.
#
# If you select "no" the delay for data to appear on the replica side will
# be reduced but more bandwidth will be used for replication.
#
# By default we optimize for low latency, but in very high traffic conditions
# or when the master and replicas are many hops away, turning this to "yes" may
# be a good idea.
repl-disable-tcp-nodelay no

# Set the replication backlog size. The backlog is a buffer that accumulates
# replica data when replicas are disconnected for some time, so that when a
# replica wants to reconnect again, often a full resync is not needed, but a
# partial resync is enough, just passing the portion of data the replica
# missed while disconnected.
#
# The bigger the replication backlog, the longer the replica can endure the
# disconnect and later be able to perform a partial resynchronization.
#
# The backlog is only allocated if there is at least one replica connected.
#
# repl-backlog-size 1mb

# After a master has no connected replicas for some time, the backlog will be
# freed. The following option configures the amount of seconds that need to
# elapse, starting from the time the last replica disconnected, for the backlog
# buffer to be freed.
#
# Note that replicas never free the backlog for timeout, since they may be
# promoted to masters later, and should be able to correctly "partially
# resynchronize" with other replicas: hence they should always accumulate backlog.
#
# A value of 0 means to never release the backlog.
#
# repl-backlog-ttl 3600

# The replica priority is an integer number published by Redis in the INFO
# output. It is used by Redis Sentinel in order to select a replica to promote
# into a master if the master is no longer working correctly.
#
# A replica with a low priority number is considered better for promotion, so
# for instance if there are three replicas with priority 10, 100, 25 Sentinel
# will pick the one with priority 10, that is the lowest.
#
# However a special priority of 0 marks the replica as not able to perform the
# role of master, so a replica with priority of 0 will never be selected by
# Redis Sentinel for promotion.
#
# By default the priority is 100.
replica-priority 100

# The propagation error behavior controls how Redis will behave when it is
# unable to handle a command being processed in the replication stream from a master
# or processed while reading from an AOF file. Errors that occur during propagation
# are unexpected, and can cause data inconsistency. However, there are edge cases
# in earlier versions of Redis where it was possible for the server to replicate or persist
# commands that would fail on future versions. For this reason the default behavior
# is to ignore such errors and continue processing commands.
#
# If an application wants to ensure there is no data divergence, this configuration
# should be set to 'panic' instead. The value can also be set to 'panic-on-replicas'
# to only panic when a replica encounters an error on the replication stream. One of
# these two panic values will become the default value in the future once there are
# sufficient safety mechanisms in place to prevent false positive crashes.
#
# propagation-error-behavior ignore

# Replica ignore disk write errors controls the behavior of a replica when it is
# unable to persist a write command received from its master to disk. By default,
# this configuration is set to 'no' and will crash the replica in this condition.
# It is not recommended to change this default, however in order to be compatible
# with older versions of Redis this config can be toggled to 'yes' which will just
# log a warning and execute the write command it got from the master.
#
# replica-ignore-disk-write-errors no

# -----------------------------------------------------------------------------
# By default, Redis Sentinel includes all replicas in its reports. A replica
# can be excluded from Redis Sentinel's announcements. An unannounced replica
# will be ignored by the 'sentinel replicas <master>' command and won't be
# exposed to Redis Sentinel's clients.
#
# This option does not change the behavior of replica-priority. Even with
# replica-announced set to 'no', the replica can be promoted to master. To
# prevent this behavior, set replica-priority to 0.
#
# replica-announced yes

# It is possible for a master to stop accepting writes if there are less than
# N replicas connected, having a lag less or equal than M seconds.
#
# The N replicas need to be in "online" state.
#
# The lag in seconds, that must be <= the specified value, is calculated from
# the last ping received from the replica, that is usually sent every second.
#
# This option does not GUARANTEE that N replicas will accept the write, but
# will limit the window of exposure for lost writes in case not enough replicas
# are available, to the specified number of seconds.
#
# For example to require at least 3 replicas with a lag <= 10 seconds use:
#
# min-replicas-to-write 3
# min-replicas-max-lag 10
#
# Setting one or the other to 0 disables the feature.
#
# By default min-replicas-to-write is set to 0 (feature disabled) and
# min-replicas-max-lag is set to 10.

# A Redis master is able to list the address and port of the attached
# replicas in different ways. For example the "INFO replication" section
# offers this information, which is used, among other tools, by
# Redis Sentinel in order to discover replica instances.
# Another place where this info is available is in the output of the
# "ROLE" command of a master.
#
# The listed IP address and port normally reported by a replica is
# obtained in the following way:
#
#   IP: The address is auto detected by checking the peer address
#   of the socket used by the replica to connect with the master.
#
#   Port: The port is communicated by the replica during the replication
#   handshake, and is normally the port that the replica is using to
#   listen for connections.
#
# However when port forwarding or Network Address Translation (NAT) is
# used, the replica may actually be reachable via different IP and port
# pairs. The following two options can be used by a replica in order to
# report to its master a specific set of IP and port, so that both INFO
# and ROLE will report those values.
#
# There is no need to use both the options if you need to override just
# the port or the IP address.
#
# replica-announce-ip 5.5.5.5
# replica-announce-port 1234

############################### KEYS TRACKING #################################

# Redis implements server assisted support for client side caching of values.
# This is implemented using an invalidation table that remembers, using
# a radix key indexed by key name, what clients have which keys. In turn
# this is used in order to send invalidation messages to clients. Please
# check this page to understand more about the feature:
#
#   https://redis.io/topics/client-side-caching
#
# When tracking is enabled for a client, all the read only queries are assumed
# to be cached: this will force Redis to store information in the invalidation
# table. When keys are modified, such information is flushed away, and
# invalidation messages are sent to the clients. However if the workload is
# heavily dominated by reads, Redis could use more and more memory in order
# to track the keys fetched by many clients.
#
# For this reason it is possible to configure a maximum fill value for the
# invalidation table. By default it is set to 1M of keys, and once this limit
# is reached, Redis will start to evict keys in the invalidation table
# even if they were not modified, just to reclaim memory: this will in turn
# force the clients to invalidate the cached values. Basically the table
# maximum size is a trade off between the memory you want to spend server
# side to track information about who cached what, and the ability of clients
# to retain cached objects in memory.
#
# If you set the value to 0, it means there are no limits, and Redis will
# retain as many keys as needed in the invalidation table.
# In the "stats" INFO section, you can find information about the number of
# keys in the invalidation table at every given moment.
#
# Note: when key tracking is used in broadcasting mode, no memory is used
# in the server side so this setting is useless.
#
# tracking-table-max-keys 1000000

################################## SECURITY ###################################

# Warning: since Redis is pretty fast, an outside user can try up to
# 1 million passwords per second against a modern box. This means that you
# should use very strong passwords, otherwise they will be very easy to break.
# Note that because the password is really a shared secret between the client
# and the server, and should not be memorized by any human, the password
# can be easily a long string from /dev/urandom or whatever, so by using a
# long and unguessable password no brute force attack will be possible.

# Redis ACL users are defined in the following format:
#
#   user <username> ... acl rules ...
#
# For example:
#
#   user worker +@list +@connection ~jobs:* on >ffa9203c493aa99
#
# The special username "default" is used for new connections. If this user
# has the "nopass" rule, then new connections will be immediately authenticated
# as the "default" user without the need of any password provided via the
# AUTH command. Otherwise if the "default" user is not flagged with "nopass"
# the connections will start in not authenticated state, and will require
# AUTH (or the HELLO command AUTH option) in order to be authenticated and
# start to work.
#
# The ACL rules that describe what a user can do are the following:
#
#  on           Enable the user: it is possible to authenticate as this user.
#  off          Disable the user: it's no longer possible to authenticate
#               with this user, however the already authenticated connections
#               will still work.
#  skip-sanitize-payload    RESTORE dump-payload sanitization is skipped.
#  sanitize-payload         RESTORE dump-payload is sanitized (default).
#  +<command>   Allow the execution of that command.
#               May be used with `|` for allowing subcommands (e.g "+config|get")
#  -<command>   Disallow the execution of that command.
#               May be used with `|` for blocking subcommands (e.g "-config|set")
#  +@<category> Allow the execution of all the commands in such category
#               with valid categories are like @admin, @set, @sortedset, ...
#               and so forth, see the full list in the server.c file where
#               the Redis command table is described and defined.
#               The special category @all means all the commands, but currently
#               present in the server, and that will be loaded in the future
#               via modules.
#  +<command>|first-arg  Allow a specific first argument of an otherwise
#                        disabled command. It is only supported on commands with
#                        no sub-commands, and is not allowed as negative form
#                        like -SELECT|1, only additive starting with "+". This
#                        feature is deprecated and may be removed in the future.
#  allcommands  Alias for +@all. Note that it implies the ability to execute
#               all the future commands loaded via the modules system.
#  nocommands   Alias for -@all.
#  ~<pattern>   Add a pattern of keys that can be mentioned as part of
#               commands. For instance ~* allows all the keys. The pattern
#               is a glob-style pattern like the one of KEYS.
#               It is possible to specify multiple patterns.
# %R~<pattern>  Add key read pattern that specifies which keys can be read 
#               from.
# %W~<pattern>  Add key write pattern that specifies which keys can be
#               written to. 
#  allkeys      Alias for ~*
#  resetkeys    Flush the list of allowed keys patterns.
#  &<pattern>   Add a glob-style pattern of Pub/Sub channels that can be
#               accessed by the user. It is possible to specify multiple channel
#               patterns.
#  allchannels  Alias for &*
#  resetchannels            Flush the list of allowed channel patterns.
#  ><password>  Add this password to the list of valid password for the user.
#               For example >mypass will add "mypass" to the list.
#               This directive clears the "nopass" flag (see later).
#  <<password>  Remove this password from the list of valid passwords.
#  nopass       All the set passwords of the user are removed, and the user
#               is flagged as requiring no password: it means that every
#               password will work against this user. If this directive is
#               used for the default user, every new connection will be
#               immediately authenticated with the default user without
#               any explicit AUTH command required. Note that the "resetpass"
#               directive will clear this condition.
#  resetpass    Flush the list of allowed passwords. Moreover removes the
#               "nopass" status. After "resetpass" the user has no associated
#               passwords and there is no way to authenticate without adding
#               some password (or setting it as "nopass" later).
#  reset        Performs the following actions: resetpass, resetkeys, off,
#               -@all. The user returns to the same state it has immediately
#               after its creation.
# (<options>)   Create a new selector with the options specified within the
#               parentheses and attach it to the user. Each option should be 
#               space separated. The first character must be ( and the last 
#               character must be ).
# clearselectors            Remove all of the currently attached selectors. 
#                           Note this does not change the "root" user permissions,
#                           which are the permissions directly applied onto the
#                           user (outside the parentheses).
#
# ACL rules can be specified in any order: for instance you can start with
# passwords, then flags, or key patterns. However note that the additive
# and subtractive rules will CHANGE MEANING depending on the ordering.
# For instance see the following example:
#
#   user alice on +@all -DEBUG ~* >somepassword
#
# This will allow "alice" to use all the commands with the exception of the
# DEBUG command, since +@all added all the commands to the set of the commands
# alice can use, and later DEBUG was removed. However if we invert the order
# of two ACL rules the result will be different:
#
#   user alice on -DEBUG +@all ~* >somepassword
#
# Now DEBUG was removed when alice had yet no commands in the set of allowed
# commands, later all the commands are added, so the user will be able to
# execute everything.
#
# Basically ACL rules are processed left-to-right.
#
# The following is a list of command categories and their meanings:
# * keyspace - Writing or reading from keys, databases, or their metadata 
#     in a type agnostic way. Includes DEL, RESTORE, DUMP, RENAME, EXISTS, DBSIZE,
#     KEYS, EXPIRE, TTL, FLUSHALL, etc. Commands that may modify the keyspace,
#     key or metadata will also have `write` category. Commands that only read
#     the keyspace, key or metadata will have the `read` category.
# * read - Reading from keys (values or metadata). Note that commands that don't
#     interact with keys, will not have either `read` or `write`.
# * write - Writing to keys (values or metadata)
# * admin - Administrative commands. Normal applications will never need to use
#     these. Includes REPLICAOF, CONFIG, DEBUG, SAVE, MONITOR, ACL, SHUTDOWN, etc.
# * dangerous - Potentially dangerous (each should be considered with care for
#     various reasons). This includes FLUSHALL, MIGRATE, RESTORE, SORT, KEYS,
#     CLIENT, DEBUG, INFO, CONFIG, SAVE, REPLICAOF, etc.
# * connection - Commands affecting the connection or other connections.
#     This includes AUTH, SELECT, COMMAND, CLIENT, ECHO, PING, etc.
# * blocking - Potentially blocking the connection until released by another
#     command.
# * fast - Fast O(1) commands. May loop on the number of arguments, but not the
#     number of elements in the key.
# * slow - All commands that are not Fast.
# * pubsub - PUBLISH / SUBSCRIBE related
# * transaction - WATCH / MULTI / EXEC related commands.
# * scripting - Scripting related.
# * set - Data type: sets related.
# * sortedset - Data type: zsets related.
# * list - Data type: lists related.
# * hash - Data type: hashes related.
# * string - Data type: strings related.
# * bitmap - Data type: bitmaps related.
# * hyperloglog - Data type: hyperloglog related.
# * geo - Data type: geo related.
# * stream - Data type: streams related.
#
# For more information about ACL configuration please refer to
# the Redis web site at https://redis.io/topics/acl

# ACL LOG
#
# The ACL Log tracks failed commands and authentication events associated
# with ACLs. The ACL Log is useful to troubleshoot failed commands blocked
# by ACLs. The ACL Log is stored in memory. You can reclaim memory with
# ACL LOG RESET. Define the maximum entry length of the ACL Log below.
acllog-max-len 128

# Using an external ACL file
#
# Instead of configuring users here in this file, it is possible to use
# a stand-alone file just listing users. The two methods cannot be mixed:
# if you configure users here and at the same time you activate the external
# ACL file, the server will refuse to start.
#
# The format of the external ACL user file is exactly the same as the
# format that is used inside redis.conf to describe users.
#
# aclfile /etc/redis/users.acl

# IMPORTANT NOTE: starting with Redis 6 "requirepass" is just a compatibility
# layer on top of the new ACL system. The option effect will be just setting
# the password for the default user. Clients will still authenticate using
# AUTH <password> as usually, or more explicitly with AUTH default <password>
# if they follow the new protocol: both will work.
#
# The requirepass is not compatible with aclfile option and the ACL LOAD
# command, these will cause requirepass to be ignored.
#
# requirepass foobared
 requirepass 123456

# New users are initialized with restrictive permissions by default, via the
# equivalent of this ACL rule 'off resetkeys -@all'. Starting with Redis 6.2, it
# is possible to manage access to Pub/Sub channels with ACL rules as well. The
# default Pub/Sub channels permission if new users is controlled by the
# acl-pubsub-default configuration directive, which accepts one of these values:
#
# allchannels: grants access to all Pub/Sub channels
# resetchannels: revokes access to all Pub/Sub channels
#
# From Redis 7.0, acl-pubsub-default defaults to 'resetchannels' permission.
#
# acl-pubsub-default resetchannels

# Command renaming (DEPRECATED).
#
# ------------------------------------------------------------------------
# WARNING: avoid using this option if possible. Instead use ACLs to remove
# commands from the default user, and put them only in some admin user you
# create for administrative purposes.
# ------------------------------------------------------------------------
#
# It is possible to change the name of dangerous commands in a shared
# environment. For instance the CONFIG command may be renamed into something
# hard to guess so that it will still be available for internal-use tools
# but not available for general clients.
#
# Example:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possible to completely kill a command by renaming it into
# an empty string:
#
# rename-command CONFIG ""
#
# Please note that changing the name of commands that are logged into the
# AOF file or transmitted to replicas may cause problems.

################################### CLIENTS ####################################

# Set the max number of connected clients at the same time. By default
# this limit is set to 10000 clients, however if the Redis server is not
# able to configure the process file limit to allow for the specified limit
# the max number of allowed clients is set to the current file limit
# minus 32 (as Redis reserves a few file descriptors for internal uses).
#
# Once the limit is reached Redis will close all the new connections sending
# an error 'max number of clients reached'.
#
# IMPORTANT: When Redis Cluster is used, the max number of connections is also
# shared with the cluster bus: every node in the cluster will use two
# connections, one incoming and another outgoing. It is important to size the
# limit accordingly in case of very large clusters.
#
# maxclients 10000

############################## MEMORY MANAGEMENT ################################

# Set a memory usage limit to the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys
# according to the eviction policy selected (see maxmemory-policy).
#
# If Redis can't remove keys according to the policy, or if the policy is
# set to 'noeviction', Redis will start to reply with errors to commands
# that would use more memory, like SET, LPUSH, and so on, and will continue
# to reply to read-only commands like GET.
#
# This option is usually useful when using Redis as an LRU or LFU cache, or to
# set a hard memory limit for an instance (using the 'noeviction' policy).
#
# WARNING: If you have replicas attached to an instance with maxmemory on,
# the size of the output buffers needed to feed the replicas are subtracted
# from the used memory count, so that network problems / resyncs will
# not trigger a loop where keys are evicted, and in turn the output
# buffer of replicas is full with DELs of keys evicted triggering the deletion
# of more keys, and so forth until the database is completely emptied.
#
# In short... if you have replicas attached it is suggested that you set a lower
# limit for maxmemory so that there is some free RAM on the system for replica
# output buffers (but this is not needed if the policy is 'noeviction').
#
# maxmemory <bytes>

# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached. You can select one from the following behaviors:
#
# volatile-lru -> Evict using approximated LRU, only keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU, only keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key having an expire set.
# allkeys-random -> Remove a random key, any key.
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
# noeviction -> Don't evict anything, just return an error on write operations.
#
# LRU means Least Recently Used
# LFU means Least Frequently Used
#
# Both LRU, LFU and volatile-ttl are implemented using approximated
# randomized algorithms.
#
# Note: with any of the above policies, when there are no suitable keys for
# eviction, Redis will return an error on write operations that require
# more memory. These are usually commands that create new keys, add data or
# modify existing keys. A few examples are: SET, INCR, HSET, LPUSH, SUNIONSTORE,
# SORT (due to the STORE argument), and EXEC (if the transaction includes any
# command that requires memory).
#
# The default is:
#
# maxmemory-policy noeviction

# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated
# algorithms (in order to save memory), so you can tune it for speed or
# accuracy. By default Redis will check five keys and pick the one that was
# used least recently, you can change the sample size using the following
# configuration directive.
#
# The default of 5 produces good enough results. 10 Approximates very closely
# true LRU but costs more CPU. 3 is faster but not very accurate.
#
# maxmemory-samples 5

# Eviction processing is designed to function well with the default setting.
# If there is an unusually large amount of write traffic, this value may need to
# be increased.  Decreasing this value may reduce latency at the risk of
# eviction processing effectiveness
#   0 = minimum latency, 10 = default, 100 = process without regard to latency
#
# maxmemory-eviction-tenacity 10

# Starting from Redis 5, by default a replica will ignore its maxmemory setting
# (unless it is promoted to master after a failover or manually). It means
# that the eviction of keys will be just handled by the master, sending the
# DEL commands to the replica as keys evict in the master side.
#
# This behavior ensures that masters and replicas stay consistent, and is usually
# what you want, however if your replica is writable, or you want the replica
# to have a different memory setting, and you are sure all the writes performed
# to the replica are idempotent, then you may change this default (but be sure
# to understand what you are doing).
#
# Note that since the replica by default does not evict, it may end using more
# memory than the one set via maxmemory (there are certain buffers that may
# be larger on the replica, or data structures may sometimes take more memory
# and so forth). So make sure you monitor your replicas and make sure they
# have enough memory to never hit a real out-of-memory condition before the
# master hits the configured maxmemory setting.
#
# replica-ignore-maxmemory yes

# Redis reclaims expired keys in two ways: upon access when those keys are
# found to be expired, and also in background, in what is called the
# "active expire key". The key space is slowly and interactively scanned
# looking for expired keys to reclaim, so that it is possible to free memory
# of keys that are expired and will never be accessed again in a short time.
#
# The default effort of the expire cycle will try to avoid having more than
# ten percent of expired keys still in memory, and will try to avoid consuming
# more than 25% of total memory and to add latency to the system. However
# it is possible to increase the expire "effort" that is normally set to
# "1", to a greater value, up to the value "10". At its maximum value the
# system will use more CPU, longer cycles (and technically may introduce
# more latency), and will tolerate less already expired keys still present
# in the system. It's a tradeoff between memory, CPU and latency.
#
# active-expire-effort 1

############################# LAZY FREEING ####################################

# Redis has two primitives to delete keys. One is called DEL and is a blocking
# deletion of the object. It means that the server stops processing new commands
# in order to reclaim all the memory associated with an object in a synchronous
# way. If the key deleted is associated with a small object, the time needed
# in order to execute the DEL command is very small and comparable to most other
# O(1) or O(log_N) commands in Redis. However if the key is associated with an
# aggregated value containing millions of elements, the server can block for
# a long time (even seconds) in order to complete the operation.
#
# For the above reasons Redis also offers non blocking deletion primitives
# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and
# FLUSHDB commands, in order to reclaim memory in background. Those commands
# are executed in constant time. Another thread will incrementally free the
# object in the background as fast as possible.
#
# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled.
# It's up to the design of the application to understand when it is a good
# idea to use one or the other. However the Redis server sometimes has to
# delete keys or flush the whole database as a side effect of other operations.
# Specifically Redis deletes objects independently of a user call in the
# following scenarios:
#
# 1) On eviction, because of the maxmemory and maxmemory policy configurations,
#    in order to make room for new data, without going over the specified
#    memory limit.
# 2) Because of expire: when a key with an associated time to live (see the
#    EXPIRE command) must be deleted from memory.
# 3) Because of a side effect of a command that stores data on a key that may
#    already exist. For example the RENAME command may delete the old key
#    content when it is replaced with another one. Similarly SUNIONSTORE
#    or SORT with STORE option may delete existing keys. The SET command
#    itself removes any old content of the specified key in order to replace
#    it with the specified string.
# 4) During replication, when a replica performs a full resynchronization with
#    its master, the content of the whole database is removed in order to
#    load the RDB file just transferred.
#
# In all the above cases the default is to delete objects in a blocking way,
# like if DEL was called. However you can configure each case specifically
# in order to instead release memory in a non-blocking way like if UNLINK
# was called, using the following configuration directives.

lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no

# It is also possible, for the case when to replace the user code DEL calls
# with UNLINK calls is not easy, to modify the default behavior of the DEL
# command to act exactly like UNLINK, using the following configuration
# directive:

lazyfree-lazy-user-del no

# FLUSHDB, FLUSHALL, SCRIPT FLUSH and FUNCTION FLUSH support both asynchronous and synchronous
# deletion, which can be controlled by passing the [SYNC|ASYNC] flags into the
# commands. When neither flag is passed, this directive will be used to determine
# if the data should be deleted asynchronously.

lazyfree-lazy-user-flush no

################################ THREADED I/O #################################

# Redis is mostly single threaded, however there are certain threaded
# operations such as UNLINK, slow I/O accesses and other things that are
# performed on side threads.
#
# Now it is also possible to handle Redis clients socket reads and writes
# in different I/O threads. Since especially writing is so slow, normally
# Redis users use pipelining in order to speed up the Redis performances per
# core, and spawn multiple instances in order to scale more. Using I/O
# threads it is possible to easily speedup two times Redis without resorting
# to pipelining nor sharding of the instance.
#
# By default threading is disabled, we suggest enabling it only in machines
# that have at least 4 or more cores, leaving at least one spare core.
# Using more than 8 threads is unlikely to help much. We also recommend using
# threaded I/O only if you actually have performance problems, with Redis
# instances being able to use a quite big percentage of CPU time, otherwise
# there is no point in using this feature.
#
# So for instance if you have a four cores boxes, try to use 2 or 3 I/O
# threads, if you have a 8 cores, try to use 6 threads. In order to
# enable I/O threads use the following configuration directive:
#
# io-threads 4
#
# Setting io-threads to 1 will just use the main thread as usual.
# When I/O threads are enabled, we only use threads for writes, that is
# to thread the write(2) syscall and transfer the client buffers to the
# socket. However it is also possible to enable threading of reads and
# protocol parsing using the following configuration directive, by setting
# it to yes:
#
# io-threads-do-reads no
#
# Usually threading reads doesn't help much.
#
# NOTE 1: This configuration directive cannot be changed at runtime via
# CONFIG SET. Also, this feature currently does not work when SSL is
# enabled.
#
# NOTE 2: If you want to test the Redis speedup using redis-benchmark, make
# sure you also run the benchmark itself in threaded mode, using the
# --threads option to match the number of Redis threads, otherwise you'll not
# be able to notice the improvements.

############################ KERNEL OOM CONTROL ##############################

# On Linux, it is possible to hint the kernel OOM killer on what processes
# should be killed first when out of memory.
#
# Enabling this feature makes Redis actively control the oom_score_adj value
# for all its processes, depending on their role. The default scores will
# attempt to have background child processes killed before all others, and
# replicas killed before masters.
#
# Redis supports these options:
#
# no:       Don't make changes to oom-score-adj (default).
# yes:      Alias to "relative" see below.
# absolute: Values in oom-score-adj-values are written as is to the kernel.
# relative: Values are used relative to the initial value of oom_score_adj when
#           the server starts and are then clamped to a range of -1000 to 1000.
#           Because typically the initial value is 0, they will often match the
#           absolute values.
oom-score-adj no

# When oom-score-adj is used, this directive controls the specific values used
# for master, replica and background child processes. Values range -2000 to
# 2000 (higher means more likely to be killed).
#
# Unprivileged processes (not root, and without CAP_SYS_RESOURCE capabilities)
# can freely increase their value, but not decrease it below its initial
# settings. This means that setting oom-score-adj to "relative" and setting the
# oom-score-adj-values to positive values will always succeed.
oom-score-adj-values 0 200 800


#################### KERNEL transparent hugepage CONTROL ######################

# Usually the kernel Transparent Huge Pages control is set to "madvise" or
# or "never" by default (/sys/kernel/mm/transparent_hugepage/enabled), in which
# case this config has no effect. On systems in which it is set to "always",
# redis will attempt to disable it specifically for the redis process in order
# to avoid latency problems specifically with fork(2) and CoW.
# If for some reason you prefer to keep it enabled, you can set this config to
# "no" and the kernel global to "always".

disable-thp yes

############################## APPEND ONLY MODE ###############################

# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
#
# The Append Only File is an alternative persistence mode that provides
# much better durability. For instance using the default data fsync policy
# (see later in the config file) Redis can lose just one second of writes in a
# dramatic event like a server power outage, or a single write if something
# wrong with the Redis process itself happens, but the operating system is
# still running correctly.
#
# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Please check https://redis.io/topics/persistence for more information.

appendonly no

# The base name of the append only file.
#
# Redis 7 and newer use a set of append-only files to persist the dataset
# and changes applied to it. There are two basic types of files in use:
#
# - Base files, which are a snapshot representing the complete state of the
#   dataset at the time the file was created. Base files can be either in
#   the form of RDB (binary serialized) or AOF (textual commands).
# - Incremental files, which contain additional commands that were applied
#   to the dataset following the previous file.
#
# In addition, manifest files are used to track the files and the order in
# which they were created and should be applied.
#
# Append-only file names are created by Redis following a specific pattern.
# The file name's prefix is based on the 'appendfilename' configuration
# parameter, followed by additional information about the sequence and type.
#
# For example, if appendfilename is set to appendonly.aof, the following file
# names could be derived:
#
# - appendonly.aof.1.base.rdb as a base file.
# - appendonly.aof.1.incr.aof, appendonly.aof.2.incr.aof as incremental files.
# - appendonly.aof.manifest as a manifest file.

appendfilename "appendonly.aof"

# For convenience, Redis stores all persistent append-only files in a dedicated
# directory. The name of the directory is determined by the appenddirname
# configuration parameter.

appenddirname "appendonlydir"

# The fsync() call tells the Operating System to actually write data on disk
# instead of waiting for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log. Slow, Safest.
# everysec: fsync only one time every second. Compromise.
#
# The default is "everysec", as that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".

# appendfsync always
appendfsync everysec
# appendfsync no

# When the AOF fsync policy is set to always or everysec, and a background
# saving process (a background save or AOF log background rewriting) is
# performing a lot of I/O against the disk, in some Linux configurations
# Redis may block too long on the fsync() call. Note that there is no fix for
# this currently, as even performing fsync in a different thread will block
# our synchronous write(2) call.
#
# In order to mitigate this problem it's possible to use the following option
# that will prevent fsync() from being called in the main process while a
# BGSAVE or BGREWRITEAOF is in progress.
#
# This means that while another child is saving, the durability of Redis is
# the same as "appendfsync no". In practical terms, this means that it is
# possible to lose up to 30 seconds of log in the worst scenario (with the
# default Linux settings).
#
# If you have latency problems turn this to "yes". Otherwise leave it as
# "no" that is the safest pick from the point of view of durability.

no-appendfsync-on-rewrite no

# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (if no rewrite has happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a percentage of zero in order to disable the automatic AOF
# rewrite feature.

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# An AOF file may be found to be truncated at the end during the Redis
# startup process, when the AOF data gets loaded back into memory.
# This may happen when the system where Redis is running
# crashes, especially when an ext4 filesystem is mounted without the
# data=ordered option (however this can't happen when Redis itself
# crashes or aborts but the operating system still works correctly).
#
# Redis can either exit with an error when this happens, or load as much
# data as possible (the default now) and start if the AOF file is found
# to be truncated at the end. The following option controls this behavior.
#
# If aof-load-truncated is set to yes, a truncated AOF file is loaded and
# the Redis server starts emitting a log to inform the user of the event.
# Otherwise if the option is set to no, the server aborts with an error
# and refuses to start. When the option is set to no, the user requires
# to fix the AOF file using the "redis-check-aof" utility before to restart
# the server.
#
# Note that if the AOF file will be found to be corrupted in the middle
# the server will still exit with an error. This option only applies when
# Redis will try to read more data from the AOF file but not enough bytes
# will be found.
aof-load-truncated yes

# Redis can create append-only base files in either RDB or AOF formats. Using
# the RDB format is always faster and more efficient, and disabling it is only
# supported for backward compatibility purposes.
aof-use-rdb-preamble yes

# Redis supports recording timestamp annotations in the AOF to support restoring
# the data from a specific point-in-time. However, using this capability changes
# the AOF format in a way that may not be compatible with existing AOF parsers.
aof-timestamp-enabled no

################################ SHUTDOWN #####################################

# Maximum time to wait for replicas when shutting down, in seconds.
#
# During shut down, a grace period allows any lagging replicas to catch up with
# the latest replication offset before the master exists. This period can
# prevent data loss, especially for deployments without configured disk backups.
#
# The 'shutdown-timeout' value is the grace period's duration in seconds. It is
# only applicable when the instance has replicas. To disable the feature, set
# the value to 0.
#
# shutdown-timeout 10

# When Redis receives a SIGINT or SIGTERM, shutdown is initiated and by default
# an RDB snapshot is written to disk in a blocking operation if save points are configured.
# The options used on signaled shutdown can include the following values:
# default:  Saves RDB snapshot only if save points are configured.
#           Waits for lagging replicas to catch up.
# save:     Forces a DB saving operation even if no save points are configured.
# nosave:   Prevents DB saving operation even if one or more save points are configured.
# now:      Skips waiting for lagging replicas.
# force:    Ignores any errors that would normally prevent the server from exiting.
#
# Any combination of values is allowed as long as "save" and "nosave" are not set simultaneously.
# Example: "nosave force now"
#
# shutdown-on-sigint default
# shutdown-on-sigterm default

################ NON-DETERMINISTIC LONG BLOCKING COMMANDS #####################

# Maximum time in milliseconds for EVAL scripts, functions and in some cases
# modules' commands before Redis can start processing or rejecting other clients.
#
# If the maximum execution time is reached Redis will start to reply to most
# commands with a BUSY error.
#
# In this state Redis will only allow a handful of commands to be executed.
# For instance, SCRIPT KILL, FUNCTION KILL, SHUTDOWN NOSAVE and possibly some
# module specific 'allow-busy' commands.
#
# SCRIPT KILL and FUNCTION KILL will only be able to stop a script that did not
# yet call any write commands, so SHUTDOWN NOSAVE may be the only way to stop
# the server in the case a write command was already issued by the script when
# the user doesn't want to wait for the natural termination of the script.
#
# The default is 5 seconds. It is possible to set it to 0 or a negative value
# to disable this mechanism (uninterrupted execution). Note that in the past
# this config had a different name, which is now an alias, so both of these do
# the same:
# lua-time-limit 5000
# busy-reply-threshold 5000

################################ REDIS CLUSTER  ###############################

# Normal Redis instances can't be part of a Redis Cluster; only nodes that are
# started as cluster nodes can. In order to start a Redis instance as a
# cluster node enable the cluster support uncommenting the following:
#
# cluster-enabled yes
cluster-enabled yes
# Every cluster node has a cluster configuration file. This file is not
# intended to be edited by hand. It is created and updated by Redis nodes.
# Every Redis Cluster node requires a different cluster configuration file.
# Make sure that instances running in the same system do not have
# overlapping cluster configuration file names.
#
# cluster-config-file nodes-6379.conf
cluster-config-file nodes.conf
# Cluster node timeout is the amount of milliseconds a node must be unreachable
# for it to be considered in failure state.
# Most other internal time limits are a multiple of the node timeout.
#
# cluster-node-timeout 15000
cluster-node-timeout 5000

# The cluster port is the port that the cluster bus will listen for inbound connections on. When set 
# to the default value, 0, it will be bound to the command port + 10000. Setting this value requires 
# you to specify the cluster bus port when executing cluster meet.
# cluster-port 0

# A replica of a failing master will avoid to start a failover if its data
# looks too old.
#
# There is no simple way for a replica to actually have an exact measure of
# its "data age", so the following two checks are performed:
#
# 1) If there are multiple replicas able to failover, they exchange messages
#    in order to try to give an advantage to the replica with the best
#    replication offset (more data from the master processed).
#    Replicas will try to get their rank by offset, and apply to the start
#    of the failover a delay proportional to their rank.
#
# 2) Every single replica computes the time of the last interaction with
#    its master. This can be the last ping or command received (if the master
#    is still in the "connected" state), or the time that elapsed since the
#    disconnection with the master (if the replication link is currently down).
#    If the last interaction is too old, the replica will not try to failover
#    at all.
#
# The point "2" can be tuned by user. Specifically a replica will not perform
# the failover if, since the last interaction with the master, the time
# elapsed is greater than:
#
#   (node-timeout * cluster-replica-validity-factor) + repl-ping-replica-period
#
# So for example if node-timeout is 30 seconds, and the cluster-replica-validity-factor
# is 10, and assuming a default repl-ping-replica-period of 10 seconds, the
# replica will not try to failover if it was not able to talk with the master
# for longer than 310 seconds.
#
# A large cluster-replica-validity-factor may allow replicas with too old data to failover
# a master, while a too small value may prevent the cluster from being able to
# elect a replica at all.
#
# For maximum availability, it is possible to set the cluster-replica-validity-factor
# to a value of 0, which means, that replicas will always try to failover the
# master regardless of the last time they interacted with the master.
# (However they'll always try to apply a delay proportional to their
# offset rank).
#
# Zero is the only value able to guarantee that when all the partitions heal
# the cluster will always be able to continue.
#
# cluster-replica-validity-factor 10

# Cluster replicas are able to migrate to orphaned masters, that are masters
# that are left without working replicas. This improves the cluster ability
# to resist to failures as otherwise an orphaned master can't be failed over
# in case of failure if it has no working replicas.
#
# Replicas migrate to orphaned masters only if there are still at least a
# given number of other working replicas for their old master. This number
# is the "migration barrier". A migration barrier of 1 means that a replica
# will migrate only if there is at least 1 other working replica for its master
# and so forth. It usually reflects the number of replicas you want for every
# master in your cluster.
#
# Default is 1 (replicas migrate only if their masters remain with at least
# one replica). To disable migration just set it to a very large value or
# set cluster-allow-replica-migration to 'no'.
# A value of 0 can be set but is useful only for debugging and dangerous
# in production.
#
# cluster-migration-barrier 1

# Turning off this option allows to use less automatic cluster configuration.
# It both disables migration to orphaned masters and migration from masters
# that became empty.
#
# Default is 'yes' (allow automatic migrations).
#
# cluster-allow-replica-migration yes

# By default Redis Cluster nodes stop accepting queries if they detect there
# is at least a hash slot uncovered (no available node is serving it).
# This way if the cluster is partially down (for example a range of hash slots
# are no longer covered) all the cluster becomes, eventually, unavailable.
# It automatically returns available as soon as all the slots are covered again.
#
# However sometimes you want the subset of the cluster which is working,
# to continue to accept queries for the part of the key space that is still
# covered. In order to do so, just set the cluster-require-full-coverage
# option to no.
#
# cluster-require-full-coverage yes

# This option, when set to yes, prevents replicas from trying to failover its
# master during master failures. However the replica can still perform a
# manual failover, if forced to do so.
#
# This is useful in different scenarios, especially in the case of multiple
# data center operations, where we want one side to never be promoted if not
# in the case of a total DC failure.
#
# cluster-replica-no-failover no

# This option, when set to yes, allows nodes to serve read traffic while the
# cluster is in a down state, as long as it believes it owns the slots.
#
# This is useful for two cases.  The first case is for when an application
# doesn't require consistency of data during node failures or network partitions.
# One example of this is a cache, where as long as the node has the data it
# should be able to serve it.
#
# The second use case is for configurations that don't meet the recommended
# three shards but want to enable cluster mode and scale later. A
# master outage in a 1 or 2 shard configuration causes a read/write outage to the
# entire cluster without this option set, with it set there is only a write outage.
# Without a quorum of masters, slot ownership will not change automatically.
#
# cluster-allow-reads-when-down no

# This option, when set to yes, allows nodes to serve pubsub shard traffic while
# the cluster is in a down state, as long as it believes it owns the slots.
#
# This is useful if the application would like to use the pubsub feature even when
# the cluster global stable state is not OK. If the application wants to make sure only
# one shard is serving a given channel, this feature should be kept as yes.
#
# cluster-allow-pubsubshard-when-down yes

# Cluster link send buffer limit is the limit on the memory usage of an individual
# cluster bus link's send buffer in bytes. Cluster links would be freed if they exceed
# this limit. This is to primarily prevent send buffers from growing unbounded on links
# toward slow peers (E.g. PubSub messages being piled up).
# This limit is disabled by default. Enable this limit when 'mem_cluster_links' INFO field
# and/or 'send-buffer-allocated' entries in the 'CLUSTER LINKS` command output continuously increase.
# Minimum limit of 1gb is recommended so that cluster link buffer can fit in at least a single
# PubSub message by default. (client-query-buffer-limit default value is 1gb)
#
# cluster-link-sendbuf-limit 0
 
# Clusters can configure their announced hostname using this config. This is a common use case for 
# applications that need to use TLS Server Name Indication (SNI) or dealing with DNS based
# routing. By default this value is only shown as additional metadata in the CLUSTER SLOTS
# command, but can be changed using 'cluster-preferred-endpoint-type' config. This value is 
# communicated along the clusterbus to all nodes, setting it to an empty string will remove 
# the hostname and also propagate the removal.
#
# cluster-announce-hostname ""

# Clusters can advertise how clients should connect to them using either their IP address,
# a user defined hostname, or by declaring they have no endpoint. Which endpoint is
# shown as the preferred endpoint is set by using the cluster-preferred-endpoint-type
# config with values 'ip', 'hostname', or 'unknown-endpoint'. This value controls how
# the endpoint returned for MOVED/ASKING requests as well as the first field of CLUSTER SLOTS. 
# If the preferred endpoint type is set to hostname, but no announced hostname is set, a '?' 
# will be returned instead.
#
# When a cluster advertises itself as having an unknown endpoint, it's indicating that
# the server doesn't know how clients can reach the cluster. This can happen in certain 
# networking situations where there are multiple possible routes to the node, and the 
# server doesn't know which one the client took. In this case, the server is expecting
# the client to reach out on the same endpoint it used for making the last request, but use
# the port provided in the response.
#
# cluster-preferred-endpoint-type ip

# In order to setup your cluster make sure to read the documentation
# available at https://redis.io web site.

########################## CLUSTER DOCKER/NAT support  ########################

# In certain deployments, Redis Cluster nodes address discovery fails, because
# addresses are NAT-ted or because ports are forwarded (the typical case is
# Docker and other containers).
#
# In order to make Redis Cluster working in such environments, a static
# configuration where each node knows its public address is needed. The
# following four options are used for this scope, and are:
#
# * cluster-announce-ip
# * cluster-announce-port
# * cluster-announce-tls-port
# * cluster-announce-bus-port
#
# Each instructs the node about its address, client ports (for connections
# without and with TLS) and cluster message bus port. The information is then
# published in the header of the bus packets so that other nodes will be able to
# correctly map the address of the node publishing the information.
#
# If cluster-tls is set to yes and cluster-announce-tls-port is omitted or set
# to zero, then cluster-announce-port refers to the TLS port. Note also that
# cluster-announce-tls-port has no effect if cluster-tls is set to no.
#
# If the above options are not used, the normal Redis Cluster auto-detection
# will be used instead.
#
# Note that when remapped, the bus port may not be at the fixed offset of
# clients port + 10000, so you can specify any port and bus-port depending
# on how they get remapped. If the bus-port is not set, a fixed offset of
# 10000 will be used as usual.
#
# Example:
#
# cluster-announce-ip 10.1.1.5
# cluster-announce-tls-port 6379
# cluster-announce-port 0
# cluster-announce-bus-port 6380

################################## SLOW LOG ###################################

# The Redis Slow Log is a system to log queries that exceeded a specified
# execution time. The execution time does not include the I/O operations
# like talking with the client, sending the reply and so forth,
# but just the time needed to actually execute the command (this is the only
# stage of command execution where the thread is blocked and can not serve
# other requests in the meantime).
#
# You can configure the slow log with two parameters: one tells Redis
# what is the execution time, in microseconds, to exceed in order for the
# command to get logged, and the other parameter is the length of the
# slow log. When a new command is logged the oldest one is removed from the
# queue of logged commands.

# The following time is expressed in microseconds, so 1000000 is equivalent
# to one second. Note that a negative number disables the slow log, while
# a value of zero forces the logging of every command.
slowlog-log-slower-than 10000

# There is no limit to this length. Just be aware that it will consume memory.
# You can reclaim memory used by the slow log with SLOWLOG RESET.
slowlog-max-len 128

################################ LATENCY MONITOR ##############################

# The Redis latency monitoring subsystem samples different operations
# at runtime in order to collect data related to possible sources of
# latency of a Redis instance.
#
# Via the LATENCY command this information is available to the user that can
# print graphs and obtain reports.
#
# The system only logs operations that were performed in a time equal or
# greater than the amount of milliseconds specified via the
# latency-monitor-threshold configuration directive. When its value is set
# to zero, the latency monitor is turned off.
#
# By default latency monitoring is disabled since it is mostly not needed
# if you don't have latency issues, and collecting data has a performance
# impact, that while very small, can be measured under big load. Latency
# monitoring can easily be enabled at runtime using the command
# "CONFIG SET latency-monitor-threshold <milliseconds>" if needed.
latency-monitor-threshold 0

################################ LATENCY TRACKING ##############################

# The Redis extended latency monitoring tracks the per command latencies and enables
# exporting the percentile distribution via the INFO latencystats command,
# and cumulative latency distributions (histograms) via the LATENCY command.
#
# By default, the extended latency monitoring is enabled since the overhead
# of keeping track of the command latency is very small.
# latency-tracking yes

# By default the exported latency percentiles via the INFO latencystats command
# are the p50, p99, and p999.
# latency-tracking-info-percentiles 50 99 99.9

############################# EVENT NOTIFICATION ##############################

# Redis can notify Pub/Sub clients about events happening in the key space.
# This feature is documented at https://redis.io/topics/notifications
#
# For instance if keyspace events notification is enabled, and a client
# performs a DEL operation on key "foo" stored in the Database 0, two
# messages will be published via Pub/Sub:
#
# PUBLISH __keyspace@0__:foo del
# PUBLISH __keyevent@0__:del foo
#
# It is possible to select the events that Redis will notify among a set
# of classes. Every class is identified by a single character:
#
#  K     Keyspace events, published with __keyspace@<db>__ prefix.
#  E     Keyevent events, published with __keyevent@<db>__ prefix.
#  g     Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ...
#  $     String commands
#  l     List commands
#  s     Set commands
#  h     Hash commands
#  z     Sorted set commands
#  x     Expired events (events generated every time a key expires)
#  e     Evicted events (events generated when a key is evicted for maxmemory)
#  n     New key events (Note: not included in the 'A' class)
#  t     Stream commands
#  d     Module key type events
#  m     Key-miss events (Note: It is not included in the 'A' class)
#  A     Alias for g$lshzxetd, so that the "AKE" string means all the events
#        (Except key-miss events which are excluded from 'A' due to their
#         unique nature).
#
#  The "notify-keyspace-events" takes as argument a string that is composed
#  of zero or multiple characters. The empty string means that notifications
#  are disabled.
#
#  Example: to enable list and generic events, from the point of view of the
#           event name, use:
#
#  notify-keyspace-events Elg
#
#  Example 2: to get the stream of the expired keys subscribing to channel
#             name __keyevent@0__:expired use:
#
#  notify-keyspace-events Ex
#
#  By default all notifications are disabled because most users don't need
#  this feature and the feature has some overhead. Note that if you don't
#  specify at least one of K or E, no events will be delivered.
notify-keyspace-events ""

############################### ADVANCED CONFIG ###############################

# Hashes are encoded using a memory efficient data structure when they have a
# small number of entries, and the biggest entry does not exceed a given
# threshold. These thresholds can be configured using the following directives.
hash-max-listpack-entries 512
hash-max-listpack-value 64

# Lists are also encoded in a special way to save a lot of space.
# The number of entries allowed per internal list node can be specified
# as a fixed maximum size or a maximum number of elements.
# For a fixed maximum size, use -5 through -1, meaning:
# -5: max size: 64 Kb  <-- not recommended for normal workloads
# -4: max size: 32 Kb  <-- not recommended
# -3: max size: 16 Kb  <-- probably not recommended
# -2: max size: 8 Kb   <-- good
# -1: max size: 4 Kb   <-- good
# Positive numbers mean store up to _exactly_ that number of elements
# per list node.
# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size),
# but if your use case is unique, adjust the settings as necessary.
list-max-listpack-size -2

# Lists may also be compressed.
# Compress depth is the number of quicklist ziplist nodes from *each* side of
# the list to *exclude* from compression.  The head and tail of the list
# are always uncompressed for fast push/pop operations.  Settings are:
# 0: disable all list compression
# 1: depth 1 means "don't start compressing until after 1 node into the list,
#    going from either the head or tail"
#    So: [head]->node->node->...->node->[tail]
#    [head], [tail] will always be uncompressed; inner nodes will compress.
# 2: [head]->[next]->node->node->...->node->[prev]->[tail]
#    2 here means: don't compress head or head->next or tail->prev or tail,
#    but compress all nodes between them.
# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail]
# etc.
list-compress-depth 0

# Sets have a special encoding in just one case: when a set is composed
# of just strings that happen to be integers in radix 10 in the range
# of 64 bit signed integers.
# The following configuration setting sets the limit in the size of the
# set in order to use this special memory saving encoding.
set-max-intset-entries 512

# Similarly to hashes and lists, sorted sets are also specially encoded in
# order to save a lot of space. This encoding is only used when the length and
# elements of a sorted set are below the following limits:
zset-max-listpack-entries 128
zset-max-listpack-value 64

# HyperLogLog sparse representation bytes limit. The limit includes the
# 16 bytes header. When an HyperLogLog using the sparse representation crosses
# this limit, it is converted into the dense representation.
#
# A value greater than 16000 is totally useless, since at that point the
# dense representation is more memory efficient.
#
# The suggested value is ~ 3000 in order to have the benefits of
# the space efficient encoding without slowing down too much PFADD,
# which is O(N) with the sparse encoding. The value can be raised to
# ~ 10000 when CPU is not a concern, but space is, and the data set is
# composed of many HyperLogLogs with cardinality in the 0 - 15000 range.
hll-sparse-max-bytes 3000

# Streams macro node max size / items. The stream data structure is a radix
# tree of big nodes that encode multiple items inside. Using this configuration
# it is possible to configure how big a single node can be in bytes, and the
# maximum number of items it may contain before switching to a new node when
# appending new stream entries. If any of the following settings are set to
# zero, the limit is ignored, so for instance it is possible to set just a
# max entries limit by setting max-bytes to 0 and max-entries to the desired
# value.
stream-node-max-bytes 4096
stream-node-max-entries 100

# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
# order to help rehashing the main Redis hash table (the one mapping top-level
# keys to values). The hash table implementation Redis uses (see dict.c)
# performs a lazy rehashing: the more operation you run into a hash table
# that is rehashing, the more rehashing "steps" are performed, so if the
# server is idle the rehashing is never complete and some more memory is used
# by the hash table.
#
# The default is to use this millisecond 10 times every second in order to
# actively rehash the main dictionaries, freeing memory when possible.
#
# If unsure:
# use "activerehashing no" if you have hard latency requirements and it is
# not a good thing in your environment that Redis can reply from time to time
# to queries with 2 milliseconds delay.
#
# use "activerehashing yes" if you don't have such hard requirements but
# want to free memory asap when possible.
activerehashing yes

# The client output buffer limits can be used to force disconnection of clients
# that are not reading data from the server fast enough for some reason (a
# common reason is that a Pub/Sub client can't consume messages as fast as the
# publisher can produce them).
#
# The limit can be set differently for the three different classes of clients:
#
# normal -> normal clients including MONITOR clients
# replica -> replica clients
# pubsub -> clients subscribed to at least one pubsub channel or pattern
#
# The syntax of every client-output-buffer-limit directive is the following:
#
# client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
#
# A client is immediately disconnected once the hard limit is reached, or if
# the soft limit is reached and remains reached for the specified number of
# seconds (continuously).
# So for instance if the hard limit is 32 megabytes and the soft limit is
# 16 megabytes / 10 seconds, the client will get disconnected immediately
# if the size of the output buffers reach 32 megabytes, but will also get
# disconnected if the client reaches 16 megabytes and continuously overcomes
# the limit for 10 seconds.
#
# By default normal clients are not limited because they don't receive data
# without asking (in a push way), but just after a request, so only
# asynchronous clients may create a scenario where data is requested faster
# than it can read.
#
# Instead there is a default limit for pubsub and replica clients, since
# subscribers and replicas receive data in a push fashion.
#
# Note that it doesn't make sense to set the replica clients output buffer
# limit lower than the repl-backlog-size config (partial sync will succeed
# and then replica will get disconnected).
# Such a configuration is ignored (the size of repl-backlog-size will be used).
# This doesn't have memory consumption implications since the replica client
# will share the backlog buffers memory.
#
# Both the hard or the soft limit can be disabled by setting them to zero.
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

# Client query buffers accumulate new commands. They are limited to a fixed
# amount by default in order to avoid that a protocol desynchronization (for
# instance due to a bug in the client) will lead to unbound memory usage in
# the query buffer. However you can configure it here if you have very special
# needs, such us huge multi/exec requests or alike.
#
# client-query-buffer-limit 1gb

# In some scenarios client connections can hog up memory leading to OOM
# errors or data eviction. To avoid this we can cap the accumulated memory
# used by all client connections (all pubsub and normal clients). Once we
# reach that limit connections will be dropped by the server freeing up
# memory. The server will attempt to drop the connections using the most 
# memory first. We call this mechanism "client eviction".
#
# Client eviction is configured using the maxmemory-clients setting as follows:
# 0 - client eviction is disabled (default)
#
# A memory value can be used for the client eviction threshold,
# for example:
# maxmemory-clients 1g
#
# A percentage value (between 1% and 100%) means the client eviction threshold
# is based on a percentage of the maxmemory setting. For example to set client
# eviction at 5% of maxmemory:
# maxmemory-clients 5%

# In the Redis protocol, bulk requests, that are, elements representing single
# strings, are normally limited to 512 mb. However you can change this limit
# here, but must be 1mb or greater
#
# proto-max-bulk-len 512mb

# Redis calls an internal function to perform many background tasks, like
# closing connections of clients in timeout, purging expired keys that are
# never requested, and so forth.
#
# Not all tasks are performed with the same frequency, but Redis checks for
# tasks to perform according to the specified "hz" value.
#
# By default "hz" is set to 10. Raising the value will use more CPU when
# Redis is idle, but at the same time will make Redis more responsive when
# there are many keys expiring at the same time, and timeouts may be
# handled with more precision.
#
# The range is between 1 and 500, however a value over 100 is usually not
# a good idea. Most users should use the default of 10 and raise this up to
# 100 only in environments where very low latency is required.
hz 10

# Normally it is useful to have an HZ value which is proportional to the
# number of clients connected. This is useful in order, for instance, to
# avoid too many clients are processed for each background task invocation
# in order to avoid latency spikes.
#
# Since the default HZ value by default is conservatively set to 10, Redis
# offers, and enables by default, the ability to use an adaptive HZ value
# which will temporarily raise when there are many connected clients.
#
# When dynamic HZ is enabled, the actual configured HZ will be used
# as a baseline, but multiples of the configured HZ value will be actually
# used as needed once more clients are connected. In this way an idle
# instance will use very little CPU time while a busy instance will be
# more responsive.
dynamic-hz yes

# When a child rewrites the AOF file, if the following option is enabled
# the file will be fsync-ed every 4 MB of data generated. This is useful
# in order to commit the file to the disk more incrementally and avoid
# big latency spikes.
aof-rewrite-incremental-fsync yes

# When redis saves RDB file, if the following option is enabled
# the file will be fsync-ed every 4 MB of data generated. This is useful
# in order to commit the file to the disk more incrementally and avoid
# big latency spikes.
rdb-save-incremental-fsync yes

# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good
# idea to start with the default settings and only change them after investigating
# how to improve the performances and how the keys LFU change over time, which
# is possible to inspect via the OBJECT FREQ command.
#
# There are two tunable parameters in the Redis LFU implementation: the
# counter logarithm factor and the counter decay time. It is important to
# understand what the two parameters mean before changing them.
#
# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis
# uses a probabilistic increment with logarithmic behavior. Given the value
# of the old counter, when a key is accessed, the counter is incremented in
# this way:
#
# 1. A random number R between 0 and 1 is extracted.
# 2. A probability P is calculated as 1/(old_value*lfu_log_factor+1).
# 3. The counter is incremented only if R < P.
#
# The default lfu-log-factor is 10. This is a table of how the frequency
# counter changes with a different number of accesses with different
# logarithmic factors:
#
# +--------+------------+------------+------------+------------+------------+
# | factor | 100 hits   | 1000 hits  | 100K hits  | 1M hits    | 10M hits   |
# +--------+------------+------------+------------+------------+------------+
# | 0      | 104        | 255        | 255        | 255        | 255        |
# +--------+------------+------------+------------+------------+------------+
# | 1      | 18         | 49         | 255        | 255        | 255        |
# +--------+------------+------------+------------+------------+------------+
# | 10     | 10         | 18         | 142        | 255        | 255        |
# +--------+------------+------------+------------+------------+------------+
# | 100    | 8          | 11         | 49         | 143        | 255        |
# +--------+------------+------------+------------+------------+------------+
#
# NOTE: The above table was obtained by running the following commands:
#
#   redis-benchmark -n 1000000 incr foo
#   redis-cli object freq foo
#
# NOTE 2: The counter initial value is 5 in order to give new objects a chance
# to accumulate hits.
#
# The counter decay time is the time, in minutes, that must elapse in order
# for the key counter to be divided by two (or decremented if it has a value
# less <= 10).
#
# The default value for the lfu-decay-time is 1. A special value of 0 means to
# decay the counter every time it happens to be scanned.
#
# lfu-log-factor 10
# lfu-decay-time 1

########################### ACTIVE DEFRAGMENTATION #######################
#
# What is active defragmentation?
# -------------------------------
#
# Active (online) defragmentation allows a Redis server to compact the
# spaces left between small allocations and deallocations of data in memory,
# thus allowing to reclaim back memory.
#
# Fragmentation is a natural process that happens with every allocator (but
# less so with Jemalloc, fortunately) and certain workloads. Normally a server
# restart is needed in order to lower the fragmentation, or at least to flush
# away all the data and create it again. However thanks to this feature
# implemented by Oran Agra for Redis 4.0 this process can happen at runtime
# in a "hot" way, while the server is running.
#
# Basically when the fragmentation is over a certain level (see the
# configuration options below) Redis will start to create new copies of the
# values in contiguous memory regions by exploiting certain specific Jemalloc
# features (in order to understand if an allocation is causing fragmentation
# and to allocate it in a better place), and at the same time, will release the
# old copies of the data. This process, repeated incrementally for all the keys
# will cause the fragmentation to drop back to normal values.
#
# Important things to understand:
#
# 1. This feature is disabled by default, and only works if you compiled Redis
#    to use the copy of Jemalloc we ship with the source code of Redis.
#    This is the default with Linux builds.
#
# 2. You never need to enable this feature if you don't have fragmentation
#    issues.
#
# 3. Once you experience fragmentation, you can enable this feature when
#    needed with the command "CONFIG SET activedefrag yes".
#
# The configuration parameters are able to fine tune the behavior of the
# defragmentation process. If you are not sure about what they mean it is
# a good idea to leave the defaults untouched.

# Active defragmentation is disabled by default
# activedefrag no

# Minimum amount of fragmentation waste to start active defrag
# active-defrag-ignore-bytes 100mb

# Minimum percentage of fragmentation to start active defrag
# active-defrag-threshold-lower 10

# Maximum percentage of fragmentation at which we use maximum effort
# active-defrag-threshold-upper 100

# Minimal effort for defrag in CPU percentage, to be used when the lower
# threshold is reached
# active-defrag-cycle-min 1

# Maximal effort for defrag in CPU percentage, to be used when the upper
# threshold is reached
# active-defrag-cycle-max 25

# Maximum number of set/hash/zset/list fields that will be processed from
# the main dictionary scan
# active-defrag-max-scan-fields 1000

# Jemalloc background thread for purging will be enabled by default
jemalloc-bg-thread yes

# It is possible to pin different threads and processes of Redis to specific
# CPUs in your system, in order to maximize the performances of the server.
# This is useful both in order to pin different Redis threads in different
# CPUs, but also in order to make sure that multiple Redis instances running
# in the same host will be pinned to different CPUs.
#
# Normally you can do this using the "taskset" command, however it is also
# possible to this via Redis configuration directly, both in Linux and FreeBSD.
#
# You can pin the server/IO threads, bio threads, aof rewrite child process, and
# the bgsave child process. The syntax to specify the cpu list is the same as
# the taskset command:
#
# Set redis server/io threads to cpu affinity 0,2,4,6:
# server_cpulist 0-7:2
#
# Set bio threads to cpu affinity 1,3:
# bio_cpulist 1,3
#
# Set aof rewrite child process to cpu affinity 8,9,10,11:
# aof_rewrite_cpulist 8-11
#
# Set bgsave child process to cpu affinity 1,10,11
# bgsave_cpulist 1,10-11

# In some cases redis will emit warnings and even refuse to start if it detects
# that the system is in bad state, it is possible to suppress these warnings
# by setting the following config which takes a space delimited list of warnings
# to suppress
#
# ignore-warnings ARM64-COW-BUG

/data/maxqhx/mydockerfile/myrediscluster/redis/Dockerfile

FROM ubuntu:22.04 as buildstage
RUN sudo sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list & apt update
RUN apt install -y build-essential
#wget http://download.redis.io/releases/redis-7.0.11.tar.gz
ADD redis-7.0.11.tar.gz /
ADD redis.conf /redis/
WORKDIR /redis-7.0.11
RUN make
RUN mv /redis-7.0.11/src/redis-server /redis/ && mv /redis-7.0.11/src/redis-cli /redis/
ENTRYPOINT ["/redis/redis-server", "/redis/redis.conf"]

FROM ubuntu:22.04
RUN mkdir -p /data/redis && mkdir -p /redis
COPY --from=buildstage /redis /redis
EXPOSE 6379
ENTRYPOINT ["/redis/redis-server", "/redis/redis.conf"]
Dockerfile 配合 docker-compose 搭建 SpringBoot微服务

准备目录

mymicroservice

mkdir -p /data/maxqhx/mydockerfile/mymicroservice

app/user

mkdir -p /data/maxqhx/mydockerfile/mymicroservice/app/user

mysql

mkdir -p /data/maxqhx/mydockerfile/mymicroservice/mysql

nginx

mkdir -p /data/maxqhx/mydockerfile/mymicroservice/nginx

redis

mkdir -p data/maxqhx/mydockerfile/mymicroservice/redis

内容:

/data/maxqhx/mydockerfile/mymicroservice/docker-compose.yml

version: "3"

services:
  mysql-master:
    build:
      context: ./mysql
      dockerfile: ./master/Dockerfile-master
    image: mysqlmaster:v2.0
    restart: always
    container_name: mysql-master
    volumes:
      - ./mastervarlib:/var/lib/mysql
    ports:
      - 9306:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
    privileged: true
    command:
      - --server-id=1
      - --log-bin=master-bin
      - --binlog-ignore-db=mysql
      - --binlog_cache_size=256M
      - --binlog_format=mixed
      - --lower_case_table_names=1
      - --character-set-server=utf8
      - --collation-server=utf8_general_ci

  mysql-slave:
    build:
      context: ./mysql
      dockerfile: ./slave/Dockerfile-slave
    image: mysqlslave:v2.0
    restart: always
    container_name: mysql-slave
    volumes:
      - ./slavevarlib:/var/lib/mysql
    ports:
      - 9307:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
    privileged: true
    command:
      - --server-id=2
      - --relay_log=slave-relay
      - --lower_case_table_names=1
      - --character-set-server=utf8
      - --collation-server=utf8_general_ci
    depends_on:
      - mysql-master

  redis01:
    image: myredis:v1.0
    build: ./redis
    ports:
      - 6379:6379
    container_name: redis01
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis02:
    image: myredis:v1.0
    container_name: redis02
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis03:
    image: myredis:v1.0
    container_name: redis03
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis04:
    image: myredis:v1.0
    container_name: redis04
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis05:
    image: myredis:v1.0
    container_name: redis05
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis06:
    image: myredis:v1.0
    container_name: redis06
    healthcheck:
      test: /redis/redis-cli ping
      interval: 10s
      timeout: 5s
      retries: 10

  redis07:
    image: myredis:v1.0
    container_name: redis07
    entrypoint:
      - /redis/redis-cli
      - --cluster
      - create
      - redis01:6379
      - redis02:6379
      - redis03:6379
      - redis04:6379
      - redis05:6379
      - redis06:6379
      - --cluster-replicas
      - "1"
      - -a
      - "123456"
      - --cluster-yes
    depends_on:
      redis01:
        condition: service_healthy
      redis02:
        condition: service_healthy
      redis03:
        condition: service_healthy
      redis04:
        condition: service_healthy
      redis05:
        condition: service_healthy
      redis06:
        condition: service_healthy

  web:
    image: mynginx:v2.0
    build:
      context: ./nginx
    ports:
      - 80:80
    depends_on:
      myuser:
        condition: service_started
      myuser2:
        condition: service_started

  myuser:
    image: myuser:v2.0
    build:
      context: ./app/user
    depends_on:
      redis01:
        condition: service_healthy
      redis02:
        condition: service_healthy
      redis03:
        condition: service_healthy
      redis04:
        condition: service_healthy
      redis05:
        condition: service_healthy
      redis06:
        condition: service_healthy
      mysql-master:
        condition: service_started

  myuser2:
    image: myuser:v2.0
    build:
      context: ./app/user
    depends_on:
      redis01:
        condition: service_healthy
      redis02:
        condition: service_healthy
      redis03:
        condition: service_healthy
      redis04:
        condition: service_healthy
      redis05:
        condition: service_healthy
      redis06:
        condition: service_healthy
      mysql-master:
        condition: service_started

mysql和redis从之前的项目拷贝就行

/data/maxqhx/mydockerfile/mymicroservice/nginx/bit.conf

upstream myapi{
 server myuser:8080;
 server myuser2:8080;
}
server {
 listen 80;

 access_log off;


 location / {
 proxy_pass http://myapi/user/;
 }
}

/data/maxqhx/mydockerfile/mymicroservice/nginx/Dockerfile

FROM nginx:1.24.0
COPY ./bit.conf /etc/nginx/conf.d/
CMD ["nginx","-g","daemon off;"]
#ENTRYPOINT ["/docker-entrypoint.sh"]

/data/maxqhx/mydockerfile/mymicroservice/app/user/Dockerfile

FROM openjdk:8
ADD ./dockerDemo-0.0.1-SNAPSHOT.jar /app.jar
#运行jar包
CMD ["java","-jar","/app.jar","--spring.profiles.active=docker"]

springBoot项目需要准备两个配置文件:

application-docker.yml

spring:
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://mysql-master:3306/test
    username: root
    password: root
  redis:
    password: 123456
    lettuce:
      pool:
        max-active: 50
        max-idle: 5
        min-idle: 0
        max-wait: 5000
    database: 0
    cluster:
      nodes: redis01:6379,redis02:6379,redis03:6379,redis04:6379,redis05:6379,redis06:6379
    connect-timeout: 5000
    timeout: 5000

application-local.yml

spring:
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://172.27.7.240:9306/test
    username: root
    password: root
  redis:
    password: 123456
    lettuce:
      pool:
        max-active: 50
        max-idle: 5
        min-idle: 0
        max-wait: 5000
    database: 0
    cluster:
      nodes: 172.27.7.240:6372
    connect-timeout: 5000
    timeout: 5000

把jar包上传到/data/maxqhx/mydockerfile/mymicroservice/app/user目录中

本地配置文件进行简单的测试:

java -jar dockerDemo-0.0.1-SNAPSHOT.jar --spring.profiles.active=local

指定配置文件,application-local.yml

--spring.profiles.active=local
Dockerfile 结合 docker compose 搭建 C++微服务

准备目录:

mycppmicroservice

mkdir -p /data/maxqhx/mydockerfile/mycppmicroservice

cppweb

mkdir -p /data/maxqhx/mydockerfile/mycppmicroservice/cppweb

nginx

mkdir -p /data/maxqhx/mydockerfile/mycppmicroservice/nginx

内容:

docker-compose.yml

services:
  web:
    image: mynginx:v3.0
    build:
      context: ./nginx
    ports:
      - 8112:80
    depends_on:
      mycppweb:
        condition: service_started

  mycppweb:
    build:
      context: ./cppweb
    image: mycppweb:v2.0

  mycppweb2:
    image: mycppweb:v2.0

/data/maxqhx/mydockerfile/mycppmicroservice/cppweb/Dockerfile

FROM ubuntu:22.04

# 换源 + 安装编译工具
RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list && \
    apt update && \
    apt install -y build-essential

WORKDIR /src
COPY main.cpp .

# 直接编译!不需要 devtoolset
RUN g++ main.cpp -o mycppweb -pthread

CMD ["/src/mycppweb"]

/data/maxqhx/mydockerfile/mycppmicroservice/cppweb/main.cpp

#include <iostream>
#include <netinet/in.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>

using namespace std;

struct pthread_data {
    struct sockaddr_in client_addr;
    int sock_fd;
};

void* serverForClient(void* arg);

int main() {
    int socket_fd;
    int conn_fd;
    int res;
    int len;
    struct sockaddr_in sever_add;

    memset(&sever_add, 0, sizeof(sever_add));
    sever_add.sin_family = AF_INET;
    sever_add.sin_addr.s_addr = htonl(INADDR_ANY);
    sever_add.sin_port = htons(8081);
    len = sizeof(sever_add);

    int option = 1;
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    assert(socket_fd >= 0);

    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));

    res = bind(socket_fd, (struct sockaddr*)&sever_add, len);
    perror("bind");
    assert(res != -1);

    res = listen(socket_fd, 10);
    assert(res != -1);

    cout << "server init success" << endl;

    while (1) {
        struct sockaddr_in client;
        socklen_t client_len = sizeof(client);

        conn_fd = accept(socket_fd, (struct sockaddr*)&client, &client_len);

        pthread_data* pdata = new pthread_data;
        pdata->client_addr = client;
        pdata->sock_fd = conn_fd;

        cout << "new client: " << conn_fd << endl;

        pthread_t pt;
        pthread_create(&pt, NULL, serverForClient, (void*)pdata);
        pthread_detach(pt);
    }

    close(socket_fd);
    return 0;
}

void* serverForClient(void* arg) {
    struct pthread_data* pdata = (struct pthread_data*)arg;
    int conn_fd = pdata->sock_fd;

    cout << "process client: " << conn_fd << endl;

    if (conn_fd < 0) {
        delete pdata;
        return nullptr;
    }

    char request[1024] = {0};
    int len = recv(conn_fd, request, 1023, 0);
    if (len <= 0) {
        close(conn_fd);
        delete pdata;
        return nullptr;
    }

    const char* resp =
        "HTTP/1.1 200 ok\r\n"
        "connection: close\r\n"
        "\r\n"
        "<!DOCTYPE html>\n"
        "<html>\n"
        "<head>\n"
        "<title>Welcome to C++ web server!</title>\n"
        "<style>\n"
        "html { color-scheme: light dark; }\n"
        "body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; }\n"
        "</style>\n"
        "</head>\n"
        "<body>\n"
        "<h1>Welcome to C++ webserver!</h1>\n"
        "<p>If you see this page, the web server is successfully installed and working.</p>\n"
        "<p><em>Thank you for using webserver.</em></p>\n"
        "</body>\n"
        "</html>";

    send(conn_fd, resp, strlen(resp), 0);

    close(conn_fd);
    delete pdata;
    return nullptr;
}

/data/maxqhx/mydockerfile/mycppmicroservice/nginx/bit.conf

upstream backend {
 server mycppweb:8081 weight=1;
 server mycppweb2:8081 weight=2;
}
server {
 listen 80;
 access_log off;
 location / {
 proxy_pass http://backend;
 }
}

/data/maxqhx/mydockerfile/mycppmicroservice/nginx/Dockerfile

FROM nginx:1.24.0
COPY ./bit.conf /etc/nginx/conf.d/
CMD ["nginx","-g","daemon off;"]
ENTRYPOINT ["/docker-entrypoint.sh"]
镜像制作常见问题
ADD 与 COPY 的区别

ADD:不仅能够将构建命令所在的主机本地的文件或目录,而且能够将远程 URL 所对应的文件或目录,作为资源复制到镜像文件系统。所以,可以认为 ADD 是增强版 的 COPY,支持将远程 URL 的资源加入到镜像的文件系统。

COPY:COPY 指令能够将构建命令所在的主机本地的文件或目录,复制到镜像 文件系统。 有的时候就是只需要拷贝压缩包,那么我们就要用 COPY 指令了

CMD 与 EntryPoint 的区别

ENTRYPOINT 容器启动后执行的命令,让容器执行表现的像一个可执行程序一 样,与 CMD 的 区 别 是 不 可 以 被 docker run 覆 盖 , 会 把 docker run 后 面 的 参 数 当 作 传 递 给 ENTRYPOINT 指令的参数。

Dockerfile 中只能指定一个 ENTRYPOINT,如果指定了很多,只 有 最 后 一 个 有 效 。 docker run 命 令 的 -entrypoint 参 数 可 以 把 指 定 的 参 数 继 续 传 递 给 ENTRYPOINT

组合使用 ENTRYPOINT 和 CMD, ENTRYPOINT 指定默认的运行命令, CMD 指定默认的运行参数

多个 From 指令如何使用

多个 FROM 指令并不是为了生成多根的层关系,最后生成的镜像,仍以最后一条 FROM 为准,之前的 FROM 会被抛弃,那么之前的 FROM 又有什么意义呢? 每一条 FROM 指令都是一个构建阶段,多条 FROM 就是多阶段构建,虽然最后 生成的镜像只能是最后一个阶段的结果,但是,能够将前置阶段中的文件拷贝到 后边的阶段中,这就是多阶段构建的最大意义。 最大的使用场景是将编译环境和运行环境分离。

快照和 dockerfile 制作镜像有什么区别?

等同于为什么要使用 Dockerfile。

什么是空悬镜像(dangling )

仓库名、标签均为 的镜像被称为虚悬镜像,一般来说,虚悬镜像已经失去了存 在的价值,是可以随意删除的。

造成虚悬镜像的原因:

原因一: 原本有镜像名和标签的镜像,发布了新版本后,重新 docker pull *** 时,旧的镜像名 被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消;

原因二: docker build 同样可以导致这种现象。比如用 dockerfile1 构建了个镜像 tnone1:v1,又 用另外一个 Dockerfile2 构建了一个镜像 tnone1:v1,这样之前的那个镜像就会变成空 悬镜像。

可以用下面的命令专门显示这类镜像:

docker image ls -f dangling=true
中间层镜像是什么?

为了加速镜像构建、重复利用资源,Docker 会利用 中间层镜像。所以在使用一段时间 后,可能会看到一些依赖的中间层镜像。默认的 docker image ls 列表中只会显示 顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加 -a 参数。

docker image ls -a

这样会看到很多无标签的镜像,与之前的虚悬镜像不同,这些无标签的镜像很多都是 中间层镜像,是其它镜像所依赖的镜像。这些无标签镜像不应该删除,否则会导致上 层镜像因为依赖丢失而出错。实际上,这些镜像也没必要删除,因为之前说过,相同 的层只会存一遍,而这些镜像是别的镜像的依赖,因此并不会因为它们被列出来而多 存了一份,无论如何你也会需要它们。只要删除那些依赖它们的镜像后,这些依赖的 中间层镜像也会被连带删除。

Docker 镜像原理

docker 是操作系统层的虚拟化,所以 docker 镜像的本质是在模拟操作系统。我们先看 下操作系统是什么。

操作系统基础

操作系统由:进程调度子系统、进程通信子系统、内存管理子系统、设备管理子系统、 比特就业课 文件管理子系统、网络通信子系统、作业控制子系统组成。

Linux 的文件管理子系统由 bootfs 和 rootfs 组成。

(1). bootfs:要包含 bootloader 和 kernel, bootloader 主要是引导加载 kernel, Linux 刚 启动时会加载 bootfs 文件系统,在 Docker 镜像的最底层是引导文件系统 bootfs。这 一层与我们典型的 Linux/Unix 系统是一样的,包含 boot 加载器和内核。当 boot 加载 完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs 转交给内核,此时 系统也会卸载 bootfs。

(2). rootfs: 在 bootfs 之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等 标准目录和文件。rootfs 就是各种不同的操作系统发行版,比如 Ubuntu,Centos 等等。

在这里插入图片描述

Union FS(联合文件系统

联合文件系统(Union File System),2004 年由纽约州立大学开发,它可以把多个 目录内容联合挂载到同一个目录下,而目录的物理位置是分开的。UnionFS 可以把只 读和可读写文件系统合并在一起,具有写时复制功能,允许只读文件系统的修改可以 保存到可写文件系统当中。

UnionFS(联合文件系统)是一种分层、轻量级并且高性能的文件系统,它支持对 文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚 拟文件系统下。UnionFS 是一种为 Linux,FreeBSD 和 NetBSD 操作系统设计的把其 他文件系统联合到一个联合挂载点的文件系统服务。它使用 branch 把不同文件系统的 文件和目录“透明地”覆盖,形成一个单一一致的文件系统。这些 branches 或者是 read-only 或者是 read-write 的,所以当对这个虚拟后的联合文件系统进行写操作的时 候,系统是真正写到了一个新的文件中。看起来这个虚拟后的联合文件系统是可以对 任何文件进行操作的,但是其实它并没有改变原来的文件,这是因为 unionfs 用到了一 个重要的资管管理技术叫写时复制。

写时复制(copy-on-write,下文简称 CoW),也叫隐式共享,是一种对可修改资 比特就业课 源实现高效复制的资源管理技术。它的思想是,如果一个资源是重复的,但没有任何 修改,这时候并不需要立即创建一个新的资源;这个资源可以被新旧实例共享。创建 新资源发生在第一次写操作,也就是对资源进行修改的时候。通过这种资源共享的方 式,可以显著地减少未修改资源复制带来的消耗,但是也会在进行资源修改的时候增 加小部分的开销。

再看 Docker 镜像是什么

image 里面是一层层文件系统 Union FS。联合文件系统,可以将几层目录挂载到 一起,形成一个虚拟文件系统。虚拟文件系统的目录结构就像普通 linux 的目录结构一 样,docker 通过这些文件再加上宿主机的内核提供了一个 linux 的虚拟环境。 每一层文件系统我们叫做一层 layer,联合文件系统可以对每一层文件系统设置三 种权限,只读(readonly)、读写(readwrite)和写出(whiteout-able),但是 docker 镜像中每一层文件系统都是只读的。 构建镜像的时候,从一个最基本的操作系统开始,每个构建的操作都相当于做一层 的修改,增加了一层文件系统。一层层往上叠加,上层的修改会覆盖底层该位置的可 见性,这也很容易理解,就像上层把底层遮住了一样。当你使用的时候,你只会看到 一个完全的整体,你不知道里面有几层,也不清楚每一层所做的修改是什么。

在这里插入图片描述

可以看到镜像分层结构有以下特性 (1)镜像共享宿主机的 kernel (2)base 镜像是 linux 的最小发行版 (3)同一个 docker 主机支持不同的 Linux 发行版 比特就业课 (4)采用分层结构,可以上层引用下层,最大化的共享资源 (5)容器层位于可写层,采用 cow 技术进行修改,该层仅仅保持变化的部分,并不 修改镜像下面的部分 (6)容器层以下都是只读层 (7)docker 从上到下找文件

镜像实现原理
Docker 分层存储实现原理

docker 镜像技术的基础是联合文件系统(UnionFS),其文件系统是分层的。

目前 docker 支持的联合文件系统有很多种,包括:AUFS、overlay、overlay2、 DeviceMapper、VSF 等。

inux 中各发行版实现的 UnionFS 各不相同,所以 docker 在不同 linux 发行版中使用 的也不同。通过 docker info 命令可以查看当前系统所使用哪种 UnionFS

overlay2 是 overlay 的升级版,官方推荐,更加稳定,而新版的 docker 默认也是这个 驱动,linux 的内核 4.0 以上或者或使用 3.10.0-514 或更高版本内核的 RHEL 或 CentOS。

Union FS 的原理

docker 镜像由多个只读层叠加面成,启动容器时,docker 会加载只读镜像层并在 镜像栈顶部加一个读写层;

如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下 面的只读层复制到读写层,该文件版本仍然存在,只是已经被读写层中该文件的副本 所隐藏,此即“写时复制(COW)”机制。

如果一个文件在最底层是可见的,如果在 layer1 上标记为删除,最高的层是用户看到 的 Layer2 的层,在 layer0 上的文件,在 layer2 上可以删除,但是只是标记删除,用 户是不可见的,总之在到达最顶层之前,把它标记来删除,对于最上层的用户是不可 见的,当标记一删除,只有用户在最上层建一个同名一样的文件,才是可见的。

overlay2 实现

OverlayFS 将单个 Linux 主机上的两个目录合并成一个目录。这些目录被称为层,统 一过程被称为联合挂载。

OverlayFS 底层目录称为 lowerdir, 高层目录称为 upperdir,合并统一视图称为 merged

lowerdir 层

其中 lowerdir 是只读的镜像层(image layer),其中就包含 bootfs/rootfs 层, bootfs(boot file system)主要包含 bootloader 和 kernel,bootloader 主要是引导加载 kernel,当 boot 成功 kernel 被加载到内存中,bootfs 就被 umount 了,rootfs(root file system)包含的就是典型 Linux 系统中的/dev、/proc、/bin、/etc 等标准目录。

upperdir 层

upper 是容器的读写层,采用了 CoW(写时复制)机制,只有对文件进行修改才会将文件拷 贝到 upper 层,之后所有的修改操作都会对 upper 层的副本进行修改。upperdir 层是 lowerdir 的上一层,只有这一层可读可写的,其实就是 Container 层,在启动一个容器 的时候会在最后的 image 层的上一层自动创建,所有对容器数据的更改都会发生在这 一层。

workdir 层

它的作用是充当一个中间层的作用,每当对 upper 层里面的副本进行修改时,会先当到 workdir,然后再从 workdir 移动 upper 层

merged 层

是一个统一图层,从 mergedir 可以看到 lower,upper,workdir 中所有数据的整合,整 个容器展现出来的就是 mergedir 层.merged 层就是联合挂载层,也就是给用户暴露 的统一视觉,将 image 层和 container 层结合,就如最上边的图中描述一致,同一文 件,在此层会展示离它最近的层级里的文件内容,或者可以理解为,只要 container 层 中有此文件,便展示 container 层中的文件内容,若 container 层中没有,则展示 image 层中的。

在这里插入图片描述

1、读: 如果文件在 upperdir(容器)层,直接读取文件; 如果文件不在 upperdir(容器)层,则从镜像层(lowerdir)读取;

2、写: 首次写入:如果 upperdir 中不存在,overlay 和 overlay2 执行 copy_up 操作,把文件 从 lowdir 拷贝到 upperdir 中,由于 overlayfs 是文件级别的(即使只有很少的一点修改, 也会产生 copy_up 的动作),后续对同一文件的再次写入操作将对已经复制到容器层的 文件副本进行修改,这也就是常常说的写时复制(copy-on-write)。 删除文件或目录:当文件被删除时,在容器层(upperdir)创建 whiteout 文件,镜像层 (lowerdir)的文件是不会被删除的,因为它们是只读的,但 whiteout 文件会阻止它们显 示,当目录被删除时,在容器层(upperdir)一个不透明的目录,这个和上边的 whiteout 的原理一样,组织用户继续访问,image 层不会发生改变

3、注意事项 copy_up 操作只发生在文件首次写入,以后都是只修改副本。 比特就业课 容器层的文件删除只是一个“障眼法”,是靠 whiteout 文件将其遮挡,image 层并没有删 除,这也就是为什么使用 docker commit 提交保存的镜像会越来越大,无论在容器层 怎么删除数据,image 层都不会改变。

操作实战
镜像分层存储实战
overlay 文件系统工作实战

准备目录:

mkdir -p /data/myworkdir/fs
cd /data/myworkdir/fs
mkdir upper lower merged work

准备文件:

echo "in lower" > lower/in_lower.txt
echo "in upper" > upper/in_upper.txt
echo "In both. from lower" > lower/in_both.txt
echo "In both. from upper" > upper/in_both.txt

挂载overlay目录:

mount -t overlay overlay -o lowerdir=./lower,upperdir=./upper,workdir=./work ./merged

通过df -h 查看挂载目录:

df -h

在这里插入图片描述

merged只是可视层,不存储文件,看到的文件都是upper和lower目录里的,只是做了一个可视化。

upper:可读修改层,当merged层修改了文件内容,实际上修改的只有upper目录的文件;当merged层删除了文件,实际上是在upper目录改了一下文件的属性,标记为不存在

lower:只读层,真正的Base Image

修改文件:

cd ./merged/
vi in_lower.txt
#修改的内容 in lower! after edit!

删除文件:

rm in_lower.txt

在这里插入图片描述

可以看到,删除的文件,会做了特殊标记

Docker 卷原理
Docker 卷机制

Docker 又是如何做到把一个宿主机上的目录或者文件,挂载到容器里面去呢?

当容器进程被创建之后,尽管开启了 Mount Namespace,但是在它执行 chroot (chroot 就是可以改变某进程的根目录,使这个程序不能访问目录之外的其他目录, 这个跟我们在一个容器中是很相似的)之前,容器进程一直可以看到宿主机上的整个 文件系统。

而宿主机上的文件系统,也自然包括了我们要使用的容器镜像。这个镜像的各个层, 保存在 /var/lib/docker/overlay2/{layer id}/diff 目录下,在容器进程启动后,它们会被联 合挂载在 /var/lib/docker/{layerid}/merged/ 目录中,这样容器所需的 rootfs 就准备好了。

所以,我们只需要在 rootfs 准备好之后,在执行 chroot 之前,把 Volume 指定的宿主 机目录(比如 /home 目录),挂载到指定的容器目录(比如 /test 目录)在宿主机上对 应的目录(即 /var/lib/docker/aufs/mnt/[可读写层 ID]/test)上,这个 Volume 的挂载工 作就完成了。

由于执行这个挂载操作时,“容器进程”已经创建了,也就意味着此时 Mount Namespace 已经开启了。所以,这个挂载事件只在这个容器里可见。你在宿主机上, 是看不见容器内部的这个挂载点的。这就保证了容器的隔离性不会被Volume打破

操作实战
实战一: mount bind

通过 mount --bind 命令来将两个目录连接起来,mount --bind 命令是将前一个目录挂 载到后一个目录上,所有对后一个目录的访问其实都是对前一个目录的访问。可以理 解为硬链接。

准备目录:

mkdir -p /data/myworkdir/mount/data1
mkdir -p /data/myworkdir/mount/data2

准备文件:

echo "Hello My bit" > /data/myworkdir/mount/data1/testfile.txt

绑定挂载目录:

mount --bind /data/myworkdir/mount/data1 /data/myworkdir/mount/data2

调用tree命令查看

tree ./

在这里插入图片描述

可以发现data2目录多了一个testfile.txt,但是我们并没有拷贝文件。data2目录里的实际上文件是data1目录里的,只是修改了一下文件指针指向而已

修改文件:

#进入到mount目录
vi ./data1/testfile.txt

查看data2目录里文件的内容:

cat ./data2/testfile.txt

在这里插入图片描述

Docker 卷深度思考

容器的镜像操作,比如 docker commit,都是发生在宿主机空间的。而由于 Mount Namespace 的隔离作用,宿主机并不知道这个绑定挂载的存在。所以,在宿主机看来, 容器中可读写层的 /test 目录(/var/lib/docker/overlay2/{layerid}/[可读写层 ID]/test), 始终是空的。在宿主机的眼里 /test 的 inode 就是原本没有重定向的 inode,你所有的 修改都不在这个文件下。 不过,由于 Docker 一开始还是要创建 /test 这个目录作为挂载点,所以执行了 docker commit 之后,你会发现新产生的镜像里,会多出来一个空的 /test 目录。

镜像 = 环境(静态),卷 = 业务数据(动态),分层隔离是容器标准设计思想;

Docker 网络原理
什么是虚拟网卡

虚拟网卡(又称虚拟网络适配器),即用软件模拟网络环境,模拟网络适配器。简单来 说就是软件模拟的网卡。

tap/tun 虚拟了一套网络接口,这套接口和物理的接口无任何区别,可以配置 IP, 可以路由流量,不同的是,它的流量只在主机内流通。

tun 和 tap 是两个相对独立的虚拟网络设备,其中 tap 模拟了以太网设备,操作二 层数据包(以太帧),tun 则模拟了网络层设备,操作三层数据包(IP 报文)。

使用 tun/tap 设备的目的是实现把来自协议栈的数据包先交由某个打开了 /dev/net/tun 字符设备的用户进程处理后,再把数据包重新发回到链路中。你可以通俗 地将它理解为这块虚拟化网卡驱动一端连接着网络协议栈,另一端连接着用户态程序, 而普通的网卡驱动则是一端连接着网络协议栈,另一端连接着物理网卡。

最典型的 VPN 应用程序为例,程序发送给 tun 设备的数据包

在这里插入图片描述

应用程序通过 tun 设备对外发送数据包后,tun 设备,便会把数据包通过字符设备 发送给 VPN 程序,VPN 收到数据包,会修改后再重新封装成新报文,譬如数据包原 本是发送给 A 地址的,VPN 把整个包进行加密,然后作为报文体,封装到另一个发送 给 B 地址的新数据包当中。然后通过协议栈发送到物理网卡发送出去。

使用 tun/tap 设备传输数据需要经过两次协议栈,不可避免地会有一定的性能损耗, 所以引入了新的网卡实现方式veth。

虚拟网卡实战tun/tap:
基础命令

添加网卡:

# 创建 tap
ip tuntap add dev tap0 mode tap
# 创建 tun
ip tuntap add dev tun0 mode tun

删除网卡:

# 删除 tap
ip tuntap del dev tap0 mode tap
# 删除 tun
ip tuntap del dev tun0 mode tun

激活网卡:

ip link set tun0 up

设置 ip:

ip addr add 10.5.0.1/24 dev tun0

查看帮助:

ip tuntap help
虚拟网卡实战veth:

在 Linux Kernel 2.6 版本,Linux 开始支持网络名空间隔离的同时,也提供了专门的虚 拟以太网(Virtual Ethernet,习惯简写做 veth)让两个隔离的网络名称空间之间可以 互相通信。

直接把 veth 比喻成是虚拟网卡其实并不十分准确,如果要和物理设备类比,它应该相 当于由交叉网线连接的一对物理网卡。

veth 实际上不是一个设备,而是一对设备,因而也常被称作 veth pair。要使用 veth, 必须在两个独立的网络名称空间中进行才有意义,因为 veth pair 是一端连着协议栈, 另一端彼此相连的,在 veth 设备的其中一端输入数据,这些数据就会从设备的另外一 端原样不变地流出。

在这里插入图片描述

veth 通信不需要反复多次经过网络协议栈,这让 veth 比起 tap/tun 具有更好的性能。 veth 实现了点对点的虚拟连接,可以通过 veth 连接两个 namespace,如果我们需要 将 3 个或者多个 namespace 接入同一个二层网络时,就不能只使用 veth 了。在物理 网络中,如果需要连接多个主机,我们会使用网桥,或者又称为交换机。Linux 也提供 了网桥的虚拟实现。

基础命令:

veth 操作:

# 添加 veth
ip link add <veth name> type veth peer name <peer name>
# 删除 veth
ip link delete <veth name>
# 查看 veth
ip link show

命名空间操作:

#添加 ns
ip netns add <name>
#删除 ns
ip netns del <name>
#执行命令
ip netns exec <name> <cmd>
#遍历 ns
ip netns list
操作实战:

创建netns1和netns2命名空间;创建veth11和veth12虚拟网卡(veth)并各自放在netns1和netns2中,然后激活,设置ip地址,最后测试能否跨命名空间通信。

创建命名空间:

ip netns add netns1
ip netns add netns2

创建veth网卡:

ip link add veth11 type veth peer name veth12

设置命名空间:

ip link set veth11 netns netns1
ip link set veth12 netns netns2

激活网卡:

ip netns exec netns1 ip link set veth11 up
ip netns exec netns2 ip link set veth12 up

设置ip地址:

ip netns exec netns1 ip addr add 10.5.0.1/24 dev veth11
ip netns exec netns2 ip addr add 10.5.0.2/24 dev veth12

测试通信:

ip netns exec netns1 ping 10.5.0.2
ip netns exec netns2 ping 10.5.0.1
虚拟交换机:

使用 veth pair 将两个隔离的 netns 连接在了一起,在现实世界里等同于用一根网线把两 台电脑连接在了一起,但是在现实世界里往往很少会有人这样使用。因为一台设备不 仅仅只需要和另一台设备通信,它需要和很多很多的网络设备进行通信,如果还使用 这样的方式,需要十分复杂的网络接线,并且现实世界中的普通网络设备也没有那么 多网络接口。

那么,想要让某一台设备和很多网络设备都可以通信需要如何去做呢?在我们的日常 生活中,除了手机和电脑,最常见的网络设备就是路由器了,我们的手机连上 WI-FI, 电脑插到路由器上,等待从路由器的 DHCP 服务器上获取到 IP,他们就可以相互通信 了,这便是路由器的二层交换功能在工作。Linux Bridge 最主要的功能就是二层交换, 是对现实世界二层交换机的模拟。

Linux Bridge ,由 brctl 命令创建和管理。Linux Bridge 创建以后,真实的物理设备 (如 eth0)抑或是虚拟的设备(veth 或者 tap)都能与 Linux Bridge 配合工作。

在这里插入图片描述

基础命令:

安装方式:

# ubuntu
apt-get install -y bridge-utils
# centos
yum install -y bridge-utils

新建一个网桥:

brctl addbr <bridge>

添加一个设备(例如 eth0)到网桥:

brctl addif <bridge> eth0

显示当前存在的网桥及其所连接的网络端口:

brctl show

启动网桥:

ip link set <bridge> up

删除网桥,需要先关闭它:

ip link set <bridge> down
brctl delbr <bridge

或者使用 ip link del 命令直接删除网桥:

ip link del <bridge>
操作实战:

我们创建三个 netns,三对 veth pair,分别一端在 netns 中,另一端连接在网桥上。

拓扑图:

在这里插入图片描述

深入理解bridge网络:

Bridge 桥接模式的实现步骤主要如下:

  1. Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备,假 设为 veth0 和 veth1。而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报 文,都会将报文传输给另一方。
  2. Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。保证 宿主机的网络报文可以发往 veth0;
  3. Docker Daemon 将 veth1 添加到 Docker Container 所属的 namespace 下,并被 改名为 eth0。如此一来,保证宿主机的网络报文若发往 veth0,则立即会被 eth0 接收, 实现宿主机到 Docker Container 网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性。

在这里插入图片描述

iptables:

iptables 组成 Linux 平台下的包过滤防火墙,与大多数的 Linux 软件一样,这个包过 滤防火墙是免费的,它可以代替昂贵的商业防火墙解决方案,完成封包过滤、封包重 定向和网络地址转换等功能。

-t 指定表名,在 iptables 中,有四张表:filter:这里面的链条,规则,可以决定 一个数据包是否可以到达目标进程端口;mangle: 这里面的链条,规则,可以修改数 据包的内容,比如 ttl;nat:这里面的链条,规则,可以修改源和目标的 ip 地址,从而 进行包路由;raw:这里面的链条,规则,能基于数据包的状态进行规则设定

-n 使用数字形式(numeric)显示输出结果

-v 查看规则表详细信息(verbose)的信息

-L 列出(list)指定链中所有的规则进行查看

nsenter:

nsenter 命令是一个可以在指定进程的命名空间下运行指定程序的命令。它位于 utillinux 包中。一个最典型的用途就是进入容器的网络命令空间。相当多的容器为了轻量 级,是不包含较为基础的命令的,比如说 ip address,ping,telnet,ss,tcpdump 等 等命令,这就给调试容器网络带来相当大的困扰:只能通过 docker inspect ContainerID 命令获取到容器 IP,以及无法测试和其他网络的连通性。这时就可以使 用 nsenter 命令仅进入该容器的网络命名空间,使用宿主机的命令调试容器网络。

常用参数:

参数 含义
-t, --target 进入目标进程的命名空间
-i, --ipc[=] 进入 IPC 空间
-m, --mount[=] 进入 Mount 空间
-n, --net[=] 进入 Net 空间
-p, --pid[=] 进入 Pid 空间
-u, --uts[=] 进入 UTS 空间
U, --user[=] 进入用户空间
-V, --version 版本查看

ip netns list 查找 docker 网络命名空间

docker 使用 namespace 实现容器网络,但是使用 ip netns 命令却无法在主机上看到 任何 docker 容器的 network namespace,这是因为默认 docker 把创建的网络命名空 间链接文件隐藏起来了。

ip netns 默认是去检查/var/run/netns 目录的。而 Docker 容器对应的 ns 信息记录到了 /var/run/docker/netns 目录。所以 ip netns 查出来就是空的

nsenter --net=/var/run/docker/netns/0d099d3eb9d6 sh
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐