单机docker部署的redis sentinel,使用python调用redis,报错

在使用单机 Docker 部署 Redis Sentinel 后, Python 调用报 MasterNotFoundError + TimeoutError,核心原因是Docker 网络配置问题 (容器端口未映射/IP 访问不到)或 Sentinel 配置错误(监控的主节点是容器内部 IP,Python 无法解析)。以下是针对「单机 Docker 部署」的专属排查和解决方案:

先明确单机 Docker 部署的典型架构

单机部署时,通常会启动 3 个容器:1 个 Redis 主节点、1 个 Redis 从节点、3 个 Sentinel 节点(或至少 1 个),但所有容器都运行在同一台宿主机上,需通过「宿主机 IP + 映射端口」访问,而非容器内部 IP。

步骤1:检查 Docker 容器端口映射(最核心)

1.1 查看容器端口映射情况

执行 docker ps,查看 Redis 主/从、Sentinel 容器的端口映射,示例正常输出:

复制代码
CONTAINER ID   IMAGE         COMMAND                  PORTS                      NAMES
xxx            redis:sentinel   "redis-sentinel /etc/..."   0.0.0.0:26380->26379/tcp   sentinel1
xxx            redis:sentinel   "redis-sentinel /etc/..."   0.0.0.0:26381->26379/tcp   sentinel2
xxx            redis:sentinel   "redis-sentinel /etc/..."   0.0.0.0:26382->26379/tcp   sentinel3
xxx            redis           "docker-entrypoint.s..."    0.0.0.0:6379->6379/tcp     redis-master
xxx            redis           "docker-entrypoint.s..."    0.0.0.0:6380->6379/tcp     redis-slave

✅ 关键:Sentinel 容器的 PORTS 列必须是 0.0.0.0:宿主机端口->26379/tcp(如 26380->26379),Redis 主节点是 6379->6379

❌ 常见错误:

  • 容器未映射端口(PORTS 列为空):Python 无法访问容器;
  • 映射端口冲突(多个容器映射同一端口):导致端口被占用,连接超时。
1.2 修复端口映射(重新启动容器)

若端口未映射,删除旧容器后重新启动(以 Sentinel 为例):

bash 复制代码
# 停止并删除旧Sentinel容器
docker stop sentinel1 sentinel2 sentinel3
docker rm sentinel1 sentinel2 sentinel3

# 启动Sentinel容器,映射端口到宿主机(26380/26381/26382)
# 注意:--network=host 可选(单机推荐,直接使用宿主机网络,无需端口映射)
docker run -d --name sentinel1 -p 26380:26379 redis:sentinel
docker run -d --name sentinel2 -p 26381:26379 redis:sentinel
docker run -d --name sentinel3 -p 26382:26379 redis:sentinel

# 启动Redis主节点(映射6379端口)
docker run -d --name redis-master -p 6379:6379 redis --requirepass "yourpassword"

步骤2:修正 Sentinel 配置(核心坑:监控的主节点是容器 IP)

单机 Docker 部署时,Sentinel 默认会监控「容器内部 IP:6379」,但 Python 运行在宿主机(或另一容器),无法访问容器内部 IP,导致 Sentinel 虽然能识别主节点,但 Python 从 Sentinel 获取到的主节点 IP 不可达。

2.1 进入 Sentinel 容器修改配置
bash 复制代码
# 进入任意Sentinel容器
docker exec -it sentinel1 /bin/bash

# 编辑sentinel.conf(默认路径/etc/redis/sentinel.conf)
vi /etc/redis/sentinel.conf
2.2 修改核心配置(关键!)
conf 复制代码
# 原配置(错误:监控容器内部IP)
# sentinel monitor mymaster 172.17.0.2 6379 2

# 新配置(监控宿主机IP + 映射端口)
sentinel monitor mymaster 宿主机IP 6379 2
# 若Redis主节点有密码,添加
sentinel auth-pass mymaster yourpassword
# 启用hostname解析(可选)
sentinel resolve-hostnames yes
sentinel announce-ip 宿主机IP  # 告诉客户端用宿主机IP连接主节点
sentinel announce-port 6379    # 主节点映射端口

✅ 宿主机 IP 查看:执行 ifconfig/ip addr,取非 127.0.0.1 的内网 IP(如 192.168.1.100)。

2.3 重启所有 Sentinel 容器
bash 复制代码
docker restart sentinel1 sentinel2 sentinel3

步骤3:修正 Python 代码(连接宿主机 IP + 映射端口)

