Docker
为什么使用docker
因为深刻理解到一句话:“这个程序可以在我的电脑运行”,但是就是在其他电脑上运行不上,
Docker为什么会出现
在产品开发过程中,环境的配置是十分麻烦的,比如一个项目(redis,MySQL),在不同的人手上,就要重新配置一遍环境,然后就想打包项目能不能带上环境安装打包
个人感觉docker过程就像一个安卓应用从开发到可以在手机上运行的过程:
在编写安卓应用的时候是用Java或者其他种类的语言来编写,容然后打包成为一个以**.apk**结尾的包,发布到应用商店,然后需要使用的人从应用商店下载这个以**.apk**结尾的安装包,安装就可以使用(Java代码在手机上是不可以运行的,但是通过一系列的打包成为在android环境中可以运行的**apk**安装包)
流程:Java -- apk -- (应用商店)-- 个人下载使用apk -- 下载安装就可以使用
所以docker的流程就像这样:
(编写的项目代码 -- (env)需要的环境 )-- 打包项目带上环境 (镜像(image))-- push到docker商店 (docker hub) -- 下载我们发布的镜像 -- 直接运行(容器 container)
就像docker的图标一样,采用隔离的机制,避免了在虚拟机中的端口冲突问题(在docker中可以可以使端口的映射来解决端口的问题)
Docker的历史
2010年,美国的几个it年轻人,成立了一家公司dotcloud,是关于一些虚拟机有关的容器技术,
他们将自己的容器化技术命名为docker,刚开始的时候docker并不出名,2013年通过开源,越来越多的人知道了docker的优点
2014年,docker 1.0 发布,因为十分的轻巧,所以非常火
在容器化技术出现之前,都是使用的虚拟化技术,
在windows中,安装一个vmware,可以虚拟出一个电脑或者多台电脑,但是笨重
vm:linux centos 原生镜像,隔离 需要多个虚拟机 一个虚拟机至少需要几个G,启动时间在分钟级
docker: 隔离,镜像(最核心的环境可能只需要几M的内存,秒级启动)
docker 网址:www.docker.com
在首页的最下面有关于docker的文档 :https://docs.docker.com
docker 仓库:https://hub.docker.com
docker能做什么

比较docker和虚拟机的不同
- 就像在上图中,关于虚拟机的原理,是在内核的基础上虚拟出我们需要的环境。我们需要分配内存,需要配置cpu,在上图中,有多个APP,但是他们的所需要的环境是不一样的,所以在配置环境的时候,将所有的环境配置在共同的lib中,造成了资源的浪费和冗余,以及端口之间的冲突。
- 但是在docker中,docker 相对于虚拟机来说,不是在宿主机上虚拟出一套硬件后在虚拟出一个操作系统,而是在宿主机上直接运行docker容器中的进程,形成相应的容器,在容器之中运行自己的APP,每个容器之间相互隔离,都有一个属于自己的文件系统,互不影响,相对来说,docker的体积会更轻.

- docker中的镜像是分层的,比如上图中的Ubuntu刚开始是72.7 mb,但是自己可以在这个基础的版本上加入自己想要加入的东西,比如MySQL。
关于docker

image(镜像):
就好像是一个模板,通过这个模板来创建容器,一个镜像可以创建多个容器,(最终的项目代码运行就是在容器中的),就像是基本类和由这个类new的对象,image就是基本类,然后new了几个对象,这些对象就像是container,实际上使用的就是这些新的对象
container(容器)
通过镜像来创建,可以看做一合简易的Linux系统,基本操作:启动,停止,删除
(repository)仓库
存放镜像的地方,默认是国外的docker hub
Docker安装
docker网站里面有详细的步骤,推荐使用阿里云的镜像加速。
使用docker version 查看是否安装成功
使用 docker run hello-world 测试
卸载docker
卸载依赖
yum remove docker-ce-cli containerd.io
卸载资源
rm -rf /var/lib/docker docker的默认工作路径
了解一下镜像run hello-world流程
在敲下run命名后,

