docker入门 – 使用docker在单机上搭建redis集群

昨天玩了一下docker,感觉官方Get Started教程里面那个whalesay的例子实在是太渣,没有一点实际用途。解释了image跟container的关系,但完全没有体现container与本地进程的关系。

在实际应用场景上,我感觉docker应该更经常会用在部署nginx、memcache这些无需持久化到本地文件的服务进程上面,一个container就相当于一个进程,随用随起,而且不受本机环境限制。docker应该还可以用在Online Judge这样的在线编程系统上,不用再担心恶意代码搞坏本机系统了。不知道Quantopian这些在线交易策略的后台是不是也用docker给每个用户一个container来跑他们的策略,有点意思嘿嘿。另外docker用来做测试环境也特方便,比如本文要做的redis集群,实际应用肯定是将每个redis-server部署在不同的服务器上,穷酸点的可以部署在不同虚拟机上,但用docker可以很方便的在一台机器起好几个redis-server进程。

1. 下载安装docker

2. 直接去docker hub拉取redis官方镜像

# docker pull redis

使用docker images可以列出当前所有的docker镜像。

屏幕快照 2016-03-18 上午1.03.57

docker镜像与容器的实际存储目录一般都在/var/lib/docker下面,关于docker的底层存储结构,这个应该得花大时间才能有所心得了。

3. 从redis镜像启动一个容器

# docker run -d --name redis redis

-d表示在后台启动容器,并打印容器ID;–name redis表示给该容器指定一个名字(如果不指定,docker会随机指定一个略文艺的名字=。=#);最后一个redis表示容器所依赖的镜像。

运行成功会打印出该容器的长id号。我们可以使用docker ps命令来检查当前在运行的容器。

屏幕快照 2016-03-18 上午1.24.16

docker ps -a 表示打印系统中的所有容器(在运行的,不在运行的)。ps打印出来的数据,CONTAINER ID就是该容器的ID前12位;IMAGE就是容器的镜像;COMMAND就是启动容器后要执行的命令(在容器中),就是在这里启动了容器中的redis;PORTS表示该容器暴露给本机的端口。

检查本机系统的进程。有一个docker daemon进程,顾名思义这是docker的全局守护进程;然后一个redis-server *:6379这个其实就是我们刚刚启动的容器;第二个/user/bin/redis-server 127.0.0.1:6379是我本机原来就有的redis-server(我只是特意开起来做对比的)。所以现在直接敲redis-cli命令,连接的是我本机原来的redis。

屏幕快照 2016-03-18 上午1.54.13

4. 连接容器中的redis-server

那么要想连接到容器中的redis呢?我们已经知道了容器中的redis同样适占用了6379端口号,那么容器ip是多少呢?我们可以使用docker inspect命令来检查容器的基本信息。

屏幕快照 2016-03-18 上午2.20.41

这个IPAddress就是容器的ip。这样,就可以用redis-cli -h 172.17.0.3 -p 6379来连接我们容器中的redis-server了。

屏幕快照 2016-03-18 上午2.29.26

如果你以前用过虚拟机,这时候肯定会觉得容器有点像虚拟机(当然它启动速度比虚拟机要快多了),我们来检查一下本机的ip以及网关。

屏幕快照 2016-03-18 上午2.25.31 屏幕快照 2016-03-18 上午2.26.07

实际上安装完docker之后,docker就会在本机系统建立一个虚拟网卡docker0,并将这个docker0的ip做为一个网关加到本机路由中,之后docker每启动一个容器就给容器分配一个在该网段下的ip地址。

PS:上面这个例子,我们是通过容器ip:容器内端口号的方式来访问容器服务。但这并不是最好的方式,推荐的做法应该是将一个本机端口映射到容器暴露出来的端口号。然后通过这个本机端口来访问容器服务。

5. 重来,启动一个新的redis容器并绑定本机端口

# docker stop redis
# docker run -d --name redis-1 -p 7001:6379 redis

先停止之前运行的redis容器,然后重新从redis镜像中启动一个叫redis-1的容器,第二句中参数-p 7001:6379的意思是将本机的7001端口映射到容器的6379端口。

这是我们再来检查一下进程。

屏幕快照 2016-03-18 上午2.02.18

首先显示docker ps,当前在运行的容器只有redis-1(之前的那个redis已经被stop了)。这次的PORTS列有了变化,表示我们将本机7001端口映射到了容器的6379端口。

然后ps -ef|grep docker,这时候除了原有的docker守护进程外,还多了一个docker-proxy进程,并且这个proxy进程就是由守护进程产生的,后面的参数就表示将本机(host)的7001端口映射到容器(container)172.17.0.2:6379上。

然后ps -ef|grep redis,这时的redis-server *:6379就是我们的容器redis-1。

端口映射后,就可以直接使用redis-cli -p 7001,通过本地端口来访问容器了。

屏幕快照 2016-03-18 上午2.58.17

 

PS: 我第一次使用端口映射的时候,提示错误ptables failed – No chain/target/match by that name。好不容易google到一条解决方法,重启docker服务就好了。但原因没有人说的清楚,总之是刚刚安装完的docker与iptables之间的问题。(github issue

# service docker restart

6. 以slave模式启动第二个redis容器

# docker run -d --name redis-2 -p 7002:6379 redis redis-server --slaveof 172.17.0.2 6379

使用-p将该redis-2容器与本机的7002端口绑定;然后在最后跟了redis-server –slaveof 172.17.0.2 6379,这是容器启动后要执行的命令,表示用–slaveof模式启动容器中的redis-server。这样我们就将redis-2容器中的redis-server作为redis-1的从服务启动了,redis-1作为主服务可读可写,redis-2作为从服务实时备份redis-1,但是可读不可写。

屏幕快照 2016-03-18 上午3.19.34

 

PS: 我参考的这篇文章用Docker构建分布式Redis集群在配置redis主从的时候,使用ssh登录到了容器中,并修改了容器内的文件。这好像是并不值得推荐的方法。因为docker的本意应该就是要封装服务,而不希望服务的内部配置被随便修改。所以大部分的docker镜像,都没有集成ssh,没有集成vi等等。容器的基本配置应该事先在Dockerfile中写好,然后生成镜像,在从镜像转换成容器的时候,可以在docker run的命令行参数中添加一些可选的配置,之后,容器的配置就不应该再有变化了。我想这应该是docker的本意。

 

又PS:redis的主从只能做到实时热备,但无法自动切换,主机挂掉的时候,得手动切换从服务的模式。后来出了redis sentinel,可以用来监控redis集群,做到自动切换主从,但还无法做到主从的ip漂移。所以现在实际应用上,redis集群通常是搭配keepalived来做主从切换的。

 

参考:

https://docs.docker.com/linux/

http://dockone.io/article/180

1 thought on “docker入门 – 使用docker在单机上搭建redis集群”

  1. 谢博主。写得很详细。不过我在实践的过程中遇到一点问题。
    我的环境vagrant的虚拟机Ubuntu 14.04 ,并安装了 Oh-My-Zsh代替了Bash
    实际使用中, 链接Docker的Redis直接运行
    redis-cli -h 172.17.0.1 -p 6379
    会返回
    zsh: command not found redis-cli

    后来查了查相关Docker的使用,使用以下命令链接成功。
    docker run -it redis redis-cli -h 172.17.0.1 -p 7001

    参考资料:
    Docker 安装 Redis http://www.runoob.com/docker/docker-install-redis.html

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top