Elastic Stack 구축 가이드입니다. 이 작업은 패키지 네 개를 설치하는 것으로 끝나지 않습니다. 수집 구간의 인증, Elasticsearch의 TLS와 권한, Kibana 공개 범위, 보존 정책, 스냅샷 복구까지 하나의 운영 경계로 설계해야 합니다. 이 글은 Rocky Linux 9와 Elastic Stack 9.4.2를 기준으로 재현 가능한 설치와 검증 절차를 정리합니다.
실습은 단일 호스트에서 시작하지만 운영 환경은 역할과 장애 영역을 분리합니다. 또한 모든 명령은 실행 목적과 확인 방법을 함께 설명합니다. 비밀번호와 API 키를 본문이나 셸 이력에 하드코딩하지 않고, Elastic이 기본으로 활성화하는 보안 설정도 끄지 않습니다.

Elastic Stack 구축 범위와 구성 요소
| 구성 요소 | 역할 | 운영 핵심 |
|---|---|---|
| Elasticsearch | 문서 색인·검색·집계와 샤드 관리 | 3노드 합의, TLS, 용량과 샤드 수 |
| Kibana | 검색·대시보드·관리 UI | loopback 바인딩, HTTPS 프록시, RBAC |
| Logstash | 파싱·변환·라우팅 | back pressure, persistent queue, 비밀정보 |
| Filebeat/Elastic Agent | 로그·메트릭 수집 | TLS 신뢰, 필드 규칙, 재전송 |
| ILM | rollover와 보존 기간 자동화 | 샤드 크기, 보존 요구, 실행 상태 |
| Snapshot/SLM | 클러스터 외부 백업과 복구 | 저장소 검증, 복구 훈련, 접근 분리 |
Elastic Stack 구축 전 설계와 요구사항
Rocky Linux 9는 RHEL 호환 배포판이지만 상용 지원이 필요하다면 Elastic 지원 매트릭스에서 정확한 OS 조합을 확인해야 합니다. 또한 Elastic Stack 구성 요소는 같은 버전으로 맞춥니다. 이 글의 검증 버전은 2026년 7월 현재 공식 문서의 최신 안정판인 9.4.2입니다.
실습과 운영 토폴로지 구분
| 항목 | 단일 노드 실습 | 운영 권장 방향 |
|---|---|---|
| Elasticsearch | 1대, discovery.type=single-node | 최소 3대의 master-eligible 노드와 장애 영역 분산 |
| Kibana | 같은 호스트의 127.0.0.1 | 별도 호스트 또는 다중 인스턴스와 HTTPS 프록시 |
| Logstash | 로컬 파이프라인 | 수집량에 맞춘 별도 노드와 persistent queue |
| 백업 | 기능 확인용 별도 경로 | 클러스터 밖의 공유 스토리지나 객체 저장소 |
| 노출 포트 | loopback만 사용 | 방화벽 source 제한과 TLS, 관리망 분리 |
호스트 자원과 시간 동기화 확인
cat /etc/rocky-release
uname -r
timedatectl status
free -h
df -hT /var/lib /var/log
sysctl vm.max_map_count
ulimit -n
Elasticsearch는 JVM heap뿐 아니라 filesystem cache를 적극 사용합니다. 따라서 같은 호스트에 무거운 Logstash 작업을 함께 넣으면 메모리 경합이 생기기 쉽습니다. 기본 자동 heap sizing을 먼저 사용하고, 부하 시험 근거가 있을 때만 Xms와 Xmx를 같은 값으로 조정합니다.
Elastic Stack 구축: 9.4.2 저장소와 패키지 설치
Elastic Stack 구축 패키지는 공식 GPG 키와 9.x RPM 저장소를 사용합니다. 저장소를 기본 비활성화하면 일상적인 dnf update에서 예상하지 못한 메이저 변경이 섞이는 일을 줄일 수 있습니다. 설치 전에는 변경 기록과 호환성을 검토하십시오.
공식 GPG 키와 저장소 등록
sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
sudo tee /etc/yum.repos.d/elastic-9.x.repo >/dev/null <<'EOF'
[elastic-9.x]
name=Elastic repository for 9.x packages
baseurl=https://artifacts.elastic.co/packages/9.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=0
type=rpm-md
EOF
sudo dnf clean metadata
sudo dnf --disablerepo='*' --enablerepo=elastic-9.x list available elasticsearch kibana logstash filebeat
동일 버전으로 설치하고 고정 확인
STACK_VERSION='9.4.2'
sudo dnf install --enablerepo=elastic-9.x "elasticsearch-${STACK_VERSION}" "kibana-${STACK_VERSION}" "logstash-${STACK_VERSION}" "filebeat-${STACK_VERSION}"
rpm -q elasticsearch kibana logstash filebeat
sudo dnf install dnf-plugins-core
sudo dnf versionlock add elasticsearch kibana logstash filebeat
Elastic Stack 구축: Elasticsearch 단일 노드 보안 구성
단일 노드 Elastic Stack 구축 실습에서는 Elasticsearch를 loopback에만 바인딩합니다. Elastic 9.x의 최초 시작은 인증과 HTTP·transport TLS를 자동 구성합니다. 이를 끄는 대신 생성된 CA를 신뢰하도록 각 클라이언트를 설정합니다.
실습용 elasticsearch.yml 최소 설정
sudo cp -a /etc/elasticsearch/elasticsearch.yml /etc/elasticsearch/elasticsearch.yml.before-lab
sudo tee -a /etc/elasticsearch/elasticsearch.yml >/dev/null <<'EOF'
# Lab-only topology. Remove conflicting duplicate keys before restart.
cluster.name: logs-lab
node.name: es01
network.host: 127.0.0.1
http.host: 127.0.0.1
transport.host: 127.0.0.1
discovery.type: single-node
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now elasticsearch
sudo systemctl status elasticsearch --no-pager
설정 파일에 같은 키가 이미 있으면 중복으로 추가하지 말고 기존 값을 수정합니다. 서비스 시작 실패 시 보안 기능을 비활성화하지 말고 journal과 Elasticsearch 로그에서 bootstrap check, 권한, YAML 오류를 먼저 찾습니다.
sudo journalctl -u elasticsearch --since '-10 min' --no-pager
sudo tail -n 100 /var/log/elasticsearch/logs-lab.log
sudo ss -lntp | grep -E ':(9200|9300)\b'
비밀번호 재설정과 CA 기반 HTTPS 검증
sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -i
read -rsp 'elastic password: ' ELASTIC_PASSWORD
echo
export ELASTIC_PASSWORD
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" https://127.0.0.1:9200/ | jq .
unset ELASTIC_PASSWORD
인증서 검증을 우회하면 연결은 되어도 위조 서버를 구별하지 못합니다. 자동 생성 CA의 fingerprint 또는 CA 파일을 배포하고, 개인 비밀번호 대신 서비스별 최소 권한 계정이나 API 키를 사용하십시오.
Elastic Stack 구축: Kibana 등록과 HTTPS 공개
Kibana는 enrollment token으로 Elasticsearch의 CA와 인증 정보를 받아 등록할 수 있습니다. 브라우저에 직접 5601을 노출하지 않고 127.0.0.1에 바인딩한 뒤, 조직 인증서를 사용하는 reverse proxy에서 HTTPS를 종료하는 구성이 이해하기 쉽습니다.
Kibana enrollment token 생성과 등록
sudo /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana
# 위 명령이 출력한 단기 토큰을 다음 명령에 입력합니다.
sudo /usr/share/kibana/bin/kibana-setup --enrollment-token '<ONE_TIME_ENROLLMENT_TOKEN>'
sudo tee -a /etc/kibana/kibana.yml >/dev/null <<'EOF'
server.host: "127.0.0.1"
server.port: 5601
server.publicBaseUrl: "https://kibana.example.com"
EOF
sudo systemctl enable --now kibana
sudo journalctl -u kibana --since '-10 min' --no-pager
Nginx HTTPS reverse proxy 예시
server {
listen 443 ssl http2;
server_name kibana.example.com;
ssl_certificate /etc/pki/tls/certs/kibana-fullchain.pem;
ssl_certificate_key /etc/pki/tls/private/kibana.key;
location / {
proxy_pass http://127.0.0.1:5601;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
sudo nginx -t
sudo systemctl reload nginx
# 관리망 주소 대역으로 바꾸십시오.
sudo firewall-cmd --permanent --new-zone=kibana-admin || true
sudo firewall-cmd --permanent --zone=kibana-admin --add-source=10.20.0.0/16
sudo firewall-cmd --permanent --zone=kibana-admin --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --zone=kibana-admin --list-all
Elastic Stack 구축: Logstash와 Filebeat 수집 파이프라인
로컬 예제는 Filebeat가 loopback의 Logstash로 보내고, Logstash가 CA로 Elasticsearch 인증서를 검증하는 흐름입니다. 원격 Beats가 5044로 접속한다면 서버·클라이언트 인증서를 별도로 배포하고 방화벽 source를 제한해야 합니다.
최소 권한 수집 계정 생성
read -rsp 'elastic password: ' ELASTIC_PASSWORD
echo
read -rsp 'logstash_writer password: ' LOGSTASH_WRITER_PASSWORD
echo
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" -X PUT https://127.0.0.1:9200/_security/role/logstash_writer_role -H 'Content-Type: application/json' -d @- <<'JSON'
{
"cluster": ["monitor", "manage_index_templates", "manage_ilm"],
"indices": [
{
"names": ["logs-*"],
"privileges": ["auto_configure", "create_doc", "write", "manage_ilm"]
}
]
}
JSON
jq -n --arg password "$LOGSTASH_WRITER_PASSWORD" '{password:$password,roles:["logstash_writer_role"]}' | curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" -X PUT https://127.0.0.1:9200/_security/user/logstash_writer -H 'Content-Type: application/json' --data-binary @-
unset LOGSTASH_WRITER_PASSWORD
Logstash 설정 문법과 연결 검증
sudo install -d -o logstash -g logstash -m 0750 /etc/logstash/certs
sudo install -o logstash -g logstash -m 0640 /etc/elasticsearch/certs/http_ca.crt /etc/logstash/certs/http_ca.crt
sudo /usr/share/logstash/bin/logstash-keystore --path.settings /etc/logstash create
sudo /usr/share/logstash/bin/logstash-keystore --path.settings /etc/logstash add ES_PASSWORD
ES_PASSWORD에는 교육용 elastic 계정이 아니라 별도로 만든 최소 권한 수집 계정의 비밀번호를 넣는 것이 원칙입니다. 아래 설정은 값 대신 keystore 변수를 참조하므로 설정 파일에 비밀정보가 남지 않습니다.
sudo tee /etc/logstash/conf.d/beats-to-elasticsearch.conf >/dev/null <<'EOF'
input {
beats { host => "127.0.0.1" port => 5044 }
}
filter {
if ![@metadata][pipeline] { mutate { add_tag => ["pipeline-default"] } }
}
output {
elasticsearch {
hosts => ["https://127.0.0.1:9200"]
user => "logstash_writer"
password => "${ES_PASSWORD}"
ssl_enabled => true
ssl_certificate_authorities => ["/etc/logstash/certs/http_ca.crt"]
ecs_compatibility => "v8"
data_stream => "true"
data_stream_type => "logs"
data_stream_dataset => "app"
data_stream_namespace => "default"
}
}
EOF
sudo chown logstash:logstash /etc/logstash/logstash.keystore
sudo chmod 0600 /etc/logstash/logstash.keystore
sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash --config.test_and_exit
sudo systemctl enable --now logstash
Filebeat filestream 입력과 출력 설정
sudo tee /etc/filebeat/filebeat.yml >/dev/null <<'EOF'
filebeat.inputs:
- type: filestream
id: system-messages
enabled: true
paths:
- /var/log/messages
output.elasticsearch:
enabled: false
output.logstash:
hosts: ["127.0.0.1:5044"]
logging.level: info
EOF
sudo filebeat test config -e
sudo filebeat test output -e
sudo systemctl enable --now filebeat
sudo journalctl -u filebeat --since '-10 min' --no-pager
Filebeat가 /var/log/messages를 읽을 권한이 있는지 확인하십시오. 무조건 root로 실행하는 대신 패키지의 서비스 계정과 권한 모델을 검토하고, 민감 필드·개인정보·토큰은 수집 전에 drop 또는 redact합니다. 파싱 실패 이벤트는 별도 태그와 대시보드로 관찰해야 합니다.
Elastic Stack 구축 후 데이터 스트림과 ILM
시간 기반 로그를 하나의 인덱스에 계속 쓰면 샤드가 비대해지고 복구 시간이 길어집니다. 데이터 스트림과 ILM을 조합하면 조건에 따라 새 backing index로 rollover하고, 보존 기간이 지난 데이터를 자동 삭제할 수 있습니다. 아래 예시는 50GB 또는 1일을 기준으로 전환합니다.
30일 ILM 정책 생성
read -rsp 'elastic password: ' ELASTIC_PASSWORD
echo
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" -X PUT https://127.0.0.1:9200/_ilm/policy/logs-30d -H 'Content-Type: application/json' -d @- <<'JSON'
{
"policy": {
"phases": {
"hot": {
"actions": {
"rollover": {"max_primary_shard_size": "50gb", "max_age": "1d"}
}
},
"delete": {
"min_age": "30d",
"actions": {"delete": {}}
}
}
}
}
JSON
데이터 스트림용 인덱스 템플릿
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" -X PUT https://127.0.0.1:9200/_index_template/logs-app -H 'Content-Type: application/json' -d @- <<'JSON'
{
"index_patterns": ["logs-app-*"],
"priority": 500,
"data_stream": {},
"template": {
"settings": {
"index.lifecycle.name": "logs-30d",
"number_of_shards": 1,
"number_of_replicas": 1
}
}
}
JSON
ILM 적용 상태 점검
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" 'https://127.0.0.1:9200/_ilm/status?pretty'
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" 'https://127.0.0.1:9200/.ds-logs-app-*/_ilm/explain?pretty'
Elastic Stack 구축: 운영 3노드 클러스터 전환
운영 Elastic Stack 구축에서는 세 master-eligible 노드를 서로 다른 장애 영역에 둡니다. 두 노드만으로는 한 노드 장애 시 과반 합의를 유지할 수 없습니다. 새 노드는 enrollment token으로 가입시키고, 모든 노드가 형성된 뒤 discovery 설정을 정리합니다.
노드 enrollment와 클러스터 확인
# 기존 클러스터 노드에서 실행
sudo /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s node
# 새 노드에서 패키지 설치 직후 실행
sudo /usr/share/elasticsearch/bin/elasticsearch-reconfigure-node --enrollment-token '<ONE_TIME_NODE_TOKEN>'
sudo systemctl enable --now elasticsearch
# 기존 클러스터에서 노드와 역할 확인
curl --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" 'https://127.0.0.1:9200/_cat/nodes?v&h=name,ip,node.role,master,heap.percent,disk.avail'
cluster.initial_master_nodes는 새 클러스터의 첫 선출에만 사용합니다. 클러스터가 형성된 뒤 각 노드에서 제거하고 다시 설정하지 마십시오. 재시작할 때 남겨두면 실수로 별도 클러스터를 부트스트랩할 위험이 있습니다. discovery.seed_hosts에는 재시작 후에도 찾을 수 있는 master-eligible 노드를 둡니다.
Elastic Stack 구축: 스냅샷과 복구 훈련
replica는 노드 장애를 견디기 위한 사본이지 백업이 아닙니다. 실수로 삭제한 문서는 replica에도 즉시 반영됩니다. Elastic Stack 구축의 완료 조건에는 클러스터 밖의 snapshot repository, 자동 SLM 정책, 실제 복구 시험이 포함되어야 합니다.
공유 파일시스템 저장소 등록 예시
# 모든 master/data 노드의 elasticsearch.yml에 같은 경로를 추가합니다.
path.repo: ["/mnt/elastic-backup"]
# rolling restart 후 저장소를 등록합니다.
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" -X PUT https://127.0.0.1:9200/_snapshot/prod_backup -H 'Content-Type: application/json' -d @- <<'JSON'
{
"type": "fs",
"settings": {
"location": "/mnt/elastic-backup",
"compress": true
}
}
JSON
저장소 검증과 시험 스냅샷
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" -X POST 'https://127.0.0.1:9200/_snapshot/prod_backup/_verify?pretty'
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" -X PUT 'https://127.0.0.1:9200/_snapshot/prod_backup/smoke-test?wait_for_completion=true&pretty'
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" 'https://127.0.0.1:9200/_snapshot/prod_backup/smoke-test?pretty'
노드의 /var/lib/elasticsearch를 rsync하거나 filesystem snapshot으로 복사하는 방식은 지원되는 백업이 아닙니다. repository 내용도 Elasticsearch 외부 프로세스가 수정하면 손상될 수 있습니다. 별도 테스트 클러스터로 정기 복구하여 인덱스, feature state와 대시보드를 확인하십시오.
Elastic Stack 구축 검증과 장애 진단
서비스·TLS·클러스터 상태 한 번에 확인
systemctl --no-pager --full status elasticsearch kibana logstash filebeat
sudo ss -lntp | grep -E ':(9200|9300|5601|5044)\b'
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" 'https://127.0.0.1:9200/_cluster/health?pretty'
curl --fail --silent --show-error --cacert /etc/elasticsearch/certs/http_ca.crt -u "elastic:${ELASTIC_PASSWORD}" 'https://127.0.0.1:9200/_cat/shards?v&s=state,index'
unset ELASTIC_PASSWORD
진단 순서
- systemd exit code와 최근 journal에서 최초 오류 시각을 찾습니다.
- 포트가 의도한 주소에만 listen하는지 확인합니다.
- CA·hostname·유효 기간과 클라이언트의 인증서 신뢰를 확인합니다.
- cluster health에서 unassigned shard 이유와 disk watermark를 확인합니다.
- Logstash config test, persistent queue, rejected event와 Filebeat output test를 확인합니다.
- ILM explain과 snapshot verify 결과로 보존·백업 자동화를 확인합니다.
- 같은 입력과 설정으로 격리된 환경에서 재현한 뒤 변경 사항을 기록합니다.
자주 하는 실수와 대안
| 실수 | 문제 | 안전한 대안 |
|---|---|---|
| 보안 기능을 false로 변경 | 인증·권한·TLS 경계 소실 | 자동 보안 설정 유지와 CA 배포 |
| curl 인증서 검증 생략 | 서버 인증서 위조 탐지 불가 | –cacert 또는 fingerprint 검증 |
| elastic 계정으로 수집 | 과도한 superuser 권한 | 서비스별 role·user 또는 API key |
| 9200·5601 전체 공개 | 관리 API와 UI 직접 노출 | loopback·관리망·reverse proxy |
| 무제한 단일 인덱스 | 샤드 비대화와 긴 복구 | 데이터 스트림·rollover·ILM |
| data 디렉터리 복사 | 일관성 없는 복구 불가 백업 | snapshot repository와 복구 시험 |
| 2노드 master 구성 | 장애 시 과반 합의 상실 | 3개 master-eligible 노드 |
Elastic Stack 구축: 업그레이드와 운영 체크리스트
- 구성 요소의 목표 버전을 동일하게 맞추고 release note와 breaking change를 검토합니다.
- 업그레이드 전에 cluster health, unassigned shard, disk watermark와 snapshot 성공을 확인합니다.
- 노드를 한 대씩 rolling upgrade하며 각 단계에서 클러스터 합류와 shard 회복을 기다립니다.
- Kibana saved object, Logstash plugin, Beats module과 사용자 정의 template 호환성을 검증합니다.
- 인증서 만료, keystore 항목, API key 회전과 최소 권한을 정기적으로 점검합니다.
- 수집 지연, JVM pressure, rejected request, shard 크기, ILM·SLM 실패를 경보로 연결합니다.
관련 자료
- Elastic 공식 RPM 설치 문서
- Elastic 공식 self-managed 보안 문서
- Elastic 공식 ILM 문서
- Elastic 공식 Snapshot and Restore 문서
- 리눅스 디스크·inode 부족 진단 가이드
- Ansible 플레이북과 롤링 배포 가이드
- 리눅스 컨테이너와 rootless Podman 가이드
Elastic Stack 구축 정리
Elastic Stack 구축의 핵심은 설치 성공 화면이 아니라 안전하게 수집하고, 예측 가능한 크기로 보존하며, 장애 뒤에 복구할 수 있는 운영 체계입니다. 같은 버전의 공식 패키지에서 시작하고 자동 TLS와 인증을 유지하십시오. 그런 다음 최소 권한, loopback·방화벽 경계, 데이터 스트림과 ILM, 클러스터 외부 스냅샷을 순서대로 검증하면 단일 노드 실습을 운영 가능한 3노드 구조로 확장할 수 있습니다.