底层原理
docker是怎么工作的?
docker是一个cs结构的系统,docker的守护进程运行在主机上,通过socket从客户端访问
DockerServer 接收到Docker-client的指令,就会执行这个命令

相比较虚拟机来说,docker的容器少了一个Hypervisor ,少了一个抽象层,所以,新建一个容器的时候,不需要像虚拟机一样重新加载一个操作系统内核,就避免了引导过程(就像以前的老电脑开机时候一行一行的显示状态码一样,这是个很长的过程),docker是利用宿主机的操作系统,
容器内部机制
容器内部的原理就大概像命名空间一样,在Linux操作系统中,有这么一个和命名空间类似的功能,将全局资源共享到进程中,如果将这些资源包装在命名空间中,使得一些资源只对同一命名空间的进程可见。
就比如,我有一块磁盘,放在命名空间为PTD的命名空间中,那么在其他比如PSD的命名空间的进程就不可以查看或者访问我在命名空间为PTD中的磁盘。当然,PTD中的进程也不可以访问PSD 中的资源。为全局资源提供了一种虚拟化和隔离。
Docker,就是这样,每个容器在自己的‘命名空间’中运行,但是和其他容器一起使用操作系统的内核,隔离是因为内核知道根据命名空间分配相应的进程。
Docker的常用命令
帮助命令
docker version 版本信息
docker info 显示docker的系统信息,包括镜像和容器的数量
docker 命令-- help 命令的帮助命令
在 https://docs.docker.com 下面的 reference 有docker的全部命令
镜像命令
docker images 查看本地的所有的镜像,有仓库名,版本信息,镜像ID,创建时间,镜像大小五个属性
docker search 搜索镜像
docker pull 下载镜像
docker rmi 删除镜像
docker rmi -f $(docker images -ap) 删除全部的镜像
容器命令
新建一个容器并启动
docker run [option] image
docker run --rm [images ]. 常用来测试,退出容器就会删掉容器
option 说明
--name='Name' 容器名字 MySQL01 mysql02 用来区分容器
-d 后台方式运行
-it 使用交互方式运行,进入容器查看内容
-p 指定容器的端口 -p 8080:8080 -p 主机端口:容器端口
-P 随机指定端口
docker ps 显示运行的容器
退出容器
exit 直接容器停止并退出
Ctrl + p + q 不停止退出
删除容器
docker rm 容器ID,不能删除正在运行的容器,如果强制删除,rm -f
docker rm -f $(docker ps -aq) 全部删除
启动和停止容器
docker start 容器ID 启动容器
docker restart 容器ID 重启容器
docker stop 容器ID 停止容器
docker kill 容器ID 强制停止容器
volume
使用docker volume --help查看使用幫助
step1:
docker volume create direct_name
step2
docker volume inspect direct_name #get volume location
step3
docker run -d -v direct_name:/home/instance -p 5000:5000 --name rain alert:0.1
常用其他命令
后台启动容器
docker run -d 镜像名
问题:使用docker ps 查看时候,发现容器停止了 ,因为docker使用后台运行,但是必须有一个前台进程,docker发现没有应用,就会自动停止,
查看日志命令
docker logs
shell
docker run -d ubuntu /bin/bash -c "while true;do echo xiaogang;sleep 1;done"
为了使用logs命令,然后在启动ubuntu时候输出
docker logs -ft --tail 10 容器ID
查看容器中的进程信息
docker top [容器ID]
查看镜像的元数据
docker inspect [容器ID]
进入当前正在运行的容器
docker exec -it 容器ID 进入容器后开启一个新的终端
docker attach 容器ID 进入容器正在执行的终端,不会启动新的终端
docker rm -f $(docker ps -aq) 删除所有的容器
拷贝文件到主机上
docker cp
docker cp 容器名:/容器内文件地址 /主机地址
el: 将容器内部的test.java拷贝到主机上,将容器内部的home目录下的test.java拷贝到主机上的home目录下
首先在进入容器内部创建或者找到拷贝的文件,
docker attach 容器名 进入容器
touch file(test.java)
docker cp 容器ID : / home/test.java /home
拷贝是一个手动过程,以后使用 -v volume卷的技术实现拷贝过程
小结
一些例子
安装使用nginx和tomcat
平时使用nginx和tomcat时候的一些部署问题
首先使用docker search 搜索相应的镜像,或者可以在docker的官网里面找到需要的版本,后根据需要下载
然后使用docker run -d --name nginx03 -p 3344:80 nginx 创建相应的容器之后,暴露主机的3344端口给容器的80 端口
最后使用docker exec -it nginx03 /bin/bash 进入创建的容器,比如在tomcat里面的WebApps里面是没有任何东西的,需要使用webapps.dist里面的ROOT里面的文件来实现相应的界面效果,
使用curl localhost:端口号 或者在浏览器里面输入主机 ip:端口号 测试访问
docker镜像
镜像
images是一种轻量级可执行的独立软件包,打包运行环境和基于运行环境开发的软件,包含某个软件所需要的所有的内容,包括代码,库,环境变量和配置文件。
联合文件系统
是一种分层,轻量级并且高性能的文件系统,支持对文件系统的修改作为一次提交来一层层的叠加,将不同的目录挂载到同一个虚拟文件系统下,镜像可以通过分层来继承,但是没有父镜像一说,更多说的是基础镜像,可以根据一个基础的镜像来制作具体应用的镜像
理解:
所有的镜像都起源于一个基础的镜像,当进行修改或者增加新的镜像时候,就会在当前镜像之上,增加新的镜像层
比如说,基于Linux创建一个新的镜像,这是第一层,然后添加Python包,这就是第二层,就是这样一层一层的增加,在不断的增加新的镜像层时候,最后的镜像始终是当前所有镜像的组合
多个Container可以共享基础Image存储,节省存储空间;快速部署 – 如果要部署多个Container,Base Image可以避免多次拷贝,实现快速部署。因为多个Container共享Image,提高多个Container中的进程命中缓存内容的几率。

