Haru Utils

EVENT STREAMING

Kafka KRaft 단일·다중 노드 구성

Apache Kafka 4.3 지원 릴리스를 서명 검증해 설치하고 단일 combined와 운영용 3 controller·분리 broker를 나눠, Cluster ID·스토리지 포맷·PKCS12 mTLS·StandardAuthorizer ACL을 안전하게 구성합니다.
Kafka KRaftKafka 단일 노드Kafka 다중 노드Kafka controller quorumKafka cluster ID
지원 환경Apache Kafka 4.3 지원 패치 릴리스 · Linux x86-64
예상 시간120
난이도고급
검토일2026-08-28

BEFORE YOU START

시작 전에 준비하세요

01

Apache Kafka 공식 지원 릴리스의 binary archive·asc·sha512와 KEYS

02

운영 다중 노드용 3개 controller와 별도 broker, 고유 node.id·고정 사설 DNS

03

각 노드의 빈 전용 metadata.log.dir·log.dirs와 복구 가능한 볼륨

04

노드별 TLS 인증서·truststore, 별도 break-glass 관리자·모니터 인증서와 비밀 저장소

05

인증서 DN별 node·관리자·앱·모니터 역할표, 방화벽·복구 콘솔

권장 대상 ZooKeeper 없는 신규 Kafka를 만들면서 단일 개발 구성과 운영 다중 노드의 쿼럼·스토리지·TLS 경계를 정확히 분리하려는 플랫폼 운영자

FOLLOW THE RECIPE

8단계 구성·점검 레시피

1
확인시스템을 변경하지 않는 점검 단계

단일 개발과 다중 운영 토폴로지 분리

단일 combined 노드는 개발·비핵심 검증에만 사용합니다. 운영은 controller와 broker 역할을 분리하고 3 또는 5 controller로 과반 쿼럼을 구성합니다.

OS·아키텍처·Java
cat /etc/os-release
uname -m
java -version
자원과 디스크
nproc
free -h
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS
df -hT /var/lib
호스트명과 DNS
hostname -f
getent hosts <CONTROLLER_1> <CONTROLLER_2> <CONTROLLER_3>
시간 동기화
timedatectl status
  • 단일 combined 모드는 운영 핵심 서비스에 사용하지 않습니다.
  • 운영 controller를 3개 이상 홀수로 배치하고 broker 역할과 분리했습니다.
  • 모든 node.id·사설 DNS·listener 포트를 중복 없이 자산 기록에 확정했습니다.
  • metadata와 broker log 볼륨의 백업·복구 목표를 정했습니다.
결과 읽기

KRaft는 controller 과반이 살아야 메타데이터 쓰기가 가능합니다. 3 controller는 1대 장애, 5 controller는 2대 장애를 견디지만 broker 복제 계수는 별도 설계입니다.

다음 판단

기존 Kafka·meta.properties·포트와 데이터 경로를 사전 점검합니다.

2
확인시스템을 변경하지 않는 점검 단계

기존 Cluster ID·스토리지·포트 점검

가장 중요한 중단 조건은 기존 meta.properties입니다. 하나라도 있으면 신규 Cluster ID 생성·스토리지 포맷을 금지하고 기존 클러스터 복구 또는 노드 추가 절차로 전환합니다.

기존 Kafka 프로세스
systemctl status kafka.service --no-pager
pgrep -a -u kafka java
기존 리스너
sudo ss -lntup | grep -E ':(9092|9093)[[:space:]]'
기존 metadata marker
sudo find /var/lib/kafka -name meta.properties -type f -print
한 개라도 나오면 신규 포맷 절차를 즉시 중단합니다. 파일 내용은 아직 바꾸지 않습니다.
기존 데이터 메타데이터
sudo find /var/lib/kafka -maxdepth 3 -type d -printf '%U %G %m %p
'
마운트와 여유공간
findmnt -T /var/lib/kafka
df -hT /var/lib/kafka
df -i /var/lib/kafka
  • 모든 신규 대상 경로에 meta.properties가 없음을 노드별로 확인했습니다.
  • 기존 클러스터 노드는 신규 설치 절차에서 제외했습니다.
  • metadata와 broker log가 임시·공유 충돌 경로가 아닙니다.
  • 9092·9093의 기존 소유 프로세스가 없습니다.
결과 읽기

meta.properties가 있는 경로를 비우거나 다른 Cluster ID로 다시 포맷하면 기존 클러스터와 데이터가 분리·손상될 수 있습니다. 자동 복구 명령을 실행하지 않습니다.

다음 판단

공식 KEYS·서명·SHA-512를 검증한 아카이브만 배치합니다.

3
변경패키지·설정·서비스 상태가 달라지는 단계

공식 서명 검증과 전용 계정 설치

Kafka Downloads에서 같은 지원 릴리스의 binary archive, asc, sha512와 KEYS를 받습니다. KEYS의 서명자 지문을 공식 Apache 배포 절차와 대조한 뒤 서명과 해시를 모두 검증합니다.

