从零开始 Docker 搭建 Redis 集群

854 阅读8分钟

从零开始 Docker 搭建 Redis 集群

Docker 图片

Docker 安装

Docker 官方安装说明地址

初识 Docker

  • 轻量,简单的建模方式.
  • 为云计算而生.
  • 多平台可以移植,易于构建,易于协作.
  • 基础设施即代码:通过 Docker 的镜像,我们可以将创建过程变为自动和且可重复,而且可以做版本管理.
  • 不可变基础设施:对无状态服务升级,部署会更为容易和简单,我们无需再修改配置,只需要销毁重建即可.
  • 配上 SOA 或 微服务架构,Docker 会更香.

Docker 的结构

Docker Archetecture

解释一下上图的几个关键词:

  • Client:这就是你所看到的 docker 控制终端.
  • DOCKER_HOST:这是 docker 运行的整体运行时上下文
  • Docker daemon:这是 Docker 的守护程序,由他来和 Client 进行通信,获取 Client 的命令,并对 Image Container 等组件进行统一管理.
  • Images:这是一切容器运行的模板或者是基础,容器都是通过 image 来创建的.
  • Containers:由 Image 所创建的运行实例,程序都运行在容器中,一个 Image 可以扩展出 N 个 Container
  • Docker Registry: Docker Image 的存放库,一般情况下都是使用官方的 DockerHub.com.不过,你也可以搭建自己的 Docker Registry 将 Image 管理私有化.

Docker Container

Docker 安装成功后,请你在命令行中使用docker info来确认 Docker 是否正确的安装在本地环境中.

启动你的第一个 Container

docker run -t -i ubuntu /bin/bash

如果,启动成功的话,你会看到你的命令行变成

root@c8fabbcb9f8a:/#

@符号后面的这串字符可能和我的不太一样,他们都是随机生成的容器 ID

你可以尝试在 Container 终端中使用 ps aux,hostname,ip a等命令,来体会容器的便利性.

你还可以在 Container 中安装你所需要的工具,你可以使用 apt-get update && apt-get install vim来给他安装 vim.

请你记住,只要不是在 Image 中所包含的,当 Container 被 Remove 后,这一切都将不复存在.

接着,我们来一个个解释命令是什么意思:

  • docker run :让 docker 启动一个容器的命令.
  • -t:创建一个虚拟的 TTY 终端.
  • -i:代表我们创建的 Container 是会被捕获 STDIN 的.
  • ubuntu:这是我们启动 Container 所对应的 Image,如果需要指定版本的话可以通过 ubuntu:18.04 这种方式.
  • /bin/bash:这是当 Container 启动完成后,就会执行这个命令.

最后,输入exit接上回车来停止这个终端.这时候你会退回到你自己的操作系统终端中,那我们怎么去看刚刚创建的容器去哪里了呢.

输入docker ps -a

你会看到下面这样的内容


CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS                     PORTS                    NAMES
c8fabbcb9f8a        ubuntu                 "/bin/bash"              7 seconds ago       Exited (0) 4 seconds ago                            elated_banzai

我们可以通过这些发现很多有用的信息:

  • CONTAINER ID:我们之前 tty 里面看到的容器 ID.
  • IMAGE: Container 所使用的容器.
  • COMMAND: Container 启动后所使用的命令.
  • CREATED: Container 创建的时间.
  • STATUS: Container 目前的状态.
  • PORTS: Container 所暴露出内部的端口,不过我们这个实例没有,后面的实例中我们会看到的具体的操作和概念.
  • NAMES:Container 的名字,我们可以在 container run 的时候通过--name 指定名字,如果没有指定,那么 docker 会自动生成一个名字.

查看 Container

docker ps,docker container ls这 2 个命令有同样的结果,就是查看当前正在运行的 Containers.如果,需要查看所有的容器,需要在命令后面加上-a

重启已经停止的 Container

docker start elated_banzai或者docker start c8fabbcb9f8a

docker start 命令后面跟上 container 的 name 或者 id 都可以重新启动它.

