본문 바로가기
DataOps/Kafka

Strimzi 기반 Kafka 3.x → KRaft 전환 가이드

by BenKangKang 2026. 1. 26.

Strimzi 기반 Kafka: ZooKeeper → KRaft 전환 기록

Strimzi와 Kafka 업그레이드를 담당하면서, 최신 Kafka 버전에서 ZooKeeper 지원이 종료됨에 따라 KRaft 기반 클러스터로 마이그레이션이 필요한 상황이 되었다. 같은 과정을 진행할 누군가에게 도움이 되기를 바라는 마음으로 기록을 남긴다.

배경

Apache Kafka는 다음과 같이 아키텍처가 변경된다.

  • Kafka 3.x: ZooKeeper 의존
  • Kafka 4.0+: KRaft(Kafka Raft) 기반 메타데이터 관리
    • ZooKeeper 완전 제거
    • Kafka 3.9가 3.x 계열의 마지막 버전

따라서 향후 업그레이드·운영을 고려하면 ZooKeeper → KRaft 전환은 필수이다.

현재 환경

  • strimzi-kafka-operator: 0.45.0
  • kafka: 3.9.0

참고 자료 영상도 함께 남긴다.
https://www.youtube.com/watch?v=CxTCgxiA2H8&list=PLj6h78yzYM2Mh0PGvD6jcn_MSNlvg4cWn


1. Broker Node 배포(우선 교체)

가장 중요한 규칙: 반드시 Broker → Controller 순서로 배포해야 한다.

그 이유는 다음과 같다:

  • 기존 메시지를 유지한 채 마이그레이션하려면 broker를 먼저 교체해야 한다.
  • Strimzi의 controller/broker node pool은 StatefulSet index 순서에 따라 PVC가 매핑된다.
  • controller를 먼저 배포하면 controller가 0번 인덱스를 차지해 기존 broker PVC가 잘못 바인딩되는 문제가 발생한다.
    • 결과적으로 기존 PVC 데이터가 유실된 것처럼 동작하며 클러스터가 초기화됨.

Kafka CR 설정: node-pool enabled, kraft disabled

resource "kubernetes_manifest" "kafka" {
  manifest = {
    apiVersion = "kafka.strimzi.io/v1beta2"
    kind       = "Kafka"
    metadata = {
      name      = local.cluster_name
      namespace = kubernetes_namespace.kafka.metadata[0].name
      labels = {
        "app.kubernetes.io/managed-by" = "terraform"
      }
      annotations = {
        "strimzi.io/kraft"      = "disabled"
        "strimzi.io/node-pools" = "enabled"
      }
    }
  }
}

Broker NodePool 스펙 정의

  • 기존 PVC와 동일한 용량(예: 140Gi)
  • NodePool 이름을 기존 broker 이름과 동일하게 설정 (예: kafka-kafka-0 형태)
resource "kubernetes_manifest" "kafka-node-pool-broker" {
  manifest = {
    apiVersion = "kafka.strimzi.io/v1beta2"
    kind       = "KafkaNodePool"
    metadata   = {
      name      = "kafka"
      namespace = local.namespace
      labels    = {
        "strimzi.io/cluster"           = local.cluster_name
        "app.kubernetes.io/managed-by" = "terraform"
      }
    }
    spec = {
      replicas = 3
      roles    = ["broker"]
      storage  = {
        type    = "jbod"
        volumes = [{
          id          = 0
          type        = "persistent-claim"
          size        = "140Gi"
          deleteClaim = false
        }]
      }
      resources = {
        requests = {
          cpu    = "500m"
          memory = "3Gi"
        }
        limits = {
          memory = "3Gi"
        }
      }
      template = {
        pod = {
          priorityClassName = "system-cluster-critical"
        }
      }
    }
  }
}

apply 후 결과

  • kafka-kafka-0~2 broker pod가 NodePool 기반으로 재구성되어 재시작됨.

2. Controller NodePool 배포

ZooKeeper를 대체할 controller 노드를 구성한다.

resource "kubernetes_manifest" "kafka-node-pool-controller" {
  manifest = {
    apiVersion = "kafka.strimzi.io/v1beta2"
    kind       = "KafkaNodePool"
    metadata   = {
      name      = "controller"
      namespace = local.namespace
      labels    = {
        "strimzi.io/cluster"           = local.cluster_name
        "app.kubernetes.io/managed-by" = "terraform"
      }
    }
    spec = {
      replicas = 3
      roles    = ["controller"]
      storage  = {
        type    = "jbod"
        volumes = [{
          id          = 0
          type        = "persistent-claim"
          size        = "10Gi"
          deleteClaim = false
        }]
      }
      resources = {
        requests = {
          cpu    = "500m"
          memory = "1Gi"
        }
        limits = {
          memory = "1Gi"
        }
      }
      template = {
        pod = {
          priorityClassName = "system-cluster-critical"
        }
      }
    }
  }
}

apply 후 결과

  • 아직 kraft = disabled 상태이므로 컨트롤러는 생성되지만 Kafka는 KRaft 모드로 전환되지 않음.

3. KRaft 마이그레이션 시작

이제 Kafka CR의 annotation을 수정해 migration 모드로 진입시킨다.

annotations = {
  "strimzi.io/kraft"      = "migration"
  "strimzi.io/node-pools" = "enabled"
}

결과

  • broker가 재시작되며 migration 절차가 시작된다.
  • controller pod들이 정상적으로 기동됨.

4. 마이그레이션 완료 처리

Kafka CRD의 Status가 KRaftPostMigration 상태가 되면
마이그레이션이 정상적으로 완료된 것이다.

이제 운영 모드로 전환하기 위해 annotation을 다시 변경한다.

annotations = {
  "strimzi.io/kraft"      = "enabled"
  "strimzi.io/node-pools" = "enabled"
}

결과

  • 잠시 후 Kafka 클러스터 상태가 KRaft로 변경된다.
  • ZooKeeper 의존성이 완전히 제거된 구성으로 운영 가능하다.

참고 자료

댓글