Docker简介

Docker 是一个开放源代码软件,是一个开放平台,用于开发应用、交付(shipping)应用、运行应用。 Docker允许用户将基础设施(Infrastructure)中的应用单独分割出来,形成更小的颗粒(容器),从而提高交付软件的速度。[1]

Docker容器 与虚拟机类似,但原理上,容器是将操作系统层虚拟化,虚拟机则是虚拟化硬件,因此容器更具有便携性、高效地利用服务器。 容器更多的用于表示 软件的一个标准化单元。由于容器的标准化,因此它可以无视基础设施(Infrastructure)的差异,部署到任何一个地方。另外,Docker也为容器提供更强的业界的隔离兼容。[2]

Docker 利用Linux核心中的资源分离机制,例如cgroups,以及Linux核心名字空间(namespaces),来创建独立的容器(containers)。这可以在单一Linux实体下运作,避免引导一个虚拟机造成的额外负担[3]。Linux核心对名字空间的支持完全隔离了工作环境中应用程序的视野,包括行程树、网络、用户ID与挂载文件系统,而核心的cgroup提供资源隔离,包括CPU存储器、block I/O与网络。从0.9版本起,Dockers在使用抽象虚拟是经由libvirtLXC与systemd - nspawn提供界面的基础上,开始包括libcontainer库做为以自己的方式开始直接使用由Linux核心提供的虚拟化的设施。 – Wikipedia

Docker安装与卸载

Docker安装(CentOS)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 因为连接的阿里云服务器,默认root用户,所以未加sudo
$ yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
$ yum install -y yum-utils
$ yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
$ yum install docker-ce docker-ce-cli containerd.io
$ systemctl start docker # 开机自启

Docker卸载

1
2
$ yum remove docker-ce docker-ce-cli containerd.io
$ rm -rf /var/lib/docker

Docker镜像加速

阿里云镜像加速-控制台-容器镜像服务-镜像加速器

Docker常用命令

帮助命令

1
2
3
$ docker version
$ docker --help # 查看帮助命令 如果对某个命令不熟悉 可以 docker [command] --help
# 比如 docker run --help

镜像命令

docker pull的时候具体发生了什么?

1
$ docker images [OPTIONS] [REPOSITORY[:TAG]]
Command Info
docker images 查看所有镜像
docker images java[:tag] 列出与java有关的镜像
docker images --digests 列出摘要信息
docker images --filter 按给定条件过滤,label,before,since,dangling,reference
1
$ docker rmi [OPTIONS] IMAGE [IMAGE...] 删除镜像,同时删除多个镜像时用空格分隔
Command Info
docker rmi -f nginx 强制删除镜像
docker rmi -f $(docker images -a -q) 删除所有镜像
docker rmi $(docker images -f "dangling=true" -q) 组合过滤删除

容器相关命令

Command Info
docker container ls 列出容器
docker stop/start xxxx 停止/启动容器
docker rm xx [yy zz] 删除一个或多个容器
docker rm -f $(docker ps -a) 强制删除所有容器
docker container stats -a 查看容器运行信息
docker exec -it nginx /bin/bash 以交互模式启动容器
1
2
# Run a command in a new container 启动一个新的容器
$ docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
1
2
3
4
5
6
7
8
9
10
11
# -p 端口映射 外部主机端口:容器端口 -P 随机暴露端口
# --name 运行的别名 可以自选
# -v || --volume 挂载卷 外部主机目录:容器内目录 用于数据持久化与数据同步 容器内外的文件操作将会同步
# -e || --env 环境变量
# -d || --detach 脱机模式运行
$ docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
1
2
# 把本地的标准输入输出与正在运行的容器进行绑定
$ docker attach [OPTIONS] CONTAINER

其他常用命令

1
2
3
4
5
# 返回 Docker 对象的详细信息
$ docker inspect [OPTIONS] NAME|ID [NAME|ID...]
# -a || --author, -m || message 将镜像提交到本地 与git commit 类似
# 根据容器的变动创建一个新的镜像
$ docker commit -a="raymond" -m="commit msg" 容器ID tomcat:1.0

Docker镜像讲解

镜像是什么?

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件

Docker镜像加载原理

UnionFS(联合文件系统)

UnionFS(联合文件系统):Union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,Union文件系统是Dokcer镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的镜像。

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统加载起来,这样最终的文件系统会包含所有的底层文件和目录。

Docker的存储驱动的实现是基于 Union File System,简称UnionFS,它是一种为Linux 、FreeBSD 和NetBSD 操作系统设计的,把其他文件系统联合到一个联合挂载点的文件系统服务。它用到了一个重要的资源管理技术,叫写时复制。写时复制(copy-on-write),也叫隐式共享,是一种对可修改资源实现高效复制的资源管理技术。对于一个重复资源,若不修改,则无需立刻创建一个新的资源,该资源可以被共享使用。当发生修改的时候,才会创建新资源。这会大大减少对于未修改资源复制的消耗。