但是,我们会发现这次启动以后,我们没有进入终端,但是查看最新的状态,他却是 UP 的状态.这是为什么呢

因为,我们这次只是重启了 Container,但是并没有通过 tty 连接到这个容器上去.

那我们还想连接回去怎么办呢,下面我们会讲到

通过 tty 连接运行中的 Container

docker exec -i -t elated_banzai /bin/bash

当然,上面使用 Container name 的地方也可以互换为 Container id.在 docker 命令中,所有指定 Container 的地方,都是 nameid 可以互换的.

这个命令比较简单,与 docker run基本上是类似的,这里就不做展开讲解了.

Container 输出的查看

首先,我们下面的命令,来创建一个叫 log_container 的 Container

docker run -d --name log_container ubuntu /bin/sh -c "while true;do echo hello world; sleep 3; done"

这时,可能你会发现,这条命令里面多了一个 -d的配置,他是用来指定使用 daemon 的模式来运行这个 Container.

我们在最后写了一个死循环的 shell 脚本,让他每 3 秒输出一个 hello world.

回车以后,他只是输出了这个 container 的 id,我们可以通过下面的命令结合 id或者 name来看输出的内容.

docker logs log_container

添加-f来持续查看他的输出,这个和 linux 中的 tail 命令是类似的.

我们还可以添加-t来查看输出的时间戳.

查看 Container 内部的进程

docker top name/id

查看所有 Containers 或者指定的 Container 的统计信息

docker stats,docker stats ContainerName1 ContainerName2...

停止 Container

docker stop name/id

删除 Container

docker rm name/id

这个命令如果不添加-f,那我们只能删除已经停止的容器.

深入查看 Container 信息

docker inspect name/id

这个命令显示的内容比较多,不过大部分都能通过keyname看懂,如果有不清楚的部分请自行查阅相关文档.

Image

查看 Images

docker images,docker image ls

删除 Image

docker images

Dockerfile

Dockerfile 是一个使用基本的 Docker DSL 语法的指令来构建 Docker Image 的文件. 通过,Dockerfile来构建 Image ,更具备重复性,透明性和幂等性.

基础理论基本上介绍的差不多了,那么我们直接上干货.

用 Docker 搭建一个 redis cluster

创建 replica Base Image

首先,我们创建 Redis 的主镜像

$ mkdir redis-replica
$ cd redis-replica
$ touch Dockerfile

Dockerfile:

#使用的母镜像
FROM redis
#维护者信息,这里填的是我自己的邮箱
MAINTAINER crowhyc@163.com
#环境变量,添加以后可以在容器和接下来的命令里面都可以使用
#这个环境变量是用于定义这个镜像的版本和日期
ENV REFESHED_AT 2020-04-01
#用来向基于Image创建的 Container 添加卷
#一个卷是可以存在于一个或多个 Container 内特定的目录,这个目录可以共享数据或对数据进行持久化功能
#下面这个 VOLUME 会在 Container 里面创建这 2 个目录
VOLUME ["/var/lib/redis","/var/log/redis/"]
#基于此 Image 创建的 Container 会对外暴露 6379 接口
#可以通过 docker ports name/id 来查询 Container 暴露接口与本地接口所映射的关系
#也可以在 Container docker run 的时候通过-p 6379:6379 把他绑定到指定的 port 上
EXPOSE 6379
#用于指定一个 Container 启动时要运行的命令,类似于后面会遇到的 RUN 命令
#只是 RUN 指令是指定 Image 被构建时需要运行的命令
#docker run 命令可以覆盖 CMD 命令,这里留空的目的是让 docker run 的时候可以自定义需要执行的命令
#后面介绍到的 ENTRYPOINT 命令则不可以被覆盖
CMD []

保存文件后,我们运行下面的这条命令

docker build -t crowhyc/redis-replica:1.0 .

我们来解释一下这条命令

docker build是用来创建镜像的.

-tcrowhyc/redis-replica:1.0是用来表明后面我们会用这种格式的方式来指定 Image 的名称和版本.