변경 단계입니다. 대상 서버, 백업 파일, 서비스 중단 영향과 바로 이전 상태로 돌아가는 방법을 다시 확인하세요.
릴리스 파일 확인
ls -lh kafka_2.13-<KAFKA_VERSION>.tgz kafka_2.13-<KAFKA_VERSION>.tgz.asc kafka_2.13-<KAFKA_VERSION>.tgz.sha512 KEYS
격리 GPG 홈 준비
mkdir -p -m 0700 ./kafka-gpg-verify
gpg --homedir ./kafka-gpg-verify --import ./KEYS
릴리스 서명 검증
gpg --homedir ./kafka-gpg-verify --verify kafka_2.13-<KAFKA_VERSION>.tgz.asc kafka_2.13-<KAFKA_VERSION>.tgz
SHA-512 검증
sha512sum -c kafka_2.13-<KAFKA_VERSION>.tgz.sha512
서비스·모니터 전용 계정
sudo useradd --system --home-dir /var/lib/kafka --create-home --shell /usr/sbin/nologin kafka
sudo useradd --system --home-dir /var/lib/kafka-monitor --create-home --shell /usr/sbin/nologin kafka-monitor
계정이 이미 있으면 UID·그룹·홈·셸을 확인하고 다시 만들지 않습니다. 두 계정을 서로의 그룹에 넣지 않습니다.
설치·데이터·설정 경로
sudo install -d -m 0755 -o root -g root /opt/kafka /etc/kafka
sudo install -d -m 0750 -o kafka -g kafka /var/lib/kafka/meta /var/lib/kafka/logs /var/log/kafka
신규 설치 경로 비어 있음
sudo test -z "$(sudo find /opt/kafka -mindepth 1 -maxdepth 1 -print -quit)"
아카이브 배치
sudo tar --no-overwrite-dir --strip-components=1 -xzf kafka_2.13-<KAFKA_VERSION>.tgz -C /opt/kafka
sudo chown -R root:root /opt/kafka
  • Downloads의 지원 릴리스를 선택하고 asc·SHA-512를 모두 검증했습니다.
  • 기존 /opt/kafka 또는 데이터 경로를 덮어쓰지 않았습니다.
  • kafka 계정은 로그인할 수 없고 데이터·로그 경로만 씁니다.
  • kafka-monitor 계정은 Kafka 서비스·관리자 그룹과 분리했습니다.
  • 모든 노드에 같은 Kafka 패치 버전과 호환 JDK를 설치했습니다.
결과 읽기

Good signature만 보고 끝내지 않고 KEYS 지문 출처와 SHA-512까지 확인합니다. 검증 실패 파일을 실행하거나 미러를 임의로 바꾸지 않습니다.

다음 판단

단일·다중 설정 파일, TLS와 systemd 실행 경계를 구성합니다.

4
주의권한·연결·중단 영향을 확인할 단계

역할별 KRaft·TLS·systemd 구성

단일 개발은 server.properties, 운영은 controller.properties와 broker.properties를 분리합니다. 각 노드의 node.id는 고유해야 하고 모든 노드는 동일한 controller.quorum.bootstrap.servers 목록을 사용합니다.