pull镜像时分层的文件系统

镜像加载原理

UnionFS文件系统是Docker镜像的基础,镜像可以通过分层来进行继承,基于Base镜像(没有父镜像),可以制作各种具体的应用镜像。Docker的存储驱动有Overlay/Overlay2, AUFS.

镜像加载过程

  • bootfs: 在Docker镜像中最底层是bootfs(boot file sysem)文件系统,bootfs主要包含bootloader和kernel。Linux刚启动时会加载bootfs文件系统,bootloader主要作用是引导加载kernel。在Docker镜像中,bootfs这一层与典型的Linux/Unix系统是一样的,包含bootloader和kernel。当bootloader加载完成之后整个内核都存放在内存中,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
  • rootfs:
    • Docker镜像中用户空间的文件系统是rootfs,包含/dev、/proc、/bin 等目录。对于Base Image来说,底层直接用Host的kernel,自己只需要提供rootfs。而对于一个精简的OS,rootfs的体积可以很小,只需要包含最基本的命令、工具和程序库就可以。
    • 不同Linux发行版的主要区别就是rootfs。比如Ubuntu14.04使用upstart管理服务,apt管理软件包;而CentOS7使用systemd和yum。这些都是用户空间上的区别,Linux kernel差别不大。因此Docker可以同时支持多种发行版的Linux镜像,模拟出多种操作系统环境。
    • 容器只能使用Host的kernel,并且不能修改。所有容器都共用host的kernel,在容器中没办法对kernel升级。如果容器对kernel版本有要求(比如应用只能在某个kernel版本下运行),则不建议用容器,这种场景虚拟机可能更合适。

容器的可写层

当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。所有对容器的改动,无论添加、删除、还是修改文件都只会发生在容器层中。即只有容器层是可写的,容器层下面的所有镜像层都是只读的。其中镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统(UnionFS)。如果不同镜像层中有一个相同路径的文件,比如/a,上层的/a会覆盖下层的/a,也就是说用户只能访问到最上层中的文件/a。在容器层中,用户看到的是一个叠加之后的文件系统。下图是容器可写层的图解。

Why developers love Docker (Part II) | Bigstep Blog

容器可写层的操作

  • 添加文件,在容器中创建文件时,新文件被添加到容器层中。
  • 读取文件,在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,打开并读入内存。
  • 修改文件,在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后再修改。
  • 删除文件,在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。
  • 上面的操作中,只有当需要修改时才复制一份数据,这种特性被称作写时复制(copy-on-write)。可见容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。

容器数据卷

为什么需要数据卷?

数据卷是存在于一个或多个容器中的特定文件或文件夹,这个文件或文件夹以独立于 docker 文件系统的形式存在于宿主机中。数据卷的最大特定是:其生存周期独立于容器的生存周期

  • 在宿主机上不能很方便地访问容器中的文件
  • 无法在多个容器之间共享数据
  • 当容器删除时,容器中产生的数据将丢失。

使用数据卷的场景

  • 在多个容器之间共享数据,多个容器可以同时以只读或者读写的方式挂载同一个数据卷,从而共享数据卷中的数据。
  • 当宿主机不能保证一定存在某个目录或一些固定路径的文件时,使用数据卷可以规避这种限制带来的问题。
  • 当你想把容器中的数据存储在宿主机之外的地方时,比如远程主机上或云存储上。
  • 当你需要把容器数据在不同的宿主机之间备份、恢复或迁移时,数据卷是很好的选择。

使用数据卷

1
2
3
4
5
$ docker run -it -v /data --name centos1 -d centos
$ docker exec -it centos1 /bin/bash
[root@a10ac03e69dd /]# ls # 可以看到创建的 /data目录
# 同步卷
$ docker run -it --volumes-from centos1 --name centos2 -d centos

Docker中的所有卷,默认情况下都在 /var/lib/docker/volumes/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ docker volume create MyVolume
$ docker inspect MyVolume
➜ volumes docker volume --help

Usage: docker volume COMMAND

Manage volumes

Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove all unused local volumes
rm Remove one or more volumes

Run 'docker volume COMMAND --help' for more information on a command.

安装MySQL并进行数据同步

  • MySQL的数据持久化问题
1
2
3
4
$ docker run -d -p 3307:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root --name mysql1 mysql:5.7
$ docker exec -it mysql1 mysql -uroot -proot
mysql> create database test;
# 外部卷将会出现新创建的数据库

具名挂载与匿名挂载

