Проблема при подключении к главному узлу Redis, работающему в режиме Sentinel в контейнерах докеров

Я запускаю Redis в контейнерах докеров и использую режим Redis Sentinel. Я установил следующую конфигурацию -

3 redis sentinels nodes
1 redis master node
2 redis slave nodes

Я запускаю все это на своей локальной машине. Таким образом, всего 6 контейнеров докеров проходят через docker-compose в сетевом режиме моста. Все контейнеры имеют сопоставление портов с внешними.

Все контейнеры могут получать доступ друг к другу, поскольку они находятся в одной и той же сети докеров моста, созданной во время работы docker-compose up.

Я создал Java-клиент, используя библиотеку Redisson для доступа к redis. Настроил клиент для использования режима redis-sentinel следующим образом:

Config config = new Config();
config.useSentinelServers()
       .setMasterName("redis-master")
       .addSentinelAddress("redis://127.0.0.1:26379")
       .addSentinelAddress("redis://127.0.0.1:26380")
       .addSentinelAddress("redis://127.0.0.1:26381")

RedissonClient client = Redisson.create(config);

Здесь я столкнулся с проблемой. Всякий раз, когда я пытаюсь запустить некоторые команды на Redis через этот клиент, запрос проходит через дозорные узлы, которые дают мне текущий адрес главного узла Redis. Но мой Java-клиент не может напрямую связываться с мастером Redis, поскольку IP-адрес, возвращаемый дозорным узлом, является IP-адресом внутренней сети докеров для главного узла, который недоступен за пределами сети докеров, и он терпит неудачу с аналогичным исключением, как показано ниже:

Exception in thread "main" org.redisson.client.RedisConnectionException: Unable to connect to Redis server: 172.21.0.2/172.21.0.2:6379
    at org.redisson.connection.pool.ConnectionPool$2$1.operationComplete(ConnectionPool.java:161)
    at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)

Как решить эту проблему? Нужно ли запускать его в каком-то другом сетевом режиме? или какой-то способ перевести этот внутренний IP-адрес докера в фактический IP-адрес машины, на которой запущены контейнеры Docker?


person Kuldeep Singh    schedule 30.01.2019    source источник


Ответы (1)


Я тоже столкнулся с этой проблемой сегодня, пытаясь настроить это для тестового экземпляра. Мой первоначальный файл компоновки был основан на https://blog.alexseifert.com/2016/11/14/using-redis-sentinel-with-docker-compose/ с изменениями в соответствии с моими потребностями. Мне удалось найти обходной путь, 1) привязав порты к моему хост-компьютеру, 2) установив флаг depend_on в docker-compose и 3) установив мой sentinel.conf так, чтобы он указывал на имя хоста, на котором работал мой мастер: https://docs.docker.com/compose/startup-order/

Это немного сложно объяснить, но я постараюсь: ваш мастер/реплика будет выглядеть примерно так в docker-compose:

  redis-master:
    image: redis:5.0.4-alpine
    volumes:
      - <mounted-data-directory>
      - "<local-master-config-directory>/redis.conf:/usr/local/etc/redis/redis.conf"
    ports:
      - "6379:6379"
    command:
      - redis-server
      - /usr/local/etc/redis/redis.conf

  redis-replica:
    image: redis:5.0.4-alpine
    links:
      - redis-master
    volumes:
      - <mounted-data-directory>
      - "<local-replica-config-directory>:/usr/local/etc/redis/redis.conf"
    ports:
      - "6380:6380"
    depends_on:
      - redis-master
    command:
      - redis-server
      - /usr/local/etc/redis/redis.conf
      - --slaveof redis-master 6379

Для своих дозорных я дал каждый Dockerfile и sentinel.conf (каждый из которых имеет разные порты): Dockerfile:

FROM redis:5.0.4-alpine
RUN mkdir -p /redis
WORKDIR /redis
COPY sentinel.conf .
RUN chown redis:redis /redis/*
ENTRYPOINT ["redis-server", "/redis/sentinel.conf", "--sentinel"]

sentinel.conf

port 26379
dir /tmp
bind 0.0.0.0
sentinel monitor mymaster <hostname> 6379 2
sentinel down-after-milliseconds mymaster 1000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 10000

Стоит отметить, что я пытался сделать это с 127.0.0.1 и локальным хостом, и я не думаю, что это сработало, поэтому я установил имя хоста на машине, на которой я это запустил. В тот момент я пробовал все и вся.

У каждого часового (у меня было три) была отдельная запись, ссылающаяся на их контексты сборки и отображающая порт в sentinel.conf на локальный порт. Итак, в docker-compose мои часовые выглядели так:

 # Instance 1
  redis-sentinel:
    build:
      context: <path-to-context>
    links:
      - redis-master
    ports:
      - "26379:26379"
    depends_on:
      - redis-replica

То, что я сделал, было определенно хаком, и я бы не стал делать это в продакшене. Я почти уверен, что для докера есть гораздо лучшее сетевое решение, я просто не хотел заходить слишком далеко в кроличью нору для того, что мне нужно было протестировать. Надеюсь это поможет.

person gtg469x    schedule 15.04.2019
comment
Да. аналогичное решение, которое мы реализовали для тестирования, чтобы открыть порты на хост-компьютере. Но это не кажется идеальным решением для использования в производстве. Другим решением может быть один файл docker-compose для всех служб, использующих Redis, и для служб Redis. Тогда все они будут работать в одной сети докеров и смогут общаться друг с другом. - person Kuldeep Singh; 27.06.2019
comment
Да, docker compose хорошо бы подходил ко всем упакованным сервисам, но, честно говоря, я не хотел переделывать нашу существующую тестовую систему, у меня не было достаточно времени, чтобы переработать весь этот пайплайн. Рад, что вы получили то, что вам нужно! - person gtg469x; 28.06.2019