기존 단일 설정 백업
sudo cp --archive --no-clobber /etc/kafka/server.properties /etc/kafka/server.properties.<BACKUP_SUFFIX>.bak
기존 파일이 있을 때만 실행합니다.
단일 개발 설정 편집
sudoedit /etc/kafka/server.properties
기존 controller 설정 백업
sudo cp --archive --no-clobber /etc/kafka/controller.properties /etc/kafka/controller.properties.<BACKUP_SUFFIX>.bak
운영 다중 노드에서 기존 파일이 있을 때만 실행합니다.
운영 controller 설정 편집
sudoedit /etc/kafka/controller.properties
기존 broker 설정 백업
sudo cp --archive --no-clobber /etc/kafka/broker.properties /etc/kafka/broker.properties.<BACKUP_SUFFIX>.bak
운영 broker에서 기존 파일이 있을 때만 실행합니다.
운영 broker 설정 편집
sudoedit /etc/kafka/broker.properties
TLS 비밀 파일 편집
sudoedit /etc/kafka/secrets.properties
keystore·truststore 비밀번호를 대화형 편집기에 입력하고 화면·클립보드 기록을 지웁니다.
TLS 파일 경로 준비
sudo install -d -m 0750 -o root -g kafka /etc/kafka/tls
sudo stat -c '%U %G %a %n' /etc/kafka/tls/node.p12 /etc/kafka/tls/truststore.p12
노드마다 고유한 node.p12와 신뢰 저장소를 배치합니다. node 인증서를 관리·앱 CLI에 재사용하지 않습니다.
root 전용 관리자 경로
sudo install -d -m 0700 -o root -g root /root/kafka-admin
sudo stat -c '%U %G %a %n' /root/kafka-admin/admin-client.p12 /root/kafka-admin/truststore.p12
별도 break-glass 관리자 인증서와 truststore를 사전 발급·배치한 뒤 실행합니다.
관리자 client·비밀 설정 편집
sudoedit /root/kafka-admin/client.properties
sudoedit /root/kafka-admin/secrets.properties
root만 읽는 파일에 관리자 인증서 비밀번호를 넣고 일상 모니터링에는 사용하지 않습니다.
모니터 전용 경로·설정
sudo install -d -m 0750 -o root -g kafka-monitor /etc/kafka/monitor
sudoedit /etc/kafka/monitor/client.properties
sudoedit /etc/kafka/monitor/secrets.properties
sudo stat -c '%U %G %a %n' /etc/kafka/monitor/monitor-client.p12 /etc/kafka/monitor/truststore.p12
별도 모니터 인증서를 사용하며 아직 ACL을 부여하기 전에는 접속이 거부되는 것이 정상입니다.
노드·관리자·모니터 권한 분리
sudo chown root:kafka /etc/kafka/<ROLE_CONFIG>.properties /etc/kafka/secrets.properties /etc/kafka/tls/node.p12 /etc/kafka/tls/truststore.p12
sudo chmod 640 /etc/kafka/<ROLE_CONFIG>.properties /etc/kafka/secrets.properties /etc/kafka/tls/node.p12 /etc/kafka/tls/truststore.p12
sudo chown root:root /root/kafka-admin/admin-client.p12 /root/kafka-admin/truststore.p12 /root/kafka-admin/client.properties /root/kafka-admin/secrets.properties
sudo chmod 600 /root/kafka-admin/admin-client.p12 /root/kafka-admin/truststore.p12 /root/kafka-admin/client.properties /root/kafka-admin/secrets.properties
sudo chown root:kafka-monitor /etc/kafka/monitor/monitor-client.p12 /etc/kafka/monitor/truststore.p12 /etc/kafka/monitor/client.properties /etc/kafka/monitor/secrets.properties
sudo chmod 640 /etc/kafka/monitor/monitor-client.p12 /etc/kafka/monitor/truststore.p12 /etc/kafka/monitor/client.properties /etc/kafka/monitor/secrets.properties
<ROLE_CONFIG>는 이 호스트의 server·controller·broker 중 하나입니다. kafka 서비스 계정은 관리자·모니터 파일을 읽을 수 없어야 합니다.
기존 유닛 백업
sudo cp --archive --no-clobber /etc/systemd/system/kafka.service /etc/systemd/system/kafka.service.<BACKUP_SUFFIX>.bak
기존 파일이 있을 때만 실행합니다.
systemd 유닛 편집
sudoedit /etc/systemd/system/kafka.service
설정 예시 · /etc/kafka/server.properties
개발 전용 단일 combined 노드
process.roles=broker,controller
node.id=1
controller.quorum.bootstrap.servers=<DEV_PRIVATE_HOST>:9093
controller.listener.names=CONTROLLER
listeners=CONTROLLER://<DEV_PRIVATE_HOST>:9093,CLIENT://127.0.0.1:9092
advertised.listeners=CLIENT://127.0.0.1:9092
listener.security.protocol.map=CONTROLLER:SSL,CLIENT:SSL
inter.broker.listener.name=CLIENT
metadata.log.dir=/var/lib/kafka/meta
log.dirs=/var/lib/kafka/logs
auto.create.topics.enable=false
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer
allow.everyone.if.no.acl.found=false
super.users=User:<DEV_NODE_CERT_DN>;User:<BREAK_GLASS_ADMIN_CERT_DN>
config.providers=file
config.providers.file.class=org.apache.kafka.common.config.provider.FileConfigProvider
config.providers.file.param.allowed.paths=/etc/kafka/secrets.properties
ssl.keystore.type=PKCS12
ssl.keystore.location=/etc/kafka/tls/node.p12
ssl.keystore.password=${file:/etc/kafka/secrets.properties:ssl.keystore.password}
ssl.key.password=${file:/etc/kafka/secrets.properties:ssl.key.password}
ssl.truststore.type=PKCS12
ssl.truststore.location=/etc/kafka/tls/truststore.p12
ssl.truststore.password=${file:/etc/kafka/secrets.properties:ssl.truststore.password}
listener.name.controller.ssl.client.auth=required
listener.name.client.ssl.client.auth=required
개발 단일 노드 전용입니다. 운영에는 사용하지 않습니다.
설정 예시 · /etc/kafka/controller.properties
운영 전용 controller 노드
process.roles=controller
node.id=<UNIQUE_CONTROLLER_ID>
controller.quorum.bootstrap.servers=<CONTROLLER_1>:9093,<CONTROLLER_2>:9093,<CONTROLLER_3>:9093
controller.listener.names=CONTROLLER
listeners=CONTROLLER://<THIS_CONTROLLER_PRIVATE_HOST>:9093
listener.security.protocol.map=CONTROLLER:SSL
metadata.log.dir=/var/lib/kafka/meta
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer
allow.everyone.if.no.acl.found=false
super.users=User:<CONTROLLER_1_CERT_DN>;User:<CONTROLLER_2_CERT_DN>;User:<CONTROLLER_3_CERT_DN>;<BROKER_NODE_CERT_DNS_AS_USER_ENTRIES>;User:<BREAK_GLASS_ADMIN_CERT_DN>
config.providers=file
config.providers.file.class=org.apache.kafka.common.config.provider.FileConfigProvider
config.providers.file.param.allowed.paths=/etc/kafka/secrets.properties
ssl.keystore.type=PKCS12
ssl.keystore.location=/etc/kafka/tls/node.p12
ssl.keystore.password=${file:/etc/kafka/secrets.properties:ssl.keystore.password}
ssl.key.password=${file:/etc/kafka/secrets.properties:ssl.key.password}
ssl.truststore.type=PKCS12
ssl.truststore.location=/etc/kafka/tls/truststore.p12
ssl.truststore.password=${file:/etc/kafka/secrets.properties:ssl.truststore.password}
listener.name.controller.ssl.client.auth=required
<BROKER_NODE_CERT_DNS_AS_USER_ENTRIES>는 각 broker 인증서의 정확한 DN을 User:<DN> 형식으로 세미콜론 구분해 펼칩니다. app·monitor 인증서는 super.users에 넣지 않습니다.
설정 예시 · /etc/kafka/broker.properties
운영 전용 broker 노드
process.roles=broker
node.id=<UNIQUE_BROKER_ID>
controller.quorum.bootstrap.servers=<CONTROLLER_1>:9093,<CONTROLLER_2>:9093,<CONTROLLER_3>:9093
controller.listener.names=CONTROLLER
listeners=CLIENT://<THIS_BROKER_PRIVATE_HOST>:9092
advertised.listeners=CLIENT://<THIS_BROKER_CLIENT_DNS>:9092
listener.security.protocol.map=CONTROLLER:SSL,CLIENT:SSL
inter.broker.listener.name=CLIENT
metadata.log.dir=/var/lib/kafka/meta
log.dirs=/var/lib/kafka/logs
auto.create.topics.enable=false
authorizer.class.name=org.apache.kafka.metadata.authorizer.StandardAuthorizer
allow.everyone.if.no.acl.found=false
super.users=User:<CONTROLLER_1_CERT_DN>;User:<CONTROLLER_2_CERT_DN>;User:<CONTROLLER_3_CERT_DN>;<BROKER_NODE_CERT_DNS_AS_USER_ENTRIES>;User:<BREAK_GLASS_ADMIN_CERT_DN>
config.providers=file
config.providers.file.class=org.apache.kafka.common.config.provider.FileConfigProvider
config.providers.file.param.allowed.paths=/etc/kafka/secrets.properties
ssl.keystore.type=PKCS12
ssl.keystore.location=/etc/kafka/tls/node.p12
ssl.keystore.password=${file:/etc/kafka/secrets.properties:ssl.keystore.password}
ssl.key.password=${file:/etc/kafka/secrets.properties:ssl.key.password}
ssl.truststore.type=PKCS12
ssl.truststore.location=/etc/kafka/tls/truststore.p12
ssl.truststore.password=${file:/etc/kafka/secrets.properties:ssl.truststore.password}
listener.name.client.ssl.client.auth=required
모든 노드가 같은 정확한 super.users 목록을 사용하되 app·monitor 인증서는 제외하고 ACL로만 허용합니다.
설정 예시 · /root/kafka-admin/client.properties
root 전용 break-glass 관리 CLI
security.protocol=SSL
ssl.endpoint.identification.algorithm=https
ssl.keystore.type=PKCS12
ssl.keystore.location=/root/kafka-admin/admin-client.p12
ssl.keystore.password=${file:/root/kafka-admin/secrets.properties:ssl.keystore.password}
ssl.key.password=${file:/root/kafka-admin/secrets.properties:ssl.key.password}
ssl.truststore.type=PKCS12
ssl.truststore.location=/root/kafka-admin/truststore.p12
ssl.truststore.password=${file:/root/kafka-admin/secrets.properties:ssl.truststore.password}
config.providers=file
config.providers.file.class=org.apache.kafka.common.config.provider.FileConfigProvider
config.providers.file.param.allowed.paths=/root/kafka-admin/secrets.properties
super.users에 정확히 일치하는 관리자 인증서 DN을 등록하지만 파일은 root 0600으로 유지하고 초기 ACL·비상 작업에만 사용합니다.
설정 예시 · /etc/kafka/monitor/client.properties
별도 모니터 주체의 읽기 전용 CLI
security.protocol=SSL
ssl.endpoint.identification.algorithm=https
ssl.keystore.type=PKCS12
ssl.keystore.location=/etc/kafka/monitor/monitor-client.p12
ssl.keystore.password=${file:/etc/kafka/monitor/secrets.properties:ssl.keystore.password}
ssl.key.password=${file:/etc/kafka/monitor/secrets.properties:ssl.key.password}
ssl.truststore.type=PKCS12
ssl.truststore.location=/etc/kafka/monitor/truststore.p12
ssl.truststore.password=${file:/etc/kafka/monitor/secrets.properties:ssl.truststore.password}
config.providers=file
config.providers.file.class=org.apache.kafka.common.config.provider.FileConfigProvider
config.providers.file.param.allowed.paths=/etc/kafka/monitor/secrets.properties
monitor 인증서 DN은 super.users에 넣지 않고 다음 보안 단계에서 Describe만 허용합니다.
설정 예시 · /etc/systemd/system/kafka.service
포맷 완료 marker를 요구하는 Kafka 유닛
[Unit]
Description=Apache Kafka KRaft
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=kafka
Group=kafka
Environment="KAFKA_HEAP_OPTS=-Xms1g -Xmx1g"
ExecStartPre=/usr/bin/test -f /var/lib/kafka/meta/meta.properties
ExecStart=/opt/kafka/bin/kafka-server-start.sh /etc/kafka/<ROLE_CONFIG>.properties
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=10
LimitNOFILE=100000
NoNewPrivileges=true
TimeoutStopSec=180

