앞선 포스팅에서 반정형 로그 수집기 애플리케이션을 만들어보았습니다. 구현 내용을 다시 상기해보면, 해당 애플리케이션은 반정형 데이터 수집 요청을 받아 Writer 인터페이스를 구현하는 Writer들로 데이터를 저장하는 역할을 했습니다.
이번 포스팅에서는 FileWriter로 로컬 저장소에 저장된 데이터들을 ELK Stack(Elastic Stack)을 이용해 수집하고, 저장하고, 시각화해보도록 하겠습니다.
docker compose 작성
도커 환경에서 ELK Stack을 띄울 것이기 때문에 docker-compose.yml 파일을 작성해주었습니다.
Elastic Search
Elastic Search는 공식 홈페이지에서 Docker 환경에서 Elastic Search를 설치하는 방법을 가이드로 제공하고있습니다.
Elastic Search에서는 데이터의 무결성과 가용성 보장을 위해 최소 3개의 노드를 구성하는 것을 권장하고 있으므로, 권장 설정에 따라 3개의 Docker 컨테이너를 구성했습니다.
아래 예제 코드에서는 그 셋 중 한 개의 컨테이너만을 가져왔으며, 전체 코드는 위 깃허브에 있으니 참고 바랍니다.
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.16.2
container_name: es01
restart: always
environment:
# 노드명
- node.name=es01
# 클러스터명. 노드들을 묶는다. (default: elasticsearch)
- cluster.name=es-data-collector-cluster
# 바인딩 할 원격 노드의 IP 또는 도메인 주소
- discovery.seed_hosts=es02,es03
# 마스터 노드 대상
- cluster.initial_master_nodes=es01,es02,es03
# Elasticsearch가 사용중인 힙메모리 영역을 다른 자바 프로그램이 간섭 못하도록 미리 점유하는 설정. true 권장
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
volumes:
- data01:/usr/share/elasticsearch/data
ulimits:
memlock:
soft: -1
hard: -1
ports:
- 9200:9200
networks:
- elastic-data-collector
node.name [링크]
- 노드의 이름을 지정합니다.
- 지정하지 않으면 해당 노드가 올라간 서버의 호스트명이 세팅됩니다.
cluster.name [링크]
- Elastic Search의 클러스터명을 지정합니다.
- 같은 클러스터명을 가진 노드들을 묶게 되는데, 기본 값(elasticsearch)으로 사용해도 문제는 없지만 production 환경에서 다수의 클러스터를 구성하는 것을 고려한다면 당연히 이름을 변경해주는 것이 맞기 때문에 처음부터 세팅해주는 것을 습관을 들이도록 합시다.
discovery.seed_hosts [링크]
- 다른 elastic search 노드를 찾고 마스터 노드를 선출하기 위한 호스트명을 지정합니다.
- IPv4, IPv6, DNS 모두 지원합니다.
- 기본적으로 9300~9305 포트를 스캔하지만, 오버 라이딩이 가능합니다.
- 추가적인 설정 없이 오토 스케일링을 지원합니다.
cluster.initial_master_nodes [링크]
- 마스터 노드를 선출하기 위한 후보 노드들을 지정합니다.
- 개발 환경에서는 Elastic Search에서 제공하는 자동 기능을 사용해도 무방하지만, production 환경에서는 명시해줄 것을 권장하므로 마찬가지로 세팅해줍니다.
- 주의할 점은, 맨 처음 클러스터를 구성할 때만 해당 설정을 사용하고 이후에 클러스터를 재시작하거나 노드를 추가할 때는 해당 속성을 사용하면 안 됩니다.
bootstrap.memory_lock [링크]
- Elasticsearch가 사용 중인 힙 메모리 영역을 다른 자바 프로그램이 간섭 못하도록 미리 점유하는 설정입니다.
- JVM의 Garbage Collection으로 인해 swap으로 메모리가 빠져나가지 않도록 합니다.
Logstash
Logstash 또한 Elastic Search와 마찬가지로 공식 홈페이지에서 Docker 환경에서의 구동 방법을 가이드하고 있습니다.
logstash:
image: docker.elastic.co/logstash/logstash:7.16.2
container_name: logstash
restart: always
environment:
MONITORING_ELASTICSEARCH_HOSTS: '["http://es01:9200","http://es02:9200","http://es03:9200"]'
ports:
- 5000:5000
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
- /Users/nhn/data-collector:/source-data
networks:
- elastic-data-collector
MONITORING_ELASTICSEARCH_HOSTS
- 모니터링을 할 Elastic Search 노드의 호스트명을 입력하는 부분입니다.
- 이 설정은 사실 Elastic Stack X-Pack을 구입하지 않았다면 빼야 합니다.
- 저는 이 사실을 몰라서 오류를 유발했고, 결과적으로는 제거했습니다. (해결 내용은 다음 포스트에!)
Docker volumes 설정
/usr/logstash/pipeline
- Logstash의 파이프라인 설정 파일의 디렉터리를 마운트 해주었습니다.
- 상대 경로로 data-collector 애플리케이션의 logstash/pipeline 디렉터리를 지정해주었습니다.
/source-data
- 수집할 데이터가 존재하는 호스트 디렉토리를 마운트 해주었습니다.
- 실제 호스트의 디렉터리는 data-collector 애플리케이션의 FileWriter의 파일 저장 디렉터리입니다.
Kibana
이쯤 되면 당연하게도 공식 홈페이지에서 Docker 환경에서의 구동 방법을 가이드해주고 있습니다.
kibana:
image: docker.elastic.co/kibana/kibana:7.16.2
container_name: kibana
restart: always
environment:
ELASTICSEARCH_HOSTS: '["http://es01:9200","http://es02:9200","http://es03:9200"]'
ports:
- 5601:5601
networks:
- elastic-data-collector
ELASTICSEARCH_HOSTS [링크]
- Kibana에서 모니터링할 Elastic Search의 노드들을 등록합니다.
- 등록된 모든 노드들은 동일한 클러스터이어야 합니다.
Logstash 파이프라인 작성
ELK Stack 컨테이너들을 구동하기 전 Logstash의 파이프라인을 작성합니다.
파이프라인은 input, filter, output 세 단계로 구성되어 원천 데이터를 가공해 elastic search에 전송해주는 설정을 담고 있습니다.
input {
file {
path => "/source-data/*.txt"
delimiter => "\n"
file_sort_by => "path"
mode => "read"
file_completed_action => "delete"
}
}
output {
elasticsearch {
hosts => ["http://es01:9200","http://es02:9200","http://es03:9200"]
}
}
input
file [링크]
- path : 읽어올 파일의 전체 경로를 지정합니다.
- delimiter : 데이터의 구분자를 지정합니다.
- file_sort_by : 읽어올 파일들의 정렬 순서를 지정합니다.
- mode : file input plugin의 동작 방식을 지정합니다.
- file_completed_action : 파이프라인의 작업이 완료된 후 파일에 대한 후처리 방식을 지정합니다.
output
elasticsearch [링크]
- hosts : 데이터를 전송할 Elastic Search 노드의 http 주소를 입력합니다.
Data Collector 개선
앞선 설정으로 ELK Stack의 구성은 성공했습니다. 다만, 아래와 같은 오류가 있었습니다.
Data Collector에서 데이터 저장을 위한 파일이 생성된 후, Logstash에서 해당 파일을 읽고 file_completed_action 설정에 따라 파일을 지워버려 Data Collector에서는 데이터를 쓸 파일이 제거되어 예외가 빵빵 터졌습니다.
그래서 Data Collector의 FileWriter 로직을 수정했습니다.
기존
- 파일 저장 디렉터리에 1시간 주기로 데이터를 쓸 파일을 생성
- 1초마다 앞서 생성된 파일에 데이터 작성
변경
- 임시 디렉토리에 1시간 주기로 데이터를 쓸 파일을 생성
- 1초마다 앞서 생성된 임시 파일에 데이터 작성
- 1시간마다 임시 파일을 파일 저장 디렉터리로 옮기고 1번 동작을 수행
일단은 동작했습니다
Data Collector까지 수정하고 나서 원하는 대로 동작했습니다. 수집된 데이터는 Logstash를 통해 Elastic Search에 저장되었고, 저장된 데이터는 Kibana를 통해 시각화되었습니다.
하지만 오류 대환장 파티가 절 기다리고 있었습니다.
'📦 ETC > TOY PROJECT' 카테고리의 다른 글
[찍어먹기] Spring Boot 부터 ELK Stack 까지 :: 트러블슈팅 (1) - Elasticsearch (0) | 2022.03.17 |
---|---|
[찍어먹기] Spring Boot 부터 ELK Stack 까지 :: 인증인가 처리 (0) | 2022.03.07 |
[찍어먹기] Spring Boot 부터 ELK Stack 까지 :: 데이터 수집해서 시각화 하기 (2) (0) | 2022.01.30 |
[찍어먹기] Spring Boot 부터 ELK Stack 까지 :: 반 정형 데이터 수집기 만들기 (0) | 2022.01.02 |