1
2
3
4
5
6
7
8
# 匿名挂载
$ docker run -d --name nginx01 -v /etc/nginx nginx
# 具名挂载
$ docker run -d --name nginx02 -v juming-nginx:/etc/nginx nginx

# -v 容器内路径 # 匿名挂载
# -v 卷名:容器内路径 # 具名挂载
# -v /宿主机路径:容器内路径 # 指定路径挂载

Dockerfile

什么是Dockerfile?

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

镜像构建

以下为 CentOS的官方镜像的Dockerfile,可以看出CentOS是从scratch上添加了centos的压缩包,然后又添加了一些基础的metadata构成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FROM scratch
ADD centos-7-x86_64-docker.tar.xz /

LABEL \
org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20200504" \
org.opencontainers.image.title="CentOS Base Image" \
org.opencontainers.image.vendor="CentOS" \
org.opencontainers.image.licenses="GPL-2.0-only" \
org.opencontainers.image.created="2020-05-04 00:00:00+01:00"

CMD ["/bin/bash"]
Dockerfile构建命令 介绍
FROM 指定基础镜像,必是 Dockerfile 文件中的首条命令。
MAINTAINER 镜像的维护者,姓名+邮箱
RUN 在镜像的构建过程中执行特定的命令,并生成一个中间镜像。
COPY 复制文件
ADD 更高级的复制文件
ENV 设置环境变量
EXPOSE 为构建的镜像设置监听端口,使容器在运行时监听。
VOLUME 用于创建挂载点,即向基于所构建镜像创始的容器添加卷。
WORKDIR 在容器内设置一个工作目录,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。
CMD 用于指定在容器启动时所要执行的命令。RUN 在构建的时候执行,并生成一个新的镜像,CMD 在容器运行的时候执行,在构建时不进行任何操作。
ENTRYPOINT 用于给容器配置一个可执行程序。docker run运行容器时指定的参数都会被传递给 ENTRYPOINT ,且会覆盖 CMD 命令指定的参数。
LABEL 为镜像添加元数据,元数以键值对的形式指定。
ARG 用于指定传递给构建运行时的变量
ONBUILD 用于设置镜像触发器
STOPSIGNAL 用于设置停止容器所要发送的系统调用信号
SHELL 用于设置执行命令(shell式)所使用的的默认 shell 类型
详细介绍 纯洁的微笑

实战1-构建CentOS

1
$ vim Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
FROM centos
MAINTAINER raymond<740567396@qq.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

CMD echo $MYPATH
CMD echo "--end--"
CMD ["/bin/bash"]
1
2
3
4
5
6
7
8
9
10
11
# 如果文件名就是 Dockerfile 的话可以不加 -f Dockerfile 否则 -f 文件名
# 最后有个 . 不可以少
$ docker build -f Dockerfile -t mycentos:0.1 .
$ docker login
# ----Username And Password-----
# 在此要使用 docker tag 将本地镜像名 tag 上 dockerhub 用户名
# 比如我本地的是 mycentos1 我的dockerhub用户名是 raymondzhaodocker
# 那么 tag 成
$ docker tag mycentos:0.1 raymondzhaodocker/mycentos:0.1
# 否则 denied: requested access to the resource is denied
$ docker push raymondzhaodocker/mycentos

实战2-打包Spring Boot