[Install]
WantedBy=multi-user.target
<ROLE_CONFIG>는 단일 server, 운영 controller 또는 broker 중 이 노드 역할 하나로 바꿉니다.
  • 단일 개발과 운영 다중 노드 설정을 같은 클러스터에 섞지 않았습니다.
  • 운영 controller는 process.roles=controller, broker는 process.roles=broker로 분리했습니다.
  • 모든 node.id가 고유하고 controller bootstrap 주소가 전 노드에서 동일합니다.
  • CLIENT·CONTROLLER listener가 TLS이고 인증서 hostname과 advertised listener가 일치합니다.
  • PKCS12 형식을 노드·관리자·모니터 설정에 명시했습니다.
  • node·break-glass 관리자·모니터 인증서와 OS 파일 권한을 서로 분리했습니다.
  • 비밀번호는 서버 설정이나 명령 인자에 직접 넣지 않았습니다.
결과 읽기

설정 파일이 올바라도 아직 스토리지는 초기화되지 않았습니다. 다음 단계의 비가역 승인 전에는 서비스를 시작하지 않습니다.

다음 판단

기존 meta.properties 부재와 Cluster ID 변경기록을 다시 확인한 뒤 단 한 번의 수동 포맷을 승인합니다.

5
변경패키지·설정·서비스 상태가 달라지는 단계

