单机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 都会解决。

相关推荐
AC赳赳老秦33 分钟前
网页公开附件自动采集:OpenClaw 批量下载页面内嵌 Word/Excel 附件,统一格式后结构化入库
java·python·word·php·excel·deepseek·openclaw
北斗落凡尘33 分钟前
LangGraph 入门实战(3)
python·langchain
TAN-90°-44 分钟前
Deep Learning for Computer Vision——Image Classification with Linear Classifiers
python·深度学习·算法·计算机视觉·线性回归
AINative软件工程1 小时前
LLM API 成本失控怎么办?工程师的实时异常检测指南
python
练习两年半的攻城狮1 小时前
LlamaIndex ResponseMode 深度解析
python·llamaindex
油丶酸萝卜别吃1 小时前
Redis 布隆过滤器快速实现
数据库·redis·缓存
承渊政道1 小时前
飞牛NAS部署Immich:搭建家庭相册并实现远程访问
运维·服务器·docker·内网穿透·cpolar·nas·immich
阿pin1 小时前
Java随笔-红黑树
java·python·算法·红黑树
2603_965148111 小时前
eBay商品数据API:寻找海外仓与价格洼地
大数据·人工智能·windows·python·microsoft