CHANBEEN.COM
Docker 기반 Redis Cluster에 Lettuce 접속이 실패한 이유?
2025-07-29#Docker

Docker 기반 Redis Cluster에 Lettuce 접속이 실패한 이유?

들어가며

안녕하세요,
프로젝트 진행 중, Redis 클러스터 연결 테스트가 필요했습니다.
JAVA 기반 Spring 프로젝트에서 Lettuce를 통해 클러스터에 연결해야 하는 상황이었어요.

기본적인 Standalone Redis는 RedisClient로 사용하게 되지만,
Cluster Redis의 경우 RedisClusterClient로, 다른 클래스를 사용하게 됩니다.

그래서 작업 PC 내 여러 개의 Redis 인스턴스를 Docker로 구성하고,
클러스터로 구성하여 Lettuce를 통해 연결해보려 했습니다.

하지만... Docker로 구성한 Redis Cluster는 Lettuce 연결에 실패했습니다.
그 이유와 해결 과정을 정리해 보았습니다.

선 결론 (Window 기준)

방안 클러스터 결성 Lettuce 연결 주요 실패 원인
Bridge network 가능 실패 클러스터 토폴로지가 컨테이너 내부 IP로 노출
Host network 불가 - Window Docker Desktop 제약
cluster-announce 불가 - 컨테이너 내부에서 호스트 네트워크 접근 불가 (network: Bridge)
host.docker.internal 불가 - cluster-announce 설정 불가
VM(리눅스 호스트) 가능 성공 네트워크 분리 없이 host IP 직접 사용

1. 목표 및 가설

가용 자원 파악

먼저 현재 하드웨어 상태를 정리 해 보겠습니다.

  • PC 1대
  • 개발 내부망 (외부 인터넷 불가)
  • Docker, VMWare 설치 되어있음

최종 목표

JAVA 앱에서 Lettuce를 통해 클러스터에 연결이 되는지 테스트해야 합니다.
이후, RedisClusterCommand 객체를 통해 CLUSTER INFO 결과를 반환받는 게 목표입니다.

목표 성취 가설

  1. Docker-Compose를 통해 Redis Container를 7대 생성
  2. Redis의 Replica는 1로 설정, Master Node 3, S 4개로 구성
  3. 각 컨테이너는 Bridge Network로 연결
  4. redis-cli --cluster create로 컨테이너 이름으로 연결

위의 순서로 작업을 진행하면,
모든 Redis container는 클러스터로 구성되어
호스트에서 특정 노드에 연결을 시도했을 때 모든 토폴로지가 자동 연결 될 것이라 생각했습니다.


2. 첫번째 테스트 (Bridge Network 활용)

  • 하드웨어: Windows 단일 PC
  • Docker-compose로 Redis 노드 7개를 구성(bridge/host 네트워크 비교)

Docker-Compose 셋업

version: "3"
services:
  redis-node-1:
    image: redis:latest
    container_name: redis-node-1
    command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
    ports:
      - "7001:6379"
    networks:
     - redis_cluster_net

  redis-node-2:
    image: redis:latest
    container_name: redis-node-2
    command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0
    ports:
     - "7002:6379"
    networks:
     - redis_cluster_net

  ... (redis-node-7까지 반복)

networks:
  redis_cluster_net:
    driver: bridge

추가로, 클러스터를 구성할 생성용 컨테이너를 추가 정의했습니다.

  redis-cluster-creator:
    image: redis:latest
    container_name: cluster-creator
    networks:
      - redis_cluster_net
    depends_on:
      - redis-node-1
      - redis-node-2
      - redis-node-3
      - redis-node-4
      - redis-node-5
      - redis-node-6
      - redis-node-7
    command: redis-cli --cluster create redis-node-1:6379 redis-node-2:6379
          ... (반복)
          --cluster-replicas 1
          --cluster-yes

이후, docker-compose up 을 통해 로그와 함께 내용을 확인합니다.

Docker compose up 로그 화면

내부 Bridge로 연결되어있기 때문에, 다른 node로의 연결도 가능합니다.
redis-cli -h 172.20.0.2 -p 6379 이런 방식으로, 접속이 가능한 것을 확인할 수 있습니다.

Lettuce JAVA 앱

이제, Lettuce기반 JAVA 앱 코드를 구성합니다.

    public static void main(String[] args) {
        SpringApplication.run(LettuceApplication.class, args);

        RedisClusterClient clusterClient = RedisClusterClient.create(
                "redis://127.0.0.1:7001"
        );

        try (StatefulRedisClusterConnection<String, String> connection = clusterClient.connect()) {
            RedisClusterCommands<String, String> commands = connection.sync();
            StringListOutput<String,String> output = new StringListOutput<>(StringCodec.UTF8);

            CommandArgs<String, String> arg = new CommandArgs<>(StringCodec.UTF8).add("INFO");
            List<String> res = commands.dispatch(CommandType.CLUSTER, output, arg);

            System.out.println(res);
        }
        clusterClient.shutdown();
    }