Cluster ID 단일 생성·분기별 포맷·기동

신규 클러스터에서만 Cluster ID를 한 번 생성해 변경기록에 저장합니다. 포맷은 되돌릴 수 없는 경계입니다. 두 사람이 빈 경로·역할·ID를 대조한 뒤 개발 단일, 최초 운영 controller, 기존 쿼럼에 추가할 broker·controller 중 정확히 한 분기만 실행합니다.

변경 단계입니다. 대상 서버, 백업 파일, 서비스 중단 영향과 바로 이전 상태로 돌아가는 방법을 다시 확인하세요.
포맷 전 marker 재확인
sudo find /var/lib/kafka -name meta.properties -type f -print
sudo -u kafka /opt/kafka/bin/kafka-storage.sh info -c /etc/kafka/<ROLE_CONFIG>.properties
meta.properties가 나오거나 info가 기존 포맷을 보고하면 즉시 중단합니다.
신규 Cluster ID 한 번 생성
sudo -u kafka /opt/kafka/bin/kafka-storage.sh random-uuid
출력을 운영 변경기록 한 곳에 저장합니다. 각 노드에서 다시 생성하지 않습니다.
운영 controller directory ID 준비
sudo -u kafka /opt/kafka/bin/kafka-storage.sh random-uuid
최초 다중 controller 분기에서 controller마다 한 번씩 생성해 node.id·DNS·directory ID 대응표를 승인합니다. Cluster ID와 혼동하지 않습니다. 개발 단일과 broker 전용 분기에서는 생략합니다.
A · 개발 단일 controller 포맷
sudo test ! -e /var/lib/kafka/meta/meta.properties && sudo -u kafka /opt/kafka/bin/kafka-storage.sh format --cluster-id <APPROVED_CLUSTER_ID> --standalone --config /etc/kafka/server.properties
개발 전용 combined 노드에서만 실행합니다. <APPROVED_CLUSTER_ID>를 변경기록의 값으로 교체하고 운영 다중 노드에서는 실행하지 않습니다.
B · 최초 운영 controller 3대 포맷
sudo test ! -e /var/lib/kafka/meta/meta.properties && sudo -u kafka /opt/kafka/bin/kafka-storage.sh format --cluster-id <APPROVED_CLUSTER_ID> --initial-controllers "<CONTROLLER_ID_1>@<CONTROLLER_1>:9093:<CONTROLLER_DIRECTORY_ID_1>,<CONTROLLER_ID_2>@<CONTROLLER_2>:9093:<CONTROLLER_DIRECTORY_ID_2>,<CONTROLLER_ID_3>@<CONTROLLER_3>:9093:<CONTROLLER_DIRECTORY_ID_3>" --config /etc/kafka/controller.properties
최초 3개 controller에서만 실행하며 세 노드 모두 같은 Cluster ID와 완전히 동일한 initial-controllers 목록을 사용합니다. 각 노드의 node.id와 대응하는 directory ID를 먼저 대조합니다.
C · 기존 쿼럼에 broker·추가 controller 포맷
sudo test ! -e /var/lib/kafka/meta/meta.properties && sudo -u kafka /opt/kafka/bin/kafka-storage.sh format --cluster-id <EXISTING_CLUSTER_ID> --no-initial-controllers --config /etc/kafka/<ROLE_CONFIG>.properties
건강한 기존 쿼럼의 ClusterId를 대조한 broker 또는 추가 controller에서만 실행합니다. 추가 controller는 기동·catch-up 뒤 공식 add-controller 절차가 별도로 필요합니다.
포맷 후 정보 확인
sudo -u kafka /opt/kafka/bin/kafka-storage.sh info -c /etc/kafka/<ROLE_CONFIG>.properties
선택한 한 분기의 포맷 후 실행합니다. 모든 노드에서 같은 Cluster ID와 예상 경로인지 대조합니다.
유닛 검증
sudo systemd-analyze verify /etc/systemd/system/kafka.service
marker와 권한
sudo -u kafka test -r /var/lib/kafka/meta/meta.properties
sudo stat -c '%U %G %a %n' /var/lib/kafka/meta/meta.properties
controller 우선 시작
sudo systemctl daemon-reload
sudo systemctl enable kafka.service
sudo systemctl start kafka.service
운영 다중 노드는 controller 과반을 먼저 시작·검증한 뒤 broker를 한 대씩 시작합니다.
상태와 로그
systemctl status kafka.service --no-pager
sudo journalctl -u kafka.service -n 180 --no-pager
  • 기존 marker가 없는 신규 클러스터에서만 Cluster ID를 생성했습니다.
  • 하나의 Cluster ID를 모든 노드에 동일하게 사용하고 다시 생성하지 않았습니다.
  • 단일 모드는 standalone, 다중 초기 controller는 동일 initial-controller 집합을 사용하는 현재 공식 절차로 수동 승인했습니다.
  • 다중 초기 controller는 각 노드의 고유 directory ID를 한 번씩 만들고, 모든 노드에서 동일한 node@host:port:directory-id 목록을 대조했습니다.
  • 추가 broker·controller는 기존 Cluster ID와 공식 no-initial-controller 절차를 사용했습니다.
  • 운영 controller 과반이 정상인 뒤 broker를 한 대씩 시작했습니다.
