为什么使用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 Raindaigang344@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>