ToasT1ng 기술 블로그

[EFK] 3. 쓸만한 EFK 구축 (1) - Fluentd Aggregator 본문

로깅시스템

[EFK] 3. 쓸만한 EFK 구축 (1) - Fluentd Aggregator

ToasT1ng 2021. 9. 25. 20:45

지난 포스팅에서는 Service => Fluentd => Elasticsearch 까지 로그를 성공적으로 받을 수 있게 구성해봤다.

 

 

[EFK] 2. 간단한 EFK 구축 (2)

지난 포스팅에서는 우리가 구축할 EFK 의 전체적인 구조와, Service 역할을 해줄 간단한 Spring Boot App 을 제작했었다. [EFK] 1. 간단한 EFK 구축 (1) EFK 의 구조 대부분의 로깅 시스템은 이런 식으로 구성

toast1ng.tistory.com

 

 

이어서 오늘은 Fluentd Aggregator 를 중점적으로 다뤄보려고 한다.

 

 


 

Fluentd Aggregator 의 필요성

 

단일 서버 구성으로 규모있는 시스템을 구축하는 것은 불가능한 일이다. 어떻게 할 수 있겠는가? 하나만 죽어도 시스템 전체가 다운되어버리는데. 대부분의 경우 시스템의 안정성을 위해, 여러 대의 서버를 Clustering 하여 하나의 시스템을 이루도록 구축한다.

 

Logging System 은 이 점을 고려해야 한다. 현재까지는 단일 End Point 에서 Log 를 발생시켜 Elasticsearch 까지 도달하도록 했지만 실제 상황에서는 여러 End Point 에서 Log 가 발생되어 Elasticsearch 까지 도달하게 된다.

 

 

지금까지 우리가 구성한 Logging System 에서는 이를 어떻게 처리할까?

 

10개로 Clustering 된 시스템이 있으면, 10개의 Fluentd 에서 각각 N초에 한 번씩 쌓인 Log 들을 ElasticSearch 로 쏜다. ES에게 N초에 한 번꼴로 1초에 10번의 접근이 있게 된다.

 

만약 이런 시스템이 10개가 더 있다고 해보자. 100개의 Fluentd 에서 각각 N초에 한 번씩 쌓인 Log 들을 ElasticSearch 로 쏜다. ES에게 N초에 한 번꼴로 1초에 100번의 접근이 있게 된다.

 

각각은 물리적으로 다른 곳에서 오기 때문에 순차적으로 접근하지 않는다. 최악의 경우, 1ms 도 다르지 않은 시간에 정말 동시에 ES에 접근하게 될 수도 있다. 우리가 구성할 ElasticSearch 에서 이 모든 트래픽을 감당할 수 있을까?

 

다중 서버에서 하나의 ES 로

 

이렇게 구성했을 경우, ElasticSearch 로 들어오는 트래픽 양은 필연적으로 점점 늘어나게 된다. 각 Cluster 를 구성하는 Server 의 개수가 늘어나면 End Point 도 증가하게 될 것이다.

 

아무리 넉넉하게 ElasticSearch 의 컴퓨팅 리소스를 책정해 둔다고 해도 언젠가는 불안정해질 수 있다는 뜻이다. 

 

Q. 늘어나는 트래픽 양에 맞춰 ES 의 컴퓨팅 파워를 계속 높이면 되지 않을까?

A. 비용이 너무 너무 너무 많이 든다. 별로 효율적이지가 않다.

 

 

 

그렇다면 어떤 방법을 써야하는게 좋을까?

 

간단하다. ES 에 직접적으로 접근하는 End Point 양을 줄이면 된다. Fluentd Aggregator 가 필요한 이유이다.

 

Fluentd Aggregator 를 두자

 

Fluentd Aggregator 가 일종의 Queue 역할을 수행해줄 수 있게 된다. 더 이상 ES 에 동시다발적으로 접근하지 않게 된다. Aggregator 를 따로 두면 서로 다른 형태의 Log 들을 여기서 수집하고 filtering 하여 같은 형태의 Log 들로 변환해서 ES 에 쏘는 것도 가능하다. 필요에 따라서 잘 활용하면 될 것이다.

 

이제 본격적으로 Fluentd Aggregator 를 구축해보자.

 

 


 

Fluentd_aggregator

 

 

전체 파일 구조에 다음과 같이 추가된다. ( fluentd-aggregator/ 추가 )

 

elasticsearch/
   ∟ backup/
   ∟ config/
      ∟ elasticsearch.yml
   ∟ data/
   ∟ docker-compose.yml


fluentd-aggregator/
   ∟ buffer/
   ∟ conf/
      ∟ fluentd.conf
   ∟ pos/
      ∟ service.pos
   ∟ Dockerfile
   
   
fluentd/
   ∟ buffer/
   ∟ conf/
      ∟ fluentd.conf
   ∟ pos/
      ∟ service.pos
   ∟ Dockerfile


