我的目标是使用 Docker 在单个 Docker VM 上设置 3x Redis 服务器和 3x Redis Sentinel,并将每个 Redis 服务器和 Sentinels 暴露给本地网络。
我的Docker主机的静态IP是192.168.2.90.
我给 Redis 服务器端口编号为 6379、6380、6381,并通过 Docker 公开了这些端口。
我的本地网络是192.168.2.0/24
我的Docker机器的内网是172.16.0.0/12.
一切都在 Docker 容器本身内运行良好。当我尝试使用本地网络上的另一台机器连接到 Redis 时,问题就来了。
我的 python 测试脚本成功连接到 Redis Sentinel。问题是当它发现主从时,地址都在 172.16.0.0/12 子网上。
Redis master:
('172.18.3.1', 6379)
Redis slaves:
[('172.18.3.3', 6381), ('192.168.2.90', 6379),('172.18.3.2', 6380)]
当我远程登录到 master 并运行 INFO 时,它同样给了我 172.16.0.0/12 地址。
role:master
connected_slaves:2
slave0:ip=172.18.3.3,port=6381,state=online,offset=252692195,lag=0
slave1:ip=172.18.3.2,port=6380,state=online,offset=252692195,lag=0
我不知道如何让 Redis Server 和 Redis Sentinel 报告 192.168.2.0/24 子网。
我定义了我的 Redis 服务器容器如下:
redis-a-1:
container_name: redis-a-1
hostname: redis-a-1
image: redis
command: "redis-server --port 6379 --bind-source-addr 192.168.2.90"
environment:
- REDIS_HOST=192.168.2.90
ports:
- "6379:6379"
restart: unless-stopped
networks:
blue-green-network:
ipv4_address: 172.18.3.1
redis-a-2:
container_name: redis-a-2
hostname: redis-a-2
image: redis
command: "redis-server --port 6380 --bind-source-addr 192.168.2.90 --slaveof 192.168.2.90 6379"
environment:
- REDIS_HOST=192.168.2.90
ports:
- "6380:6380"
restart: unless-stopped
networks:
blue-green-network:
ipv4_address: 172.18.3.2
redis-a-3:
container_name: redis-a-3
hostname: redis-a-3
image: redis
command: "redis-server --port 6381 --bind-source-addr 192.168.2.90 --slaveof 192.168.2.90 6379"
environment:
- REDIS_HOST=192.168.2.90
ports:
- "6381:6381"
restart: unless-stopped
networks:
blue-green-network:
ipv4_address: 172.18.3.3
我尝试了很多方法让每个 Redis 服务器将它们的 IP 地址作为 Docker 主机的 IP 地址相互报告,但没有成功。
关于我如何做到这一点的任何想法,或者我是在做傻事吗?
非常感谢。
注意:我知道机器本身是单点故障
您通过公开 Redis 服务器的端口所做的是创建从主机 IP 地址到内部 Docker IP 地址的映射。但是,这 not 改变了 Redis 服务器看到并用来相互通信的 IP 地址。他们仍然认为自己的 IP 地址位于 172.16.0.0/12 子网中。
Docker 默认情况下将容器与宿主机和其他容器隔离,并为每个容器提供自己的网络堆栈。容器从内部 Docker 子网(在您的示例中为 172.16.0.0/12)分配 IP 地址,这些地址通常无法从 Docker 主机外部访问。
你正在使用 Redis Sentinel(它应该有助于管理 Redis 服务器拓扑,提供监控、通知、自动故障转移和配置等服务),当它查询 Redis 服务器时,它们会报告它们的内部 Docker IP 地址:这就是你看到了。
阅读“IP地址和DNS名称”,您可以使用“
announce-ip
”:这将告诉Redis向客户端和其他Redis服务器宣布不同的IP地址。
--announce-ip
选项可用于告诉 Redis 服务器向客户端和其他 Redis 服务器通告不同的 IP 地址,当 Redis 在 Docker 容器内运行并需要与外部实体通信时,这会有所帮助。
您的问题出在 Redis Sentinel 上,由于 Docker 的端口重新映射,它无法发现 Redis 服务器和其他 Sentinel 实例。根据 Redis 文档,您应该在 Sentinel 配置中使用
sentinel announce-ip <ip>
和 sentinel announce-port <port>
指令来解决此问题 1 。
redis-sentinel-1:
container_name: redis-sentinel-1
hostname: redis-sentinel-1
image: redis
command: "redis-server /etc/redis/sentinel.conf --sentinel --announce-ip 192.168.2.90 --announce-port 26379"
environment:
- REDIS_HOST=192.168.2.90
ports:
- "26379:26379"
restart: unless-stopped
networks:
blue-green-network:
ipv4_address: 172.18.3.4
这将使用 Redis 映像设置 Redis Sentinel,并使用
--announce-ip
和 --announce-port
选项运行 Sentinel 服务。/etc/redis/sentinel.conf
)才能正常工作。
对
redis-a-2
和redis-a-3
重复此操作,希望这可以解决您的问题。
“主机网络模式下的 Docker”将是一个更简单的解决方案,但前提是它与您的设置和安全要求兼容。
在主机网络模式下,Docker 容器与 Docker 主机本身共享网络堆栈,这意味着它不执行任何网络地址转换 (NAT) 或端口映射。这可以缓解您在使用 Redis Sentinel 的自动发现和故障转移机制时遇到的问题。
但显然,这不太安全(容器在主机模式下的网络隔离较少,因为它们共享主机的网络命名空间并可以访问其所有网络接口),并且可能包括与主机上应用程序的端口冲突。