간단하게 구성했습니다.
redis에 연결한 후, Cluster Info 메시지를 날립니다.

결과

connection failed 오류 이미지

connection timed out after 10000 ms: /172.20.0.7:6379
위 로그처럼, Unable to connect를 얻었습니다.
가장 큰 문제는, Lettuce에서 연결하려는 대상172.20.0.7:6379 인 것으로 판단했습니다.

해당 주소는 docker network inspect dca_redis_cluster_net 명령어를 통해
Docker 내부 컨테이너 전용 IP라는 것을 알 수 있지요.

> docker network inspect dca_redis_cluster_net

  [
    {
      "Name": "dca_redis_cluster_net",

      ...(생략)

      "IPAM": {
        "Driver": "default",
        "Options": null,
        "Config": [
          {
            "Subnet": "172.20.0.0/16",
            "Gateway": "172.20.0.1"
          }
        ]
      },

      ...(생략)

      "Containers": {
        "17151efcca8b5e326536717daf4712edfd1d47eaa883accdca409b081a5eb730": {
          "Name": "redis-node-3",
          "EndpointID": "d7379693b4eea17d36e4988ae2ecc1dac606aa378021eaf26b49640965c1b672",
          "MacAddress": "02:42:ac:14:00:02",
          "IPv4Address": "172.20.0.2/16",
          "IPv6Address": ""
        },
        "47db6a380c842f091bd7bb726cf6ff1bcf560d58150a5a85f70101cb82302daf": {
          "Name": "redis-node-7",
          "EndpointID": "9829afd2d94f1d9e77e893582ff39f84018c8830b25a076bf092c64735815c36",
          "MacAddress": "02:42:ac:14:00:05",
          "IPv4Address": "172.20.0.5/16",
          "IPv6Address": ""
        },

      ... (이하 생략)

그럼 다시 돌아가서, 172.20.0.x는 도커 컨테이너 내부 서브넷 IP입니다.
호스트, 도커 컨테이너 외부에선 접근할 수 없는 주소이죠.

호스트에서 접근하려면 localhost: 로 접근해야 하며.
docker에서 ports로 포트포워딩한 위치로 접근해야 해당 노드로 접근할 수 있게 됩니다.

그럼, 왜 Lettuce는 토폴로지탐색에 도커 내부 컨테이너 주소를 쓸까?


3. Lettuce의 클러스터 탐색 방식?

Lettuce는 최초로 한 노드에 접속하게 되면,
자동으로 CLSUTER SLOTS을 수행합니다.

127.0.0.1:6379> CLUSTER SLOTS

1) 1) (integer) 0
   2) (integer) 5460
   3) 1) "172.20.0.7"
      2) (integer) 6379
      3) "cdc471c93bff4771944f8c936c552be18ec7541c"
      4) (empty array)
   4) 1) "172.20.0.3"
      2) (integer) 6379
      3) "ff4793dd3ea08102af6a081df3e1ad7abc2c16c1"
      4) (empty array)
   5) 1) "172.20.0.6"

여기서 검색 된 IP로 LETTUCE에서 자동 검색을 수행하는데,
모두 도커 내부 IP임을 확실히 알 수 있습니다.

이를 기반으로 Lettuce가 통신 연결을 시도하기 때문에,
호스트에서는 도커 내부 IP로 접속할 수 없는 상황이 벌어진 것이죠...


4. 두번째 방안 (Host Network 활용)

가설

이를 해결하기 위해 할 수 있는 걸 생각해봤을 때...
Docker-Bridge로 하면 내부 네트워크로 잡으니,
Host 네트워크를 사용하도록 하고, 각 컨테이너를 다른 포트로 실행시키면 되지 않을까?
하는 가설을 세웠습니다.

  • Host 네트워크 사용
  • 각 Redis Cluster 실행 포트를 변경

결과 (한계)

Window Docker에서는 network Host를 별도 설정할 수 없습니다.

개발 PC에서는 구동중인 다른 컨테이너들이 있어,
일괄 변경되는 Docker Desktop의 Host 설정 활성화는 무리가 있습니다.

Linux 환경에서는 충분히 가능하다 생각합니다.
이를 테스트하려면, linux에서 host로 REDIS들을 실행시킨 후
특정 노드에서 redis-cli -h 127.0.0.1 -p <다른 REDIS 컨테이너 포트>
접속이 가능하면 아마 문제없이 될 것으로 보입니다.

하지만... 저는 Window 환경이고, 빠른 테스트가 필요합니다.
물론, Docker-in-Docker로 Rocky Linux 등을 설치해서 redis를 구동시키는 것도 방법이죠.
그래도 깔끔하게 테스트를 하고 싶었어요.


5. 세번째 방안 (cluster-announce-ip 활용)

announce 설정 시도