错误代码(连容器内部 IP,必超时):
python 复制代码
from redis.sentinel import Sentinel
# 错误:172.24.0.7是容器内部IP,Python访问不到
sentinel = Sentinel([("172.24.0.7", 26380), ("172.24.0.6", 26381), ("172.24.0.5", 26382)], socket_timeout=3)
正确代码(连宿主机 IP + 映射端口):
python 复制代码
from redis.sentinel import Sentinel

# 核心:Sentinel地址是「宿主机IP + 容器映射的端口」
sentinel = Sentinel(
    [
        ("宿主机IP", 26380),  # 对应sentinel1的映射端口26380
        ("宿主机IP", 26381),  # sentinel2
        ("宿主机IP", 26382)   # sentinel3
    ],
    socket_timeout=3.0,        # 延长超时时间
    socket_connect_timeout=3.0,
    retry_on_timeout=True,     # 超时重试
    password="Sentinel密码(若有)"  # 若Sentinel配置了requirepass才加
)

# 获取主节点(注意:主节点密码是Redis的密码,不是Sentinel的)
try:
    master = sentinel.master_for(
        "mymaster",
        password="yourpassword",  # Redis主节点的密码
        retry_on_timeout=True
    )
    print("连接成功:", master.ping())
    master.set("test", "docker redis sentinel")
    print("取值:", master.get("test"))
except Exception as e:
    print("错误详情:", e)

步骤4:验证连通性(单机环境快速测试)

4.1 宿主机测试 Sentinel 连接
bash 复制代码
# 用redis-cli连接宿主机的Sentinel端口
redis-cli -h 宿主机IP -p 26380
# 执行命令,查看是否能识别主节点
127.0.0.1:26380> sentinel master mymaster
# 输出中检查:
# - "ip":宿主机IP(不是容器IP)
# - "port":6379
# - "status":ok
4.2 测试 Python 代码

运行修正后的 Python 代码,若输出 连接成功:True 则正常。

单机 Docker 部署的额外避坑点

  1. 使用 Docker Network 桥接模式

    若不想映射端口,可创建自定义网络,让 Python 容器(若 Python 也在 Docker 中)和 Redis/Sentinel 容器在同一网络:

    bash 复制代码
    # 创建自定义网络
    docker network create redis-net
    # 启动容器时指定--network=redis-net
    docker run -d --name redis-master --network=redis-net redis
    docker run -d --name sentinel1 --network=redis-net redis:sentinel
    # Python容器也加入同一网络,此时可通过容器名访问(如sentinel1:26379)
  2. Redis 保护模式

    若 Redis 主节点未设置密码,需关闭保护模式(否则拒绝外部连接):

    bash 复制代码
    docker run -d --name redis-master -p 6379:6379 redis --protected-mode no
  3. 端口冲突

    单机部署时,确保 26380/26381/26382/6379 端口未被其他进程占用:

    bash 复制代码
    # 检查端口占用
    netstat -tulpn | grep 26380
    netstat -tulpn | grep 6379

最终总结(单机 Docker 核心要点)

  1. 所有容器必须映射端口到宿主机,或加入同一 Docker 网络;
  2. Sentinel 配置中监控的主节点必须是「宿主机 IP + 映射端口」,而非容器内部 IP;
  3. Python 代码必须连接「宿主机 IP + 容器映射的 Sentinel 端口」,而非容器内部 IP;
  4. 延长超时时间 + 开启重试,适配单机 Docker 的网络延迟。

按以上步骤操作后,99% 的单机 Docker 环境下 MasterNotFoundError + TimeoutError 都会解决。

相关推荐
BoBoZz192 小时前
IterativeClosestPoints icp配准矩阵
python·vtk·图形渲染·图形处理
test管家2 小时前
PyTorch动态图编程与自定义网络层实战教程
python
laocooon5238578862 小时前
python 收发信的功能。
开发语言·python
清水白石0083 小时前
《Python 责任链模式实战指南:从设计思想到工程落地》
开发语言·python·责任链模式
沛沛老爹3 小时前
Web开发者快速上手AI Agent:基于LangChain的提示词应用优化实战
人工智能·python·langchain·提示词·rag·web转型
宁大小白3 小时前
pythonstudy Day39
python·机器学习
拾贰_C3 小时前
【VSCode | python | anaconda | cmd | PowerShell】在没有进入conda环境时使用conda命令默认安装位置
vscode·python·conda
大千AI助手3 小时前
基于OpenAPI生成的 SDK 的工业级和消费级概念区别
人工智能·python·机器学习·openai·代码生成·openapi·大千ai助手
java1234_小锋3 小时前
Redis6为什么引入了多线程?
java·redis