容器数据卷
数据,在创建一个容器过程中,如果容器被删除,数据就会丢失。那么实现数据持久化就是一个问题。
方式1:直接使用命令挂载
docker run -it -v 主机目录:容器目录

使用docker inspect 容器id
例子:
使用MySQL镜像创建相应的容器之后,如果容器被删除,那么数据库里面的相应数据也会被删除,使用数据卷挂载的技术,使容器的数据在外部也可以进行相应的操作,相当于备份。
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql
在这一行中
-d 表示后台运行容器
-v 进行容器和宿主机之间的挂载
-p 实现端口的暴露
--name 如果要根据一个镜像启动多个容器,那么可以使用--name 对不同的容器之间进行区分

具名和匿名挂载
三种挂载方式:
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /主机路径:容器内部路径 #指定路径挂载
相应的,在挂载路径后面加上ro或者rw ,表示onlyread和readwrite,只读和可读可写
DockerFile
是用来构建docker镜像的文件,命令参数脚本。
构建步骤:
1、编写一个dockerfile文件
2、docker build构建一个镜像
3、docker run 运行镜像
4、docker push 发布镜像(dockershub 阿里云镜像仓库)
官方的镜像中,很多都是基础版本,所以我们需要自己制作自己的镜像
dockerfile构建过程
基础知识 :
每个关键字都是大写的字母
执行顺从上倒下
井号表示注释
每个指令都会创建提交一个新的镜像层,每一行命令都是一层
dockerfile是面向开发的,发布项目,做镜像,就需要dockerfile文件,
docker镜像成为交付的标准。必须要掌握。
dockerfile:构建文件,定义了一切的步骤,源代码
dockerimage:通过dockerfile构建生成的镜像,最终发布和运行的产品
docker容器:容器就是镜像运行起来提供服务
dockerfile的指令
通过使用这些指令,来写自己 的镜像
例子:创建一个自己的nginx
FROM NGINX
MAINTAINER Rain<daigang344@163.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash
通过这个编写的文件构建镜像
docker build-f dockerfile文件路径 -t 镜像名:[tag]
使用docker history 查看更改历史
提交自己的镜像
使用方法和git一样
1、在hub docker https://hub.docker.com/上面注册自己的账号 在本地使用docker login -u 登录 会要求输入自己的密码
2、使用docker push 镜像名 发送到自己的仓库
提交到阿里云镜像仓库
1、登录阿里云, 创建相应的仓库和命名空间
2、相应的步骤阿里云上有
小结
在上图中,使用dockerfile制作一个镜像,命令是docker build 镜像名
使用docker run 启动一个容器使用docker push 发送到远端仓库,使用start stop restart 启动 停止 重启 容器
使用 docker pull 从远端仓库拉取相应的镜像,使用 docker save -o 压缩镜像,使用 docker load 解压缩镜像,tag是镜像的标签,在发布镜像时候会给镜像加上相应的版本,
使用docker commit 提交新的镜像(假设我们在docker中运行了一个Tomcat容器,我们在tomcat容器中做了一些我们自定义的修改,然后我们这个修改的tomcat容器进行commit,这样我们就形成了一个新的自定义镜像 )命令是docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]
关于docker的操作上满这幅图中做了详细的解释
docker 网络
在Linux中,每启动一个docker 容器,都会分配一个IP地址,所有的容器在不指定网络的情况下,都是docker 0路由的,