1
2
3
4
5
FROM java:8
COPY target/*.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

小结

img

Docker网络

1
2
3
4
5
$ docker network ls [OPTIONS]
NETWORK ID NAME DRIVER SCOPE
e14287f9fd31 bridge bridge local
642edd192245 host host local
2272acc1f6df none null local

Docker四种网络模式

  • bridge:桥接式
  • host:开放式
  • none: 封闭式
  • Container(join) : 联合挂载式网络模式,是host网络模式的延伸

网络模式

桥接模式

Docker 的默认网络方式

1
2
3
4
5
6
7
8
9
10
11
12
13
$ ip addr # centos 命令
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:16:3e:0c:56:96 brd ff:ff:ff:ff:ff:ff
inet 172.16.139.14/20 brd 172.16.143.255 scope global dynamic eth0
valid_lft 315321918sec preferred_lft 315321918sec
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:69:a1:6d:e0 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever

可以看到三个网卡lo,eth0,docker0,分别为本地环路,ethernet0(以太网),以及Docker进程启动时创建的docker0.

当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上,所以有默认地址172.17.0.0/16的地址。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。

DockerNet

1
2
3
4
5
6
$ docker inspect e14287f9fd31 # 这个是 NETWORK_ID 本节开始前查询出的桥接模式的 id
# 启动一个Nginx容器之后 会发现下面的文件中 Containers 中多一条 nginx的数据
$ docker --name nginx -p 80:80 -d nginx
# 如果使用 ip addr 的话会发现多出一个 ip addr 此处名字 veth5a0f960@if36
37: veth5a0f960@if36: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 82:52:b0:fe:16:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
[
{
"Name": "bridge",
"Id": "e14287f9fd319f2e57dfb2a3f07cfaff266be66edd66fe68848d996a0ebe3710",
"Created": "2020-06-08T09:51:00.898646131+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"43ee792642bfce2e349eb463db14412476b69ac7066e367eeae4cc13aa1289b9": {
"Name": "nginx",
"EndpointID": "3c0badf28429f752f17ac4c2eeb5a94d0f911fcac577557dbebfb77f270e86e4",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]

Host模式

如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的

Container模式

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

自定义网络

1
2
3
4
5
$ docker network create mynet
$ docker inspect mynet # 查看自建的网络信息
# 在自建网络上启动容器
$ docker run -it --name nginx1 -p 81:81 --net mynet -d nginx
$ docker inspect mynet # 再查看自建的网络信息看看有什么变化?

网络连通

还记得之前在默认bridge下创建的容器nginx吗?刚刚在自定义网络mynet中又新建了一个nginx1,如果想让nginxnginx1在同一个网络中该怎么办? --link似乎可以解决掉,但是有更好的方式。

1
2
3
4
5
# docker network connect [OPTIONS] NETWORK CONTAINER
$ docker network connect mynet nginx
# 再查看一下 mynet 就可以发现 Containers 中不止一个 nginx1 了
# 此时 nginx 一个容器,两个 ip
$ docker inspect mynet

实战:Redis集群

启动六个 redis 容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 创建网卡 子网地址可能会有变化 在这个子网下可以容纳 255*255 - 2 个容器
$ docker network create redis-net --subnet 172.16.0.0/16
for port in $(seq 1 6); \
do \
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >/mydata/redis/node-${port}/conf/redis.conf
port 6379
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.16.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} \
-v /mydata/redis/node-${port}/data:/data \
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf \
--net redis-net --ip 172.16.0.1${port} -d redis redis-server /etc/redis/redis.conf \
done

创建三主三从集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 随便进入一个redis 注意 redis 镜像里没有 /bin/bash 只有 /bin/sh
$ docker exec -it redis-1 /bin/sh
$ redis-cli --cluster create 172.16.0.11:6379 172.16.0.12:6379 172.16.0.13:6379 172.16.0.14:6379 172.16.0.15:6379 172.16.0.16:6379 --cluster-replicas 1
# --cluster-replicas 1 的意思是复制一份,6个容器,又需要复制,所以自然是三主三从了。

# 可以看到是以 Slot 插槽方式创建的三个主结点

>>> 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.16.0.15:6379 to 172.16.0.11:6379
Adding replica 172.16.0.16:6379 to 172.16.0.12:6379
Adding replica 172.16.0.14:6379 to 172.16.0.13:6379
M: 4eede4f17800f1896e59658517a7aa85e064374c 172.16.0.11:6379
slots:[0-5460] (5461 slots) master
M: aa60f670a81aa2bcc03457a4d1e8650ee6817c81 172.16.0.12:6379
slots:[5461-10922] (5462 slots) master
M: 59444f77747d6c0f6cdccfeb9ee29bdd09c9de2e 172.16.0.13:6379
slots:[10923-16383] (5461 slots) master
S: 510b0b6f666382c74f3bca61e4018563100f2758 172.16.0.14:6379
replicates 59444f77747d6c0f6cdccfeb9ee29bdd09c9de2e
S: 6e3bdb3e58afd0a23a5acfa30fbc0f82ca15896f 172.16.0.15:6379
replicates 4eede4f17800f1896e59658517a7aa85e064374c
S: 2b59b296014cedfdc6dc12a2e62a70f1ca5f57ee 172.16.0.16:6379
replicates aa60f670a81aa2bcc03457a4d1e8650ee6817c81
Can I set the above configuration? (type 'yes' to accept): yes

# 可以看出 172.16.0.15 是 172.16.0.11 的 slave
# 一定要加 -c 否则是单机
# 随便以交互模式进入一个 redis 容器, redis的 /bin/ 下没有bash,只有 sh
$ docker exec it redis1 /bin/sh
$ redis-cli -c
$ cluster info # 查看集群信息
$ cluster nodes # 查看结点信息
$ exit; # 退出 redis
# 模拟宕机
$ docker stop redis-1
# 此时以交互模式启动 redis-5 查看结点信息 可以看到 redis-1 已宕机
# 但是 get hello 是正常的,因为 slave 顶替了它的 master 的角色
$ get hello
# 如果此时 redis-1 恢复正常 重新上线 则会与 redis-5 的角色互换

Docker Compose

Docker Swarm

评论