spring/
   ∟ log/
      ∟ simplelogging.log
   ∟ ......

 

 

 

fluentd_aggregator 의 fluentd.conf 는 다음과 같이 작성한다.

 

<source>
  @type forward
  port 24224
  bind 0.0.0.0
  tag log.*
</source>

<match **>
  @type copy
  <store>
    @type elasticsearch
    hosts http://<YOUR_ES_IP>:9200
    user fluentd_user
    password [YOUR_PASSWORD]
    <buffer service,time>
      @type file
      path /var/buffer/elasticsearch
      timekey 30s
      flush_mode interval               # flush_interval 에 설정한 시간마다 flush
      flush_interval 5s
      flush_thread_count 5
      retry_type exponential_backoff
      retry_forever false
      retry_wait 1                      # 첫 Retry 까지 기다리는 시간
      retry_exponential_backoff_base 2  # N 번 이상 실패했을 경우 exponential_backoff
      retry_randomize true              # exponential_backoff 에 random number 쓸지 말지     
      retry_max_interval 5m
      retry_timeout 72h                 # Maximum duration before giving up.
    </buffer>
    index_name fluentd-${service}-%Y%m%d
    include_tag_key true
    type_name access_log
    tag_key @log_name
    flush_interval 1s
    reconnect_on_error true
    reload_on_failure true
    reload_connections false

  </store>
  <store>
    @type stdout
  </store>
</match>

 

forward 되어 들어온 data 들을 elasticsearch 로 보낸다. <match></match> 부분은 저번 포스팅에서 fluentd 설정에서 사용했던 것과 같다.

 

 

 

Dockerfile 은 저번에 설정했던 것과 동일하다.

 

FROM fluent/fluentd:edge-debian 
ADD conf/fluentd.conf /fluentd/etc/fluentd.conf
USER root
RUN ["gem", "install", "fluent-plugin-elasticsearch", "--no-document", "--version", "4.3.3"]
USER fluent

 

 

이제 실행시켜보자.

 

~$ sudo docker build -f Dockerfile -t <ID>/fluentd-aggregator .
~$ sudo docker run -d -p 24224:24224 -e FLUENTD_CONF=fluentd.conf --network <YOUR_NETWORK_NAME> -v <YOUR_BUFFER_PATH>:/var/buffer -v <YOUR_POS_FOLDER>:/var/pos --name fluentd-aggregator <ID>/fluentd-aggregator


< Example >
~$ sudo docker build -f Dockerfile -t toast1ng/fluentd-aggregator .
~$ sudo docker run -d -p 24224:24224 -e FLUENTD_CONF=fluentd.conf --network elasticsearch_efk -v /home/ubuntu/fluentd-aggregator/buffer:/var/buffer -v /home/ubuntu/fluentd-aggregator/pos:/var/pos --name fluentd-aggregator toast1ng/fluentd-aggregator

 

 

아무런 문제없이 잘 작동한다.

 

 

 

 

 

 

fluentd 의 fluentd.conf 를 다음과 같이 수정하자.