容器内部的网卡信息


docker 使用的是Linux的桥接技术,宿主机中是一个docker的容器网桥
容器中的网卡都是成对出现的,evth-pair 就是一对虚拟的设备接口,一端连着协议,一端连着彼此,利用这个特性,连接各种虚拟设备,
port # 查看映射端口对应的容器内部源端口
pause # 暂停容器
ps # 猎户容器列表
pull # 从docker镜像源服务器拉取指定镜像或者库镜像
push # 推送指定镜像或者库镜像至docker源服务器
restart # 重启运行的容器
rm # 移除一个或多个容器
rmi # 移除一个或多个镜像 (无容器使用该镜像才可删除,否则需要删除相关容器才可继续或 -f 强制删除)
run # 创建一个新的容器并运行一个命令
save # 保存一个镜像为一个 tar 包【对应 load】
search # 在 docker hub 中搜索镜像
start # 启动容器
stop # 停止容器
tag # 给源中镜像打标签
top # 查看容器中运行的进程信息
unpause # 取消暂停容器
version # 查看 docker版本号
wait # 截取容器停止时的退出状态值
一些基本的命令。
docker images 查看本地镜像
docker run -d --name 容器名(可以是多个) -p 宿主机端口:容器端口 容器名
上一句命令主要是用在部署服务器上面,在一个容器中运行多个服务
自定义网络
查看所有的docker 网络

网络模式
bridge 桥接模式。默认
none 不配置网络
host. share network with host
Container 容器网络联通
测试
docker run -d -P --nama tomcat01 tomcat
docker run -d -P --name tomcat01 --net bridge tomacat
# 自定义网络
# bridge
docker network create --driver bridge --subnet 192.168.0.0/16 --geteway 192.168.0.1 mynet
root@xiaogang:~# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
c99b09dcc450d3ab2d2f6a8bb81c4a5afa0f17d42cfa5718aa5e1a8a5e9e3642
root@xiaogang:~#
root@xiaogang:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
4c696778bfab bridge bridge local
db42b2ce883e host host local
c99b09dcc450 mynet bridge local
0f13dfc2aac3 none null local
root@xiaogang:~#

网络连通

测试 docker01 dao 自定义网络之间的容器连通

root@xiaogang:~# docker network connect mynet tomcat01
将tomcat01 加入到mynet网段中
一个容器两个IP

