Kafka

ZooKeeper 볼륨 꼬임으로 Kafka 죽는 문제

99duuk 2026. 1. 7. 10:40

 

services:
  zookeeper:
    image: confluentinc/cp-zookeeper:7.3.0
    container_name: DI-zookeeper
    ports:
      - "2181:2181"
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_SERVER_ID: 1
      ZOOKEEPER_SERVERS: zookeeper:2888:3888
    volumes:
      - ./docker-data/zookeeper:/var/lib/zookeeper
    networks:
      - kafka-network

   kafka:
    image: confluentinc/cp-kafka:7.3.0
    container_name: DI-kafka-1
    restart: unless-stopped
    ports:
      - "9092:9092"
      - "29092:29092"
      - "9999:9999"
    environment:
      KAFKA_ADVERTISED_LISTENERS: INTERNAL://kafka:19092,EXTERNAL://${DOCKER_HOST_IP:-127.0.0.1}:9092
      KAFKA_LISTENERS: INTERNAL://0.0.0.0:19092,EXTERNAL://0.0.0.0:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,DOCKER:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
      KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181"
      KAFKA_BROKER_ID: 1
      KAFKA_LOG4J_LOGGERS: "kafka.controller=INFO,kafka.producer.async.DefaultEventHandler=INFO,state.change.logger=INFO"
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_JMX_PORT: 9999
      KAFKA_JMX_HOSTNAME: ${DOCKER_HOST_IP:-127.0.0.1}
      KAFKA_AUTHORIZER_CLASS_NAME: kafka.security.authorizer.AclAuthorizer
      KAFKA_ALLOW_EVERYONE_IF_NO_ACL_FOUND: "true"
    depends_on:
      - zookeeper
    volumes:
      - ./docker-data/kafka:/var/lib/kafka/data
    networks:
      - kafka-network

 

up down 할때 한번씩 kafka가 안올라옴. 

 up down up 하면 보통 올라오곤 했는데 

 up down up down up 해도 안올라옴;;;

 


 

inspect 날려보니

docker inspect DI-kafka-1 --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'
docker inspect DI-zookeeper --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

/Users/tars/Documents/namu/gitlab/di-backend/docker-data/kafka -> /var/lib/kafka/data
/var/lib/docker/volumes/ba0bab31ff4baa9903e8a5d297b13fbd23ca24108f9aebf656ebe0908af618cc/_data -> /etc/kafka/secrets

/Users/tars/Documents/namu/gitlab/di-backend/docker-data/zookeeper -> /var/lib/zookeeper
/var/lib/docker/volumes/7953da39d7dda53bcefd827dee910750e391a16552f87c0cc662f8165300e8ea/_data -> /etc/zookeeper/secrets
/var/lib/docker/volumes/8ab3a16e5f539536a6cd27e47aee946450778aca269db79808a51c0cb5de2eae/_data -> /var/lib/zookeeper/data
/var/lib/docker/volumes/676ddc837a8a0eb9bf4cbecd83a048a719031d6f2e7ac955589005d97b4eefe9/_data -> /var/lib/zookeeper/log

결론

Kafka가 죽는 직접 트리거:

  • ZooKeeper의 cluster.id(새로 생성됨) ≠ Kafka 디스크의 cluster.id(meta.properties에 남아있음)
  • 그래서 Kafka가 InconsistentClusterIdException 던지고 종료

 


문제

Zookeeper 데이터가 의도한 ./docker-data/zookeeper에 안 쌓이고 있음

  • /Users/.../docker-data/zookeeper -> /var/lib/zookeeper (의도한 bind mount)
  • /var/lib/docker/volumes/... -> /var/lib/zookeeper/data
  • /var/lib/docker/volumes/... -> /var/lib/zookeeper/log

컨테이너 안에서 /var/lib/zookeeper는 호스트 폴더로 붙였는데,
그 안의 핵심 디렉토리인 /var/lib/zookeeper/data, /var/lib/zookeeper/log는 “익명(anonymous) 볼륨”이 따로 덮어씌워져 있음.

 

 

즉, 진짜 중요한 ZK 상태(클러스터 ID 포함)는 익명 볼륨에 저장되고,
컨테이너가 재생성되면 그 익명 볼륨이 새로 생기면서 cluster.id가 바뀔 수 있음 → Kafka는 기존 meta.properties를 들고 있어서 ID mismatch 터짐.

 

  • 컨테이너가 한번 재생성(recreate) 되었거나 (up -d 하면서 설정 바뀌어 recreate, 또는 down/up, 이미지 재풀 등)
  • 그때 ZK의 익명 볼륨이 새로 붙으면서 cluster.id가 바뀐 거라고 보면 됨.

상위 디렉터리를 bind해서 생긴 문제임.

- ./docker-data/zookeeper:/var/lib/zookeeper

컨테이너가 뜰 때 더 구체적인 마운트(하위 경로) 가 우선으로 적용돼서:

  • /var/lib/zookeeper → 호스트 폴더에 붙음 ✅
  • 근데 /var/lib/zookeeper/data익명 볼륨이 덮어씀
  • /var/lib/zookeeper/log익명 볼륨이 덮어씀

 

그래서 “진짜 중요한 ZK 상태(스냅샷/로그/cluster id)”는
기대한 ./docker-data/zookeeper/...에 저장되지 않고,
도커가 만든 익명 볼륨 안으로 들어가버린 거.

 

그 결과, 컨테이너가 한 번 recreate 되거나(또는 down -v 같은 거) 익명 볼륨이 바뀌는 순간
ZK의 cluster id가 새로 만들어지고 → Kafka의 meta.properties랑 mismatch가 터진 것.

 

따라서,

- ./docker-data/zookeeper/data:/var/lib/zookeeper/data
- ./docker-data/zookeeper/log:/var/lib/zookeeper/log

아예 하위 경로를 직접 바인드해버리면 익명 볼륨이 끼어들 틈이 없어짐.


조치 결과
docker inspect DI-kafka-1 --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'
docker inspect DI-zookeeper --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

/Users/tars/Documents/namu/gitlab/di-backend/docker-data/kafka -> /var/lib/kafka/data
/var/lib/docker/volumes/d5849ed8d6e705530c7559a38119be9f4c58cb31821165be311fd491043e81dd/_data -> /etc/kafka/secrets

/Users/tars/Documents/namu/gitlab/di-backend/docker-data/zookeeper/data -> /var/lib/zookeeper/data
/Users/tars/Documents/namu/gitlab/di-backend/docker-data/zookeeper/log -> /var/lib/zookeeper/log
/var/lib/docker/volumes/fecffd194e9ae3ee5fd3c0bbbf9179e1c75316e104f79b3910638e1f16611161/_data -> /etc/zookeeper/secrets

이제 ZK 핵심 상태(스냅샷/로그/cluster id)가 호스트 폴더에 영속 저장됨. 더 이상 익명 볼륨이 data/log를 덮어쓰지 않음.