<source>
  @type tail
  format json
  path /var/log/*.log
  path_key tailed_path
  pos_file /var/pos/service.pos
  tag fluentdlog.*
</source>

<match **>
  @type copy
  <store>
    @type forward
    <buffer>
      @type file
      total_limit_size 1GB              # File Buffer 의 Max Size
      path /var/buffer/fluentd
      flush_interval 5
      retry_wait 1                      # 첫 Retry 까지 기다리는 시간
      retry_exponential_backoff_base 2  # N 번 이상 실패했을 경우 exponential_backoff
      retry_randomize true              # exponential_backoff 에 random number 쓸지 말지          
      retry_max_interval 30s
      retry_timeout 72h                 # Retry 의 최대 Duration ( 3일로 설정함 )
      retry_forever false               
    </buffer>
    reconnect_on_error true
    reload_on_failure true
    reload_connections false
    <server>
      host <YOUR_IP_ADDRESS>
      port <YOUR_PORT>
    </server>
  </store>
  <store>
    @type stdout
  </store>
</match>

 

@forward 를 사용하여 원하는 Server IP 주소와 Port 로 Data 들을 보내도록 설정 파일을 고쳤다. 

 

 

 

 

Dockerfile 은 다음과 같다.

FROM fluent/fluentd:edge-debian
ADD conf/fluentd.conf /fluentd/etc/fluentd.conf

 

저번 파일에서 Elasticsearch 관련 명령어를 실행하는 부분을 없앴다.

 

 

 

이제 실행해보자.

~$ sudo docker build -f Dockerfile -t <ID>/fluentd .
~$ sudo docker run -d -e FLUENTD_CONF=fluentd.conf --network <YOUR_NETWORK_NAME> -v <YOUR_BUFFER_PATH>:/var/buffer -v <YOUR_POS_FOLDER>:/var/pos -v <YOUR_LOG_FOLDER>:/var/log --name fluentd <ID>/fluentd


< Example >
~$ sudo docker build -f Dockerfile -t toast1ng/fluentd .
~$ sudo docker run -d -e FLUENTD_CONF=fluentd.conf --network elasticsearch_efk -v /home/ubuntu/fluentd/buffer:/var/buffer -v /home/ubuntu/fluentd/pos:/var/pos -v /home/ubuntu/spring/log:/var/log --name fluentd toast1ng/fluentd

 

 

다 잘 실행되는지 확인하기 위해서, Service 에서 Log 를 발생시켜보자.

 

~$ curl -XPOST 'localhost:8080/loop?msg=hello&loopTimes=10&term=1'

 

 

~$ sudo docker logs -f fluentd-aggregator

 

 

 

Fluentd-Aggregator 의 로그를 확인해보면 5초에 한 번씩 Elasticsearch 로 잘 보내고 있음을 확인할 수 있다.

 

 

 


 

Kibana

 

Elasticsearch 에 잘 도달했는지 확인하고 싶다. 그런데 매번 API Call 을 사용해 확인하면 너무 번거로워진다.  Kibana 쓰면 더 간단하고 빠르게 볼 수 있다.

 

Kibana 는 Elasticsearch 와 연동되어, ES 의 Indexing 된 Data 를 검색할 수 있게 하고 표나 테이블 등으로 시각화시켜주는 하나의 툴이다. 사용자가 ES 로 Direct 하게 API Call 을 할 필요 없이, Kibana 가 제공해주는 웹 페이지에서 클릭과 입력 몇 번으로 모든 것을 가능하게 한다. Grafana 와 같은 다른 Monitoring Tool 을 사용해도 되지만 Kibana 는 Elasticsearch 와 같은 회사이므로 연동성이 훨씬 더 보장된다.

 

그럼 이제 Kibana 를 구축해보자.

 

 


 

파일 구조에 kibana/ 가 추가된다.

 

kibana/
   ∟ config/
      ∟ kibana.yml
   ∟ docker-compose.yml


elasticsearch/
   ∟ backup/
   ∟ config/
      ∟ elasticsearch.yml
   ∟ data/
   ∟ docker-compose.yml


fluentd-aggregator/
   ∟ buffer/
   ∟ conf/
      ∟ fluentd.conf
   ∟ pos/
      ∟ service.pos
   ∟ Dockerfile
   
   
fluentd/
   ∟ buffer/
   ∟ conf/
      ∟ fluentd.conf
   ∟ pos/
      ∟ service.pos
   ∟ Dockerfile


spring/
   ∟ log/
      ∟ simplelogging.log
   ∟ ......

 

 

 

kibana.yml

 

---
## Default Kibana configuration from Kibana base image.
## https://github.com/elastic/kibana/blob/master/src/dev/build/tasks/os_packages/docker_generator/templates/kibana_yml.template.ts
#
server.name: kibana
server.host: 0.0.0.0
elasticsearch.hosts: [ "http://<YOUR_ES_IP>:9200" ]
monitoring.ui.container.elasticsearch.enabled: true

## X-Pack security credentials
#
elasticsearch.username: elastic
elasticsearch.password: <YOUR_PASSWORD>
xpack.security.sessionTimeout: 600000

 

 

docker-compose.yml

 

version: '3.4'

services:
  kibana:
    image: docker.elastic.co/kibana/kibana:7.10.2
    container_name: kibana
    volumes:
      - ./config/kibana.yml:/usr/share/kibana/config/kibana.yml
    environment:
      - "ELASTICSEARCH_USERNAME=elastic"
      - "ELASTICSEARCH_PASSWORD=<YOUR_PASSWORD>"
    ports:
      - 5601:5601
    networks:
      - elasticsearch_efk

networks:
  elasticsearch_efk:
    external:
      name: elasticsearch_efk

 

 

다음과 같이 실행시킨다.

 

~$ sudo docker-compose -f docker-compose.yml up --build -d

 

 

 

잠시 기다렸다가 <Kibana_Server_IP>:5601 로 접속한다.

 

 

 

 

아이디 비번을 입력하여 접속하고 좌상단의 메뉴바를 눌러 Management > Stack Management 에 들어간다.

 

 

왼쪽의 Kibana > Index Patterns 에 들어가서

 

 

 

새 Index Pattern 을 생성해준다.

 

 

다 만들고 나서 Kibana > Discover 로 들어와 우상단의 시간 설정을 하면

발생시킨 로그들이 잘 있는 것을 확인할 수 있다.

 

 


 

이번 포스팅에서는 Fluentd Aggregator 를 사용해 Elasticsearch 의 부담을 줄이고, Kibana 까지 구축해봤다.

 

Elasticsearch 로 오는 트래픽 부담을 줄였다고는 하지만.. Elasticsearch 한 대만으로 충분한 것일까? 문제가 생기면 어떻게 해야 할까?

 

다음 포스팅에서는 이를 해결하기 위한 방법으로 Elasticsearch 의 Clustering 에 대해 다룰 것이다.

Comments