部署redis集群
docker network create redis --subnet 172.38.0.0/16
for port in $(seq 1 6); do
echo "Creating directory for node-${port}"
mkdir -p /mydata/redis/node-${port}/conf
if [ $? -eq 0 ]; then
echo "Directory created successfully"
else
echo "Failed to create directory"
exit 1
fi
echo "Creating redis.conf for node-${port}"
touch /mydata/redis/node-${port}/conf/redis.conf
if [ $? -eq 0 ]; then
echo "redis.conf created successfully"
else
echo "Failed to create redis.conf"
exit 1
fi
echo "Writing configuration to redis.conf"
cat << EOF > /mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
if [ $? -eq 0 ]; then
echo "Configuration written successfully"
else
echo "Failed to write configuration"
exit 1
fi
done
# 创建容器的脚本
docker run -p 6371:6379 -p 16371:16379 --name redis-1 \
-v /mydata/redis/node-1/data:/data \
-v /mydata/redis/node-1/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.11 redis redis-server /etc/redis/redis.conf
docker run -p 6372:6379 -p 16372:16379 --name redis-2 \
-v /mydata/redis/node-2/data:/data \
-v /mydata/redis/node-2/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.12 redis redis-server /etc/redis/redis.conf
docker run -p 6373:6379 -p 16373:16379 --name redis-3 \
-v /mydata/redis/node-3/data:/data \
-v /mydata/redis/node-3/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.13 redis redis-server /etc/redis/redis.conf
docker run -p 6374:6379 -p 16374:16379 --name redis-4 \
-v /mydata/redis/node-4/data:/data \
-v /mydata/redis/node-4/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.14 redis redis-server /etc/redis/redis.conf
docker run -p 6375:6379 -p 16375:16379 --name redis-5 \
-v /mydata/redis/node-5/data:/data \
-v /mydata/redis/node-5/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.15 redis redis-server /etc/redis/redis.conf
docker run -p 6376:6379 -p 16376:16379 --name redis-6 \
-v /mydata/redis/node-6/data:/data \
-v /mydata/redis/node-6/conf/redis.conf:/etc/redis/redis.conf \
-d --net redis --ip 172.38.0.16 redis redis-server /etc/redis/redis.conf
创建集群
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
# redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379 --cluster-replicas 1
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.38.0.15:6379 to 172.38.0.11:6379
Adding replica 172.38.0.16:6379 to 172.38.0.12:6379
Adding replica 172.38.0.14:6379 to 172.38.0.13:6379
M: e7700cf1bea4a79a1613dcf5f6fd046607738a74 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
M: 1133afbd48c55cb7dde887a5438dc59d1e7038a2 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 741b4a8ac77cd79b7a09f42310ef2771dd2e9adb 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 4a53d12a49b2b4d5a3f8b7cacd6c267d4076eae4 172.38.0.14:6379
replicates 741b4a8ac77cd79b7a09f42310ef2771dd2e9adb
S: 9c336e0b3bd3c6804a3f09bc75561fa7722a87ad 172.38.0.15:6379
replicates e7700cf1bea4a79a1613dcf5f6fd046607738a74
S: fe6c4a3d6fc34330a9ac70ac251c6f83bf1fa32e 172.38.0.16:6379
replicates 1133afbd48c55cb7dde887a5438dc59d1e7038a2
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 172.38.0.11:6379)
M: e7700cf1bea4a79a1613dcf5f6fd046607738a74 172.38.0.11:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
M: 741b4a8ac77cd79b7a09f42310ef2771dd2e9adb 172.38.0.13:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: fe6c4a3d6fc34330a9ac70ac251c6f83bf1fa32e 172.38.0.16:6379
slots: (0 slots) slave
replicates 1133afbd48c55cb7dde887a5438dc59d1e7038a2
S: 4a53d12a49b2b4d5a3f8b7cacd6c267d4076eae4 172.38.0.14:6379
slots: (0 slots) slave
replicates 741b4a8ac77cd79b7a09f42310ef2771dd2e9adb
M: 1133afbd48c55cb7dde887a5438dc59d1e7038a2 172.38.0.12:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 9c336e0b3bd3c6804a3f09bc75561fa7722a87ad 172.38.0.15:6379
slots: (0 slots) slave
replicates e7700cf1bea4a79a1613dcf5f6fd046607738a74
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
# redis-cli -c
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:73
cluster_stats_messages_pong_sent:79
cluster_stats_messages_sent:152
cluster_stats_messages_ping_received:74
cluster_stats_messages_pong_received:73
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:152
127.0.0.1:6379> cluster nodes
741b4a8ac77cd79b7a09f42310ef2771dd2e9adb 172.38.0.13:6379@16379 master - 0 1740718606000 3 connected 10923-16383
fe6c4a3d6fc34330a9ac70ac251c6f83bf1fa32e 172.38.0.16:6379@16379 slave 1133afbd48c55cb7dde887a5438dc59d1e7038a2 0 1740718606000 2 connected
4a53d12a49b2b4d5a3f8b7cacd6c267d4076eae4 172.38.0.14:6379@16379 slave 741b4a8ac77cd79b7a09f42310ef2771dd2e9adb 0 1740718607863 3 connected
e7700cf1bea4a79a1613dcf5f6fd046607738a74 172.38.0.11:6379@16379 myself,master - 0 1740718606000 1 connected 0-5460
1133afbd48c55cb7dde887a5438dc59d1e7038a2 172.38.0.12:6379@16379 master - 0 1740718607000 2 connected 5461-10922
9c336e0b3bd3c6804a3f09bc75561fa7722a87ad 172.38.0.15:6379@16379 slave e7700cf1bea4a79a1613dcf5f6fd046607738a74 0 1740718607000 1 connected
127.0.0.1:6379>
127.0.0.1:6379> set a b
-> Redirected to slot [15495] located at 172.38.0.13:6379对应的容器redis-3停掉
OK
172.38.0.13:6379> get a
Error: Server closed the connection
172.38.0.13:6379> exit
# redis-cli -c
# 在这一步之前将172.38.0.13:6379对应的容器redis-3停掉
127.0.0.1:6379> get a
-> Redirected to slot [15495] located at 172.38.0.14:6379
"b"
# 会发现在172.38.0.14:6379中拿到数据
172.38.0.14:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:7
cluster_my_epoch:7
cluster_stats_messages_ping_sent:458
cluster_stats_messages_pong_sent:452
cluster_stats_messages_meet_sent:1
cluster_stats_messages_auth-req_sent:5
cluster_stats_messages_sent:916
cluster_stats_messages_ping_received:447
cluster_stats_messages_pong_received:458
cluster_stats_messages_fail_received:1
cluster_stats_messages_auth-ack_received:2
cluster_stats_messages_received:908
172.38.0.14:6379> cluster nodes
4a53d12a49b2b4d5a3f8b7cacd6c267d4076eae4 172.38.0.14:6379@16379 myself,master - 0 1740718819000 7 connected 10923-16383
fe6c4a3d6fc34330a9ac70ac251c6f83bf1fa32e 172.38.0.16:6379@16379 slave 1133afbd48c55cb7dde887a5438dc59d1e7038a2 0 1740718818855 2 connected
9c336e0b3bd3c6804a3f09bc75561fa7722a87ad 172.38.0.15:6379@16379 slave e7700cf1bea4a79a1613dcf5f6fd046607738a74 0 1740718818554 1 connected
e7700cf1bea4a79a1613dcf5f6fd046607738a74 172.38.0.11:6379@16379 master - 0 1740718819858 1 connected 0-5460
741b4a8ac77cd79b7a09f42310ef2771dd2e9adb 172.38.0.13:6379@16379 master,fail - 1740718720566 1740718718000 3 connected
1133afbd48c55cb7dde887a5438dc59d1e7038a2 172.38.0.12:6379@16379 master - 0 1740718820561 2 connected 5461-10922
172.38.0.14:6379> get a
"b"
172.38.0.14:6379>