결과 읽기

format은 빈 디렉터리 자동 복구 명령이 아닙니다. 기존 클러스터의 빈 경로나 손실된 metadata를 새 Cluster ID로 포맷하면 committed metadata를 잃을 수 있습니다.

다음 판단

쿼럼·broker API·두 번째 TLS 클라이언트 연결을 검증합니다.

6
주의권한·연결·중단 영향을 확인할 단계

KRaft 쿼럼과 TLS 클라이언트 검증

controller 리더·voter·lag를 확인하고 broker API를 TLS client 설정으로 조회합니다. 단일 개발과 다중 운영의 기대 voter 수를 다르게 판정합니다.

KRaft feature
sudo /opt/kafka/bin/kafka-features.sh --command-config /root/kafka-admin/client.properties --bootstrap-controller <CONTROLLER_1>:9093 describe
쿼럼 상태
sudo /opt/kafka/bin/kafka-metadata-quorum.sh --command-config /root/kafka-admin/client.properties --bootstrap-controller <CONTROLLER_1>:9093 describe --status
쿼럼 복제
sudo /opt/kafka/bin/kafka-metadata-quorum.sh --command-config /root/kafka-admin/client.properties --bootstrap-controller <CONTROLLER_1>:9093 describe --replication
Broker API
sudo /opt/kafka/bin/kafka-broker-api-versions.sh --command-config /root/kafka-admin/client.properties --bootstrap-server <BROKER_1>:9092
두 번째 controller 경유 상태
sudo /opt/kafka/bin/kafka-metadata-quorum.sh --command-config /root/kafka-admin/client.properties --bootstrap-controller <CONTROLLER_2>:9093 describe --status
단일 개발 모드에서는 생략합니다.
서비스와 리스너
systemctl is-active kafka.service
sudo ss -lntp | grep -E ':(9092|9093)[[:space:]]'
  • 단일 개발은 voter 1개, 운영은 계획한 3개 이상 voter와 leader를 확인했습니다.
  • 모든 controller의 ClusterId가 같고 follower lag가 안정적으로 따라옵니다.
  • broker API가 TLS client 설정으로 응답합니다.
  • 두 번째 controller bootstrap에서도 같은 ClusterId·leader가 보입니다.
  • 테스트 topic의 replication factor·min.insync.replicas를 운영 기준으로 별도 검증했습니다.
결과 읽기

쿼럼 상태가 보인다고 broker 데이터 복제가 자동으로 안전한 것은 아닙니다. topic replication factor, ISR, rack awareness와 producer acks를 별도로 점검합니다.

다음 판단

listener 인증·ACL·모니터링과 백업 정책을 강화합니다.

7
주의권한·연결·중단 영향을 확인할 단계

인증서 주체별 최소 ACL·네트워크 강화

StandardAuthorizer의 기본 거부를 유지하고 root 전용 break-glass 인증서로 앱·모니터 주체에 필요한 권한만 부여합니다. controller 9093은 controller·broker 사설망에서만, 9092는 승인된 client CIDR에서만 접근하게 합니다.

