ECK Stack (Elasticsearch & Kibana)
ECK Operator로 Elasticsearch 클러스터와 Kibana를 배포합니다.
- 버전:
Elasticsearch 7.17.16,Kibana 7.17.16 - 네임스페이스:
database - 접속 URL:
https://kibana.cnapcloud.com - 의존성: ECK Operator (2-05-eck-operator.md), cert-manager (1-03-cert-manager.md), reflector (1-02-reflector.md)
1. 개요
Elasticsearch 3노드 클러스터와 Kibana 1노드를 배포합니다. TLS는 Ingress에서 종료하며 내부 통신은 평문입니다. podAntiAffinity (required)로 각 Elasticsearch Pod가 반드시 별도 노드에 스케줄링되므로 워커 노드 3개 이상이 필요합니다.
2. 사전 요구사항
- ECK Operator:
database네임스페이스에 설치 완료 (2-05-eck-operator.md) - 워커 노드: 3개 이상 (Elasticsearch podAntiAffinity required 조건)
- TLS Secret:
cnapcloud.com-tls가database네임스페이스에 존재 (cert-manager + reflector) - DNS:
kibana.cnapcloud.com등록
3. 디렉터리 구조
eck/ek/
├── Makefile
└── kustomize/
├── base/
│ ├── kustomization.yaml # secretGenerator, 리소스 목록
│ └── resources/
│ ├── elasticsearch.yaml # Elasticsearch 3노드 클러스터
│ ├── kibana.yaml # Kibana 1노드
│ └── ingress.yaml # Kibana Ingress (kibana.cnapcloud.com)
└── overlays/
├── dev/
│ └── kustomization.yaml # namespace: database, TZ=Asia/Seoul
└── dev-arm64/
└── kustomization.yaml # dev + _JAVA_OPTIONS=-XX:UseSVE=0 (ARM64용)
4. 사전 설정
Elasticsearch 인증에 사용할 Secret을 base/kustomization.yaml의 secretGenerator로 생성합니다.
secretGenerator:
- name: es-elastic-user
type: kubernetes.io/basic-auth
literals:
- username=elastic
- password=<password>
- roles=superuser
주의: password 값을 평문으로 Git에 커밋하지 않습니다. SOPS로 암호화하거나 외부 Secret 관리 도구를 사용합니다.
5. 배포
5.1 배포 설정
base/resources/elasticsearch.yaml — 주요 설정:
- 노드 수: 3 (master + data + ingest 통합)
- sysctl:
vm.max_map_count=262144,fs.file-max=65536(initContainer) - podAntiAffinity: required — 각 Pod를 반드시 별도 노드에 배치
- preStop: 종료 전 샤드 재배치 후 대기 (최대 280초)
- TLS: 비활성화 (Ingress에서 종료)
ARM64 노드에 배포하는 경우 overlays/dev-arm64를 사용합니다. SVE 명령어 비호환 문제를 피하기 위해 _JAVA_OPTIONS=-XX:UseSVE=0을 추가합니다.
5.2 배포 실행
make preview # 적용 전 매니페스트 확인
make apply # 클러스터에 적용 (x86)
# ARM64 노드인 경우
make preview DEPLOY_ENV=dev-arm64
make apply DEPLOY_ENV=dev-arm64
6. 설치 후 검증
6.1 CRD 상태 확인
kubectl get elasticsearch,kibana -n database
예상 결과 — 두 리소스 모두 health: green, phase: Ready:
NAME HEALTH NODES VERSION PHASE
elasticsearch.elasticsearch.k8s.elastic.co/... green 3 7.17.16 Ready
NAME HEALTH NODES VERSION AGE
kibana.kibana.k8s.elastic.co/kibana green 1 7.17.16 ...
6.2 Elasticsearch 클러스터 헬스 확인
kubectl exec -n database elasticsearch-es-default-0 -- \
curl -s -u elastic:<password> http://localhost:9200/_cluster/health?pretty
예상 결과:
{
"status" : "green",
"number_of_nodes" : 3,
"active_shards_percent_as_number" : 100.0
}
6.3 Kibana UI 접근 확인
브라우저에서 https://kibana.cnapcloud.com 접속 시 Kibana 로그인 화면이 표시됩니다. elastic / <password>로 로그인합니다.
7. Troubleshooting
7.1 Elasticsearch Pod Pending — podAntiAffinity 충족 불가
증상: Elasticsearch Pod 중 일부가 Pending 상태
원인: requiredDuringSchedulingIgnoredDuringExecution 조건으로 3개 Pod가 각각 별도 노드를 요구하는데 가용 노드 부족
해결: 워커 노드를 3개 이상으로 확장하거나, elasticsearch.yaml의 podAntiAffinity를 preferredDuringSchedulingIgnoredDuringExecution으로 변경합니다.
7.2 vm.max_map_count 오류
증상: Elasticsearch Pod가 max virtual memory areas vm.max_map_count [65530] is too low 오류로 기동 실패
원인: sysctl initContainer 실행 실패 또는 권한 부족
해결: initContainer가 privileged: true로 설정되어 있는지 확인합니다. PodSecurityPolicy 또는 Security Context가 privileged 실행을 차단하는 경우 노드에 직접 sysctl -w vm.max_map_count=262144를 적용합니다.
7.3 Kibana — Elasticsearch 연결 실패
증상: Kibana Pod가 기동 후 kibana_task_manager 인덱스 생성 중 오류
원인: Elasticsearch가 아직 green 상태가 아니거나 es-elastic-user Secret 불일치
해결: Elasticsearch phase: Ready 확인 후 Kibana Pod를 재시작합니다.
8. 제거
주의: make delete로 Elasticsearch를 삭제하면 PVC가 남아 있어도 데이터 복구가 어렵습니다. 삭제 전 스냅샷 백업을 권장합니다.
make delete
PVC는 별도로 삭제해야 합니다.
kubectl delete pvc -n database -l elasticsearch.k8s.elastic.co/cluster-name=elasticsearch