이것도 Host-Network와 비슷한 문제입니다.

  redis-node-1:
    image: redis:latest
    container_name: redis-node-1
    command: redis-server --port 6379 --cluster-enabled yes --cluster-config-file nodes.conf --cluster-node-timeout 5000 --appendonly yes --bind 0.0.0.0 --cluster-announce-ip 127.0.0.1 --cluster-announce-port 7001 
    ports:
      - "7001:6379"

이런식으로, redis 서버 생성 시 cluster-announce-를 입력하여
본인의 원격 주소를 입력해줄 수 있습니다.

하지만... 역시 동일하죠. 브릿지로 구동되는 서버이기 때문에,
container에 들어가서 클러스터를 생성하려 하면,

root@ddfabbf00ab4:/data# redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 127.0.0.1:7007 --cluster-replicas 1
Could not connect to Redis at 127.0.0.1:7001: Connection refused

이런 에러가 나올겁니다.
cluster-announce 자체는 Redis 설정상 가능하지만,
Docker Bridge 네트워크 특성상 호스트 IP로의 연결은 컨테이너 내부에서 제한됩니다.
이렇게 되면, 당연하게도 클러스터 구성 자체가 불가합니다.

그럼, host.docker.internal을 사용하면 되지 않나?

host.docker.internal은 Docker 컨테이너에서 호스트 머신으로 접근할 때 사용할 수 있습니다. 논리상 network 설정을 host로 입력하고 사용하는 것과 다를 게 없죠.

하지만
Redis 클러스터에 본인으로 접속하기 위한 IP를 설정하는 cluster-announce-ip는 IP 정규식만 허용합니다.
--cluster-announce-ip host.docker.internal 입력을 해 주면, 아래와 같은 에러가 발생합니다.
host.docker.internal 에러 이미지

그렇다고 cluster-announce-ip를 127.0.0.1로 하면, 컨테이너마다 네트워크가 고립되는 결과가 나올 뿐입니다.


6. 마지막 방안 (VM 활용)

윈도우 환경에서 별도 OS 설정 없이 진행하려면, 도커 컨테이너로는 어렵다는 판단이 섰습니다.

  • 리눅스 환경이라면 network - host 설정으로 가능할 것으로 보임.

VM 구성 컴퓨팅 리소스 이미지

환경 설정

  1. 외부망에서 Rocky-Linux Container를 생성.
  2. redis 설치에 필요한 rpm 추가. dnf download --resolve --arch=x86_64 redis
  3. 이후 rpm 파일을 개발망 내부 NAS 서버로 이동합니다.
  4. 내부 개발망, VMWare에서 Linux를 구동합니다.
  5. 공유 폴더를 통해 rpm을 전달한 후, 설치합니다. dnf --disablerepo="*" localinstall *.rpm --nogpgcheck

클러스터 셋업

  1. 각 VM에 접속하여 /etc/redis.confbind값을 0.0.0.0으로 허용 처리 해 줍니다.
  2. 각 VM의 방화벽에 접속하여 637916379 포트를 허용합니다.
  3. /var/lib/redis/nodes.conf가 VM별로 다른 값이 들어있는지 확인합니다.
  4. 한 VM에 접속하여 redis-cli --cluster create <VM-IP>:6379 ~ 반복 ~ --cluster-replicas 1 --cluster-yes 로 클러스터를 구성합니다.
  5. CLUSTER INFO에서 cluster state가 ON으로 표시되는지 확인하고, CLUSTER NODES가 정상인지 확인합니다.

결과 (Lettuce 연결 테스트)

이후, 호스트에서 다시 Lettuce를 통해 create.connect.sync를 실행하면,
정상적으로 연결된 후 데이터를 반환받는 모습을 확인할 수 있었습니다.

CLUSTER NODES 결과 이미지

Cluster INFO에 대한 값도 정상적으로 반환되네요.


마무리

여러모로 재미있는 테스트였습니다.
현재도 좀 더 REDIS를 JAVA에서 핸들링하기 위해 LETTUCE를 사용하고 있습니다.
spring-boot-Redis도 가능은 하지만, 커맨드 string을 직접 구동시키기에는
lettuce가 더 좋다 판단했습니다.

  • Docker Bridge로 Redis Cluster를 구성하면, 외부에서 Lettuce 연결은 실패합니다.
  • 가장 큰 원인은 CLUSTER SLOTS 결과가 내부 IP를 반환하기 때문입니다.
  • Windows Docker는 Host 네트워크를 부분적으로 지원하기 때문에, VM 기반 리눅스가 사실상 유일한 대안이었습니다.

아직 리눅스 기반 OS에서 도커를 설치한 뒤, host 기반으로 동작 테스트를 하는 건
수행되지 않았지만, Linux 기반에서는 host network 설정이 자유롭기 때문에
브릿지 네트워크의 문제를 개선할 수 있을 것으로 생각하고 있습니다.

빠른 시일 내에 테스트하여 글 수정을 해 두도록 하겠습니다. 😊

틀린 부분이나 더 보완할만한 부분이 있다면,
댓글 부탁드립니다!

감사합니다.