리스너 노출
sudo ss -lntup | grep -E ':(9092|9093)[[:space:]]'
TLS 인증서 만료
sudo -u kafka keytool -list -v -storetype PKCS12 -keystore /etc/kafka/tls/node.p12
비밀번호는 대화형 프롬프트에만 입력하고 출력의 내부 이름은 외부 공유 전 가립니다.
기존 ACL 기준값
sudo /opt/kafka/bin/kafka-acls.sh --bootstrap-server <BROKER_1>:9092 --command-config /root/kafka-admin/client.properties --list
초기 빈 클러스터 또는 승인된 기존 ACL과 대조하고, 예상하지 못한 wildcard principal을 발견하면 변경을 중단합니다.
producer 주체 최소 ACL
sudo /opt/kafka/bin/kafka-acls.sh --bootstrap-server <BROKER_1>:9092 --command-config /root/kafka-admin/client.properties --add --allow-principal 'User:<APP_PRODUCER_CERT_DN>' --operation Write --operation Describe --topic '<APP_TOPIC_PREFIX>' --resource-pattern-type prefixed
sudo /opt/kafka/bin/kafka-acls.sh --bootstrap-server <BROKER_1>:9092 --command-config /root/kafka-admin/client.properties --add --allow-principal 'User:<APP_PRODUCER_CERT_DN>' --operation IdempotentWrite --cluster
인증서의 RFC2253 DN과 Kafka가 표시한 principal을 정확히 대조합니다. topic 생성은 별도 관리자 변경으로 수행합니다.
consumer 주체 최소 ACL
sudo /opt/kafka/bin/kafka-acls.sh --bootstrap-server <BROKER_1>:9092 --command-config /root/kafka-admin/client.properties --add --allow-principal 'User:<APP_CONSUMER_CERT_DN>' --operation Read --operation Describe --topic '<APP_TOPIC_PREFIX>' --group '<APP_GROUP_PREFIX>' --resource-pattern-type prefixed
모니터 주체 Describe ACL
sudo /opt/kafka/bin/kafka-acls.sh --bootstrap-server <BROKER_1>:9092 --command-config /root/kafka-admin/client.properties --add --allow-principal 'User:<MONITOR_CERT_DN>' --operation Describe --cluster
sudo /opt/kafka/bin/kafka-acls.sh --bootstrap-server <BROKER_1>:9092 --command-config /root/kafka-admin/client.properties --add --allow-principal 'User:<MONITOR_CERT_DN>' --operation Describe --operation DescribeConfigs --topic '<APP_TOPIC_PREFIX>' --resource-pattern-type prefixed
sudo /opt/kafka/bin/kafka-acls.sh --bootstrap-server <BROKER_1>:9092 --command-config /root/kafka-admin/client.properties --add --allow-principal 'User:<MONITOR_CERT_DN>' --operation Describe --group '<APP_GROUP_PREFIX>' --resource-pattern-type prefixed
TopicCommand의 상세 조회에는 topic DescribeConfigs도 필요합니다. group에는 지원되지 않으므로 topic·group ACL을 반드시 별도 명령으로 적용합니다.
ACL 적용 결과
sudo /opt/kafka/bin/kafka-acls.sh --bootstrap-server <BROKER_1>:9092 --command-config /root/kafka-admin/client.properties --list
모니터 주체의 일상 조회
sudo -u kafka-monitor /opt/kafka/bin/kafka-broker-api-versions.sh --command-config /etc/kafka/monitor/client.properties --bootstrap-server <BROKER_1>:9092
sudo -u kafka-monitor /opt/kafka/bin/kafka-topics.sh --command-config /etc/kafka/monitor/client.properties --bootstrap-server <BROKER_1>:9092 --describe --topic '<APP_TOPIC_PREFIX>.*'
monitor 주체의 produce·consume·ACL 변경과 접두사 밖 topic 조회가 거부되는지도 별도 테스트합니다.
OS 파일 권한 경계
sudo -u kafka test ! -r /root/kafka-admin/client.properties
sudo -u kafka test ! -r /etc/kafka/monitor/client.properties
sudo -u kafka-monitor test ! -r /etc/kafka/secrets.properties
sudo stat -c '%U %G %a %n' /etc/kafka/tls /root/kafka-admin /etc/kafka/monitor
최근 경고
sudo journalctl -u kafka.service -p warning --since today --no-pager
  • PLAINTEXT·SASL_PLAINTEXT listener를 공인·공유망에 노출하지 않았습니다.
  • controller 9093과 broker 9092의 소스 CIDR을 분리했습니다.
  • StandardAuthorizer와 allow.everyone.if.no.acl.found=false가 모든 역할 설정에 있습니다.
  • node와 break-glass 관리자만 super.users이며 앱·모니터 주체는 최소 ACL만 가집니다.
  • node·관리자·모니터 keystore와 비밀 파일을 서로 다른 OS 권한 경계에 보관합니다.
  • 관리자 ACL 목록과 모니터의 허용·거부 동작을 모두 검증했습니다.
  • controller lag, under-replicated partition, 디스크·JVM·인증서 만료 경보를 운영합니다.
결과 읽기

Kafka ACL을 켠 뒤 super.users나 broker·controller 주체가 잘못되면 클러스터 자체가 통신하지 못할 수 있습니다. 테스트 클러스터와 롤링 적용·두 번째 연결 검증이 필요합니다.

다음 판단

장애 시 재포맷 없이 서비스를 격리하고 설정·데이터를 보존합니다.

8
변경패키지·설정·서비스 상태가 달라지는 단계

서비스 격리와 Cluster ID·데이터 보존

문제가 생기면 producer 신규 쓰기를 중지하고 controller 과반을 함부로 동시에 내리지 않습니다. 해당 노드만 정상 중지하고 meta.properties와 log dirs를 그대로 보존합니다.