最后,还有一个不起眼的.这个是用来指定 Dockerfile 的地址..是说明 Dockerfile 就在当前目录下

我们不会 run 这个 Image.它是接下来我们 redis-primary 和 redis-slave 的母镜像

创建 redis primary Image

$ mkdir redis-primary
$ cd redis-primary
$ touch Dockerfile
FROM crowhyc/redis-primary:1.0
MAINTAINER crowhyc "crowhyc@163.com"
ENV REFRESHED_AT 2020-04-01
#是 Container 启动以后执行的命令,与 CMD 不同,Container 启动的命令不能覆盖它
ENTRYPOINT ["redis-server","--logfile /var/log/redis/redis-server.log"]

紧接着,我们创建 redis 的主镜像

docker build -t crowhyc/redis-primary:1.0 .

创建 redis slave Image

$ mkdir redis-slave
$ cd redis-slave
$ touch Dockerfile
FROM crowhyc/redis-replica:1.0
MAINTAINER crowhyc "crowhyc@163.com"
ENV REFRESHED_AT 2020-04-01
#这里有一点需要注意的是,我们第三个参数使用的是 redis-primary 当我们启动 primary Container 的时候需要与这个名字相同
ENTRYPOINT ["redis-server","--logfile /var/log/redis/redis-server.log","--slaveof redis-primary 6379"]

启动 redis cluster 并查看状态

创建 Network

docker network create redis-cluster

首先,我们使用上面的命令创建一个新的 network.

docker network是 docker Container 之间用来通信的网络,用户可以自己创建网络,用来组件自己的集群网络.

docker network ls

同样,我们也可以用上面的命令来查看所有的网络

启动 redis-primary

接着,我们使用下面的docker run来启动我们的 primary redis server.

docker run -d -h redis-primary --net redis-cluster --name reids-primary crowhyc/redis-primary:1.0

-h是一个之前没有出现过的新标志,他用来设置 Container 的 hostname,这会覆盖默认的行为即将 Container 主机名设置为 ContainerId.

使用这个标志可以保证redis-primary被作为 Container 的 hostname,并被本地的 DNS 服务正确解析.

--net是用来设定这个 Container 所使用的 Network

查看 redis-primary 日志

我们输入 docker logs 命令去查看日志

docker logs -f redis-primary

稍作等待,你会发现--根本什么都没有...那这是为什么呢?

这是因为我们在做 redis-primary 的时候,让日志记录到了/var/log/redis/redis-server.log 这个文件里面.

接着,我们用更加巧妙的方式去观察类似这种情况下的日志输出.

docker run -it --rm --volumes-from redis-primary ubuntu cat /var/log/redis/redis-server.log

这下我们就能看到对应的 redis-primary 的日志了,如果出现了Ready to accept connections说明 redis-primary已经启动成功.

接着我们来为他启动 2 个 redis-slave

启动多个 redis-slave

docker run -d -h redis-slave01 --net redis-cluster crowhyc/redis-slave:1.0 docker run -d -h redis-slave02 --net redis-cluster crowhyc/redis-slave:1.0

接着我们用上面刚刚学的 docker run 来观察 slave 是否和 primary 建立了联系 docker run -it --rm --volumes-from redis-slave01 ubuntu cat /var/log/redis/redis-server.log docker run -it --rm --volumes-from redis-slave02 ubuntu cat /var/log/redis/redis-server.log

如果,我们能看到类似于MASTER <-> REPLICA sync: Finished with success这样的日志,说明我们 slave 与 primary 已经连接成功了 接下来,我们用 docker 的方式来测试 redis 吧

简要 redis 集群测试

docker run -it --rm --net redis-cluster redis /bin/bash 紧接着我们连接到 redis-primary

redis-cli -h redis-primary

然后,我们 SET 一个值

redis-primary:6379> set "test" 1234

接着,我们再进入 redis-slave01

docker exec -it redis-slave01 /bin/bash

redis-cli -h localhost

get "test"

如果,我们在执行完get命令后看到了"1234"说明我们的 redis 集群已经完成搭建了.