이전 글에서 Prometheus + Grafana를 이용하여 시스템 모니터링을 구성했었다.
이번 글에선 Filebeat + Elastic Search + Log Stash + Kibana 를 이용하여 로그 모니터링을 구성한 과정을 작성한다.
ELK Stack을 쓰는 이유는 ?
로그 수집 / 분석
- 문제가 생긴 원인을 파악하거나 사용자 행위 분석 등 텍스트 기반 검색이 필요할 때
- "왜" 죽었는지 알 수 있다.
구성 요소 | 역할 |
Filebeat | 로그 파일을 읽어 Logstash로 전달 |
Log Stash | 로그 수집 및 파싱 (필요 시 변환) |
Elastic Search | 로그 저장 및 검색 |
Kibana | 로그 시각화 및 대시보드 |
현재 디렉터리 구조는 아래와 같다.
msa-deploy/
├── docker-compose.yml
├── .env 파일들
├── prometheus.yml
└── elk/
├── logstash.conf # Logstash 입력 → 출력 규칙
├── filebeat.yml # Filebeat가 로그를 어디서 → 어디로 보낼지
└── data/ # (Elasticsearch 저장용, volume 연결)
- docker-compose.yml, logstash.conf, filebeat.yml을 작성해야한다.
docker-compose.yml
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
container_name: elasticsearch
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- ./elk/data:/usr/share/elasticsearch/data
ports:
- "9200:9200"
restart: unless-stopped
kibana:
image: docker.elastic.co/kibana/kibana:8.12.0
container_name: kibana
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
depends_on:
- elasticsearch
restart: unless-stopped
logstash:
image: docker.elastic.co/logstash/logstash:8.12.0
container_name: logstash
ports:
- "5044:5044" # Filebeat input
volumes:
- ./elk/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
depends_on:
- elasticsearch
restart: unless-stopped
filebeat:
image: docker.elastic.co/beats/filebeat:8.12.0
container_name: filebeat
user: root
depends_on:
- logstash
volumes:
- ./elk/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
Filebeat
elk/filebeat.yml
filebeat.inputs:
- type: container
paths:
- /var/lib/docker/containers/*/*.log
processors:
- add_docker_metadata: ~
output.logstash:
hosts: ["logstash:5044"]
- filebeat.inputs : Docker 컨테이너 로그 파일 자동 수집
- add_docker_metadata : 컨테이너 이름, 이미지 이름 등 메타데이터 자동 추가
- output.logstash : 로그를 Logstash에 전달한다. (5044 포트)
설정을 마쳤으면 docker-compose를 재시작한다.
혹시 filebeat에서 아래와 같은 오류가 발생하면 권한을 바꿔줘야한다.
ubuntu@ip-@@@@:~/msa-deploy$ docker logs filebeat
Exiting: error loading config file: config file ("filebeat.yml") must be owned
by the user identifier (uid=0) or root
아래 명령어로 파일의 소유자를 root로 바꿔준다.
sudo chown root:root ./elk/filebeat.yml
sudo chmod 600 ./elk/filebeat.yml
아래 명령어로 Elastic Search가 정상적으로 응답하고 있는지 확인한다.
curl http://localhost:9200
다음과 같이 출력되면 정상 동작중인 것이다.
{
"name" : "6624bd4560b2",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "dFhT841PRu6k5uFggLcNCw",
"version" : {
"number" : "8.12.0",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "1665f706fd9354802c02146c1e6b5c0fbcddfbc9",
"build_date" : "2024-01-11T10:05:27.953830042Z",
"build_snapshot" : false,
"lucene_version" : "9.9.1",
"minimum_wire_compatibility_version" : "7.17.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "You Know, for Search"
}
또 아래 명령어를 이용해 로그가 정상 수집되고 있는지 확인한다.
curl http://localhost:9200/_cat/indices?v

컨테이너별로 태그를 지정하여 로그를 관리하고 싶은 경우
filebeat.yml의 processors: 부분에 match_source: true를 넣어준다.
filebeat.inputs:
- type: container
paths:
- /var/lib/docker/containers/*/*.log
processors:
- add_docker_metadata:
match_source: true
output.logstash:
hosts: ["logstash:5044"]
docker-compose.yml의 로그를 관리하고 싶은 컨테이너에 아래와 같이 label을 추가한다.
user-service:
image: @@@/user-service:latest
container_name: user-service
labels:
service: user-service
백, 프론트 컨테이너만 붙여줘도 된다.
DB, Redis 같은 외부 패키지 / 미들웨어 서비스에 레이블을 붙여도 되지만, 보통 애플리케이션 로그보단 시스템 로그 중심이기 때문에 Kibana에서 추적할 일이 드물기 때문이다.
하지만 백, 프론트 컨테이너는 서비스 별로 로그를 관리를 해야하기 때문에 꼭 붙여주자.
설정을 마치면 Filebeat에서 자동으로 태그별로 수집해준다.
Logstash
elk/logstash.conf
input {
beats {
port => 5044
}
}
filter {
json {
source => "message"
skip_on_invalid_json => true
}
if [container][labels][service] {
mutate {
add_field => { "service_name" => "%{[container][labels][service]}" }
}
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "docker-logs-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
- input : Filebeat가 보내는 로그를 5044 포트에서 받음
- filter : JSON 파싱 + 레이블에서 service_name 필드 추가
- output : Elastic Search에 docker-logs-YYYY.MM.dd 인덱스로 저장 + 콘솔 출력
Kibana
http://<서버 IP>:5601 로 이동하여 Kibana에 접속하자.

- 보안 설정은 나중에 할 수 있으므로 일단 Dismiss를 선택하자.
- Integrations는 이미 Filebeat로 로그를 전송 중이므로 Explore on my own을 선택하자.
Index 패턴 만들기
1. 왼쪽 햄버거 메뉴나, 검색창에 Stack Management를 검색하여 클릭한다.
2. 메뉴 중 Kibana - Data Views를 클릭한다.
3. Create data view 클릭 후 Name, Index pattern을 입력 해 준다.
- Timestamp는 자동 감지 된다. 없다면 다른 값들이 후보로 나올 수 있다.

인덱스를 모르는 경우는 아까 엘라스틱 서치 동작 테스트 중 사용한 명령어를 다시 한 번 사용하자.
curl http://localhost:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size dataset.size
yellow open docker-logs-2025.05.19 W4UkbhiVQuKaZUJDO1csrg 1 1 1717750 0 427.8mb 427.8mb 427.8mb
현재 나는 이런 응답이 오는데 여기서 index인 docker-logs-* 만 입력해주면 된다.
4. Kibana - Discover로 이동하여 로그가 잘 수집되고 있는지 확인

현재 ELK 스택 구성은 완료되었지만 전체 컨테이너의 로그를 수집하는 상황이 발생했다.
전에 label을 붙인 컨테이너 이외에는 로그를 수집 할 필요가 없기 때문에 이미 들어온 로그들은 삭제하고 label이 붙은 컨테이너만 로그를 수집하도록 변경할 것이다.
.elk/filebeat.yml
filebeat.inputs: []
filebeat.autodiscover:
providers:
- type: docker
templates:
- condition:
contains:
docker.container.labels.service: ""
config:
- type: container
paths:
- /var/lib/docker/containers/${data.docker.container.id}/*.log
processors:
- add_docker_metadata:
match_source: true
새로 변경된 autodiscover 방식은 기존의 inputs 방식과 아래와 같은 차이가 있다.
설정이 좀 더 복잡해도 유연하게 로그를 처리하고, 더 빠른 수집이 가능하기 때문에 변경했다.
항목 | filbeat.inputs 방식 | filebeat.autodiscover 방식 |
로그 경로 수집 방식 | 고정된 경로 (/var/lib/docker/container/*/*.log) |
컨테이너가 시작될 때 동적으로 경로 생성 |
라벨 필터링 | drop_evenet 등의 프로세서로 필터링 | condition.contains로 라벨 조건 직접 지정 가능 |
유연성 | 낮음 - 모든 컨테이너 대상 | 높음 - 조건 만족 컨테이너 대상 |
리소스 효율성 | 더 많은 로그 읽고 나서 필터 | 처음부터 조건 맞는 컨테이너만 수집 |
설정 난이도 | 간단 | 상대적으로 복잡하지만 정밀 제어 가능 |
실시간 반응성 | 느림 (파일 변경 감지 기반) | 빠름 (컨테이너 이벤트 기반) |
기존 로그 삭제
Stack Management - Index management 에 접속한다.
삭제할 로그를 선택하고 Manage Index에서 Delete index를 클릭하여 삭제한다.

filebeat의 로그 초기화 하는 법
# Filebeat 수집 상태 초기화
docker-compose down filebeat
sudo rm -rf /var/lib/filebeat/registry
# 기존 로그 파일 삭제 (주의: 이건 실제 로그 삭제임)
sudo rm -rf /var/lib/docker/containers/*/*-json.log
# 다시 시작
docker-compose up -d filebeat
Spring Boot에서 Log 형식 Json으로 바꾸는 법
기존 로그 형식은 Json 형식이 아니다. Kibana에서 로그 분석, 수집을 더욱 잘 할 수 있게 하려면 Json으로 로그를 바꿔야한다.
build.gradle에 아래 의존성 추가
implementation 'net.logstash.logback:logstash-logback-encoder:7.4'
main/resources에 아래 파일을 추가한다.
logback-spring.xml
<configuration>
<appender name="JSON_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<root level="INFO">
<appender-ref ref="JSON_CONSOLE" />
</root>
</configuration>
이제 Spring Boot에서 로그를 JSON 형식으로 출력하게 된다.
'Infra' 카테고리의 다른 글
Prometheus + Grafana로 시스템 상태 모니터링 하기 (0) | 2025.05.28 |
---|---|
Netlify에 프론트 서버 띄우기 (0) | 2025.04.17 |
CI/CD (GitHub Actions, Jenkins) (0) | 2025.03.25 |