변경 단계입니다. 대상 서버, 백업 파일, 서비스 중단 영향과 바로 이전 상태로 돌아가는 방법을 다시 확인하세요.
쿼럼 상태 기록
sudo /opt/kafka/bin/kafka-metadata-quorum.sh --command-config /root/kafka-admin/client.properties --bootstrap-controller <HEALTHY_CONTROLLER>:9093 describe --status
대상 노드 중지
sudo systemctl stop kafka.service
systemctl is-active kafka.service
운영 controller는 중지해도 과반이 유지되는지 먼저 확인합니다.
기존 역할 설정 복원
sudo cp --preserve=all /etc/kafka/<ROLE_CONFIG>.properties.<BACKUP_SUFFIX>.bak /etc/kafka/<ROLE_CONFIG>.properties
기존 설정의 같은 변경 시점 백업이 있을 때만 실행합니다.
기존 유닛 복원
sudo cp --preserve=all /etc/systemd/system/kafka.service.<BACKUP_SUFFIX>.bak /etc/systemd/system/kafka.service
기존 설치 분기에서만 실행합니다.
신규 자동 시작 해제
sudo systemctl disable kafka.service
최초 설치 롤백 분기에서 실행합니다.
신규 유닛 보존 비활성화
sudo mv --no-clobber /etc/systemd/system/kafka.service /etc/systemd/system/kafka.service.disabled.<BACKUP_SUFFIX>
최초 설치 분기에서만 실행하며 meta·log·설정·TLS 파일은 삭제하지 않습니다.
유닛 다시 읽기
sudo systemctl daemon-reload
Cluster ID·데이터 보존 확인
sudo -u kafka /opt/kafka/bin/kafka-storage.sh info -c /etc/kafka/<ROLE_CONFIG>.properties
sudo du -sh /var/lib/kafka/meta /var/lib/kafka/logs
  • producer 쓰기를 중지하고 영향 topic·partition을 기록했습니다.
  • controller 과반을 유지한 채 한 노드만 중지했습니다.
  • Cluster ID를 다시 생성하거나 storage format을 재실행하지 않았습니다.
  • meta.properties, metadata log, broker log를 삭제·이동하지 않았습니다.
  • 기존 설정·유닛만 복원하고 같은 Cluster ID를 확인한 뒤 재시작 여부를 별도 승인했습니다.
결과 읽기

빈 디렉터리처럼 보여도 새로 포맷하지 않습니다. 손실 노드 추가·controller 교체는 현재 KRaft membership 절차와 기존 Cluster ID를 사용해야 합니다.

다음 판단

건강한 쿼럼을 기준으로 복구 계획을 세우고 복제 catch-up 확인 후 한 노드씩 재합류합니다.

SECURITY CHECK

운영 전 마지막 보안 점검

  • 운영은 combined 모드를 피하고 3개 이상 controller와 broker 역할을 분리한다.
  • Cluster ID는 신규 클러스터에서 한 번만 생성하고 모든 노드에 동일하게 사용한다.
  • 기존 meta.properties가 있으면 format·재포맷·새 UUID 생성을 금지한다.
  • 모든 역할에 StandardAuthorizer·기본 거부와 명시적 PKCS12 형식을 적용한다.
  • node·root 전용 break-glass 관리자·별도 모니터·앱 인증서와 파일 권한을 분리한다.
  • controller와 client listener에 mTLS·최소 ACL을 적용하고 포트를 사설 CIDR로 제한한다.
  • controller 쿼럼과 topic 데이터 복제를 별도 지표·복구 절차로 운영한다.

COMMON ERRORS

자주 막히는 지점

Cluster ID 불일치

증상
노드가 InconsistentClusterIdException으로 시작하지 않습니다.
가능한 원인
각 노드에서 UUID를 따로 생성했거나 기존 meta.properties와 다른 ID로 구성했습니다.
확인 순서
재포맷하지 말고 건강한 클러스터의 ClusterId와 대상 meta.properties·변경기록을 대조합니다.

controller 쿼럼 없음

증상
broker가 controller를 찾지 못하거나 leader가 선출되지 않습니다.
가능한 원인
controller 과반 미기동, DNS·TLS·9093 방화벽 또는 bootstrap 목록 불일치입니다.
확인 순서
건강한 노드의 metadata-quorum 상태, DNS, 인증서 SAN, 사설 포트 연결을 순서대로 확인합니다.
트러블슈팅으로 이어보기

클라이언트가 연결 후 실패

증상
bootstrap에는 연결되지만 advertised listener 주소에서 실패합니다.
가능한 원인
advertised.listeners가 클라이언트가 해석·접근할 수 없는 이름이거나 인증서 SAN과 다릅니다.
확인 순서
broker API와 TLS hostname 검증을 클라이언트 네트워크에서 확인하고 광범위 bind로 우회하지 않습니다.
트러블슈팅으로 이어보기

PRIMARY REFERENCES

공식 문서

설치 저장소와 지원 버전은 바뀔 수 있습니다. 검토일 이후에는 링크된 공식 문서와 현재 서버의 패키지 후보 버전을 함께 확인하세요.

도구 빠른 검색

최근 사용한 도구를 다시 열거나, 이름과 기능으로 검색하세요.

검색어와 도구의 입력·결과는 저장하지 않습니다.

↑↓ 이동 · Enter 열기 · Esc 닫기