使用Docker Compose和Redis集群4.0的新功能”port-forwarding”来创建Redis集群的方法(适用于任何规模)
无论什么尺寸,都可适应。使用Docker Compose和Redis集群4.0的“端口转发”功能,来创建Redis集群吧!
由于Redis4.0最近开始对普通用户提供服务,Docker用户期待已久的Redis集群功能中的NAT/端口转发也开始得到支持。这使得可以利用Docker的临时端口来运行Redis集群。因此,无需使用”host-mode networking”或”静态分配端口”,就能在Docker上运行Redis集群。
英文原文在这里可用。
从Redis 4.0开始,开始支持Docker网络的封装,使得部署更加动态化。
$ git clone https://github.com/aprice-/redisclustercompose
$ cd redisclustercompose
$ docker-compose up -d --scale redis=9
Github – GitHub
参考Github链接:https://github.com/aprice-/redisclustercompose。
在4.0版本中有哪些变化发生了?
最新新增了三个设置参数。由此,Redis可以控制通知集群其他成员的“IP地址”、“数据端口(例如:6379)”和“集群端口(例如:16379)”。最值得关注的一点是现在可以按端口进行设置。这样一来,就不再受限于按照10000的间隔来设置端口了。
cluster-announce-ip: The IP address to announce.
cluster-announce-port: The data port to announce.
cluster-announce-bus-port: The cluster bus port to announce.
为什么那很重要呢?
Docker的吸引力在于其灵活性,可以动态地组装服务,并且无需摩擦。但是,在Redis集群3.0中,实现这一点的两个主要功能“NAT/port-forwarding”和“网络封装”是不可用的。
Redis集群3.0作为NAT的背景(不成功的版本)。
Redis 3.0默认会通知自动识别到的本地IP地址和设置的端口号。因此,如果在默认的桥接网络上运行Redis,”内部私有IP地址”和”仅内部访问端口”会被通知给对等端和客户端。
这种情况下,NAT背后的Redis节点可能会以“MOVED重定向”的方式响应给客户端,无法建立连接。
在Redis 3.0的集群中,使用主机模式网络的规避方法(某种可以解决问题的版本)。
在Docker上使用Redis Cluster 3.0,唯一能做的就是使用“主机模式网络”来静态定义每个节点的端口。在主机模式网络中,使用主机的网络栈,容器会通知主机的“公共IP地址”。由于Docker不进行端口转发,因此管理端口冲突取决于用户。
假设在任意的Docker主机上运行n个Redis节点,每个节点必须选择一个端口并在redis.conf中定义。考虑到建议使用6个或更多节点的集群配置,这将很快变得复杂。同时,Docker Swarm和Docker配置也会变得冗长。
Redis Cluster 4.0 作为NAT的背景
在Redis集群4.0中,提供了新的选项。由于Redis可以通知任意的“IP地址”、“端口”和“集群端口”,因此可以进行与NAT状态兼容的设置。不必再使用host-mode网络。但在启动Redis进程之前,必须在节点的redis.conf文件中配置“IP地址”、“端口”和“集群端口”。
通过此方式,所有的MOVED重定向都将指向正确的IP地址和端口号。对于使用静态设置运行Redis集群的用户来说,我认为这已经足够了。但是,如果要使用集群调度器,则需要在事前进行这些配置,这是一个障碍。在剩下的博客中,我们将探索可以动态通过“发现”机制来配置Redis集群节点的方法。
NAT 的发现 (NAT de
集群中的每个节点都可以为每个容器设置NAT,并只有在设置了相应的redis.conf值后,才能拥有单独的共享容器配置。 “Docker compose”,”Docker swarm”和其他”集群解决方案”的服务定义可以集中在仅有一行的Redis容器模板中。例如,只需一行docker-compose –scale命令,Redis服务就可以实现可扩展性!
因为Docker在容器启动时会随机分配端口,所以要确认分配了哪个端口,我们需要查询”Docker API”。有几种方法可行,但在此我们将探讨如何定制官方的”Redis Docker Image”并将其与简单的HTTP发现代理集成。
1. 代理人
我认为,拥有一个以Docker API为基础的HTTP薄包装器,比在完全功能的Docker套接字中不必要地暴露所有Redis容器更合理。此外,还有许多其他可用的服务发现选项。在这里,我将介绍一个非常简单且定制化的示例。
代理容器是基于官方的”nodejs alpine docker image”创建的一个”nodejs express application”。唯一可用的路由是通过容器ID参数化的GET请求。目标是使用Docker API根据请求的容器ID动态查找分配的端口。
代理在使用request时,通过Docker Unix Socket查询Docker API。Docker的“unix socket”会在容器启动时作为Docker卷传递给容器。从Docker API获取容器信息非常简单。
request({
method: 'GET',
url: `http://unix:/var/run/docker.sock:/containers/${id}/json`,
headers: {host: 'localhost'},
json: true
}, (error, res, body) => {
if (error) {
callback(error, null);
return;
}
if (res.statusCode >= 200 && res.statusCode <= 299) {
callback(null, body);
} else {
callback(new Error(body.message));
}
})
通过Docker可以获取任何容器的信息,然后只需定义express路由,从返回的对象中读取端口信息。
app.get('/:id', (req, res) => {
dockerInspect(req.params.id, (error, container) => {
if (error) {
res.status(400);
res.send(error);
} else {
let portInfo = container.NetworkSettings.Ports["6379/tcp"];
let cportInfo = container.NetworkSettings.Ports["16379/tcp"];
if (portInfo && cportInfo) {
let port = portInfo[0].HostPort;
let cport = cportInfo[0].HostPort;
res.send(`${clusterAnnounceIp}:${port}@${cport}`);
} else {
res.send("");
}
}
});
});
结果以与Redis 4.0的CLUSTER NODES相同的格式返回: :<端口>@<集群总线端口>。
$ curl http://192.168.50.5:3000/2bddf88b0904
192.168.50.5:34176@34175
在这里,我们会调整Redis容器,并使用这些信息进行NAT设置。
如果有必要的话,请使用环境变量INTERFACE,并选择要通知的网络接口。
2. Redis容器
在基于官方库/redis容器的alpine变种上,Redis容器将覆盖ENTRYPOINT,在启动时进行发现服务的查询,以找到NAT配置。
仅需通过容器内向Docker主机发出查询,Discovery Agent可以通过host-mode networking获取正确的“announce IP地址”。
gateway=$(/sbin/ip route|awk '/default/ { print $3 }') # Find the gateway IP address
network_info=$(curl -s http://${gateway}:3000/$(hostname)) # Query the discovery agent
# returns: 192.168.50.5:34176@34175
cluster_announce_ip=$(echo ${network_info} | cut -d ':' -f 1) # Cut out the different parts of <IP>:<port>@<cluster-bus-port>`
ports=$(echo ${network_info} | cut -d ':' -f 2)
cluster_announce_port=$(echo ${ports} | cut -d '@' -f 1)
cluster_announce_bus_port=$(echo ${ports} | cut -d '@' -f 2)
请将以下内容用中文重新表述,只需要一种选项:请将新的cluster-announce-ip、cluster-announce-port以及cluster-announce-bus-port设置添加到redis-server的执行中。
set -- redis-server "$@" "--cluster-announce-port ${cluster_announce_port}" "--cluster-announce-bus-port ${cluster_announce_bus_port}" "--cluster-announce-ip ${cluster_announce_ip}"
3. 创建聚类
一旦集群的所有成員都在線上,通過發現到的NAT設定,就能夠創建集群。Redis官方的Ruby管理腳本為redis-trib.rb,以下是創建集群的示例。
ruby redis-trib.rb create --replicas 1 <ip>:<port>[]
只要同时使用Docker CLI,就可以创建任何大小的集群。
docker ps -q -f label=redis | # loop over each container labeled 'redis'
{
while read x; do # inspect each container for its private IP address
private_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $x)
cluster_hosts=\"$cluster_hosts $private_ip:6379\" # Append it to the list of cluster hosts
done
ruby redis-trib.rb create --replicas 1 $cluster_hosts # Form the cluster
}
当执行此操作时,每个成员都会被连接起来,并进行初始哈希插槽和所有权设置。这样集群就可以使用了!
使用Docker Compose
通过使用Docker Compose,可以对各个服务进行配置。通过启动额外实例来扩展容器,可以实现灵活的扩缩容。由于在Redis 3.0中有限制静态配置的限制,所以在单独服务的情况下无法执行多个节点。但在Redis 4.0中,通过这种发现方法,每个容器可以共享相同的模板,因此这就成为可能。
redis:
image: redis:discover
build: ./redis
command: --cluster-enabled yes --bind 0.0.0.0
ports:
- 6379
- 16379
labels:
- redis
depends_on:
- discover
现在您可以使用docker-compose up -scale redis=来提供此服务,以便根据您的要求启动所需数量的容器实例。
$ docker-compose up -d --scale redis=6
$ docker exec redisclustercompose_redis_1 exec redis-cli cluster nodes
48836a86da5d54d56393f866befde47efacc256d 192.168.50.5:34238@34237 master - 0 1504307943992 2 connected 5461-10922
53eb5604cf752e3811b5db01bddb1eb5d580d142 192.168.50.5:34244@34243 slave 48836a86da5d54d56393f866befde47efacc256d 0 1504307944996 5 connected
8b2b5e4eec8d25eab59bdedd0eb356465f3a4102 192.168.50.5:34246@34245 master - 0 1504307942000 1 connected 0-5460
dc71aa602eb6ab6f0d4c71208061b7230f53dc50 192.168.50.5:34240@34239 slave 8b2b5e4eec8d25eab59bdedd0eb356465f3a4102 0 1504307943000 4 connected
e1ab6ad9c5b806f564486b1bb8be2567244d9f5c 192.168.50.5:34242@34241 master - 0 1504307944000 3 connected 10923-16383
3b061c92f30154046c2eba2f858a81ff0c95d2c1 192.168.50.5:34236@34235 myself,slave e1ab6ad9c5b806f564486b1bb8be2567244d9f5c 0 1504307943000 6 connected
瑞蒂套餐
在Github的Docker Compose代码中,已经预先包含了Reddie。并且已经设置好连接到您创建的新集群。当Docker Compose构建完容器后,导航到https://localhost并且欣赏全新的作品吧!
总结
对于很多在Docker上部署的Redis集群来说,新功能的“NAT/port-forwarding”只是意味着可以将主机模式网络更改为桥接或叠加网络。
然而,通过使用Swarm、Kubernetes、Nomad等集群调度器,在这个博客中所展示的例子中,可以实现对Redis集群节点的调度,从而能够以有效方式融合Redis 4.0的新功能并处理Redis集群。
很遗憾,在运行时必须使用发现机制重新配置Redis,这是非常复杂的开销。如果Redis能够动态地重新配置自身(例如使用入站连接信息或在客户端连接中提供集群总线端口),那么Redis集群的动态调度将变得更加简单。
当然,还有很多缺少的部分。比如,永久存储设备、将新调度的节点加入到集群中、重新分配哈希槽等等,这些都是例子。