일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 이력서
- ubuntu
- cv
- aws sns
- 로깅시스템
- 2024년
- efk
- root password
- 포트앤어댑터아키텍처
- 만들면서배우는클린아키텍처
- Fluentd Aggregator
- 로그관제시스템
- aws sqs
- Spring boot
- 이력서페이지
- interface default
- 회고록
- spring_cv
- openjdk-8-jdk
- Spring
- ubuntu docker
- 헥사고날아키텍처
- mac docker
- 클린아키텍처
- docker
- ubuntu20.04LTS
- FluentdTail
- spring sleuth
- docker설치
- FluentdElasticsearch
- Today
- Total
ToasT1ng 기술 블로그
[EFK] 2. 간단한 EFK 구축 (2) 본문
지난 포스팅에서는 우리가 구축할 EFK 의 전체적인 구조와, Service 역할을 해줄 간단한 Spring Boot App 을 제작했었다.
[EFK] 1. 간단한 EFK 구축 (1)
EFK 의 구조 대부분의 로깅 시스템은 이런 식으로 구성된다. ( 지난 포스팅 참조 ) 이번에 구축할 EFK 의 구조는 다음과 같이 이루어진다. Spring - Log 를 발생시키는 Service 의 역할을 담당한다. - Log
toast1ng.tistory.com
이어서 오늘은 Fluentd 를 구축해보도록 하겠다.
Fluentd
Fluentd 는 기본적으로는 로그 수집기 역할을 한다. 하지만 꼭 로그 수집기로만 사용하지 않을 수도 있다. Fluentd 는 다양한 형태의 Input 을 받아서 다양한 형태의 Output 으로 들어온 값들을 배출해낼 수 있다. Input 은 대부분 Http 나 TCP 형태로 이루어져 있으며, Output 은 Elasticsearch 를 비롯하여, Http, File, S3, Kafka 등 무궁무진한 플러그인이 존재한다. 자세한건 Fluentd 공식 레퍼런스를 참조하자.
Introduction
docs.fluentd.org
일단 기본적인 설치를 진행해보자. Docker 를 사용해 간단히 설치할 것이다.
전체 파일 구조
fluentd/
∟ conf/
∟ fluentd.conf
∟ Dockerfile
Dockerfile
FROM fluent/fluentd:edge-debian
ADD conf/fluentd.conf /fluentd/etc/fluentd.conf
fluentd.conf
<source>
@type http
port 8888
</source>
<match **>
@type stdout
</match>
Http 로 값을 입력받아 Console 창에 보여주는 간단한 Fluentd 설정이다.
다음과 같이 실행한다.
~$ sudo docker build -f Dockerfile -t <ID>/fluentd .
~$ sudo docker run -d -p 8888:8888 -e FLUENTD_CONF=fluentd.conf --name fluentd <ID>/fluentd
< Example >
~$ sudo docker build -f Dockerfile -t toast1ng/fluentd .
~$ sudo docker run -d -p 8888:8888 -e FLUENTD_CONF=fluentd.conf --name fluentd toast1ng/fluentd
~$ curl -X POST -d 'json={"foo":"bar"}' http://localhost:8888/some.logtag
그러면 콘솔창에 다음과 찍힐 것이다.
~$ sudo docker logs -f -n 10 fluentd
Http 를 이용해 보낸 값이 잘 들어옴을 확인할 수 있다.
이번엔 파일을 Tail 해와서 콘솔창에 띄워보자.
전체 파일 구조가 다음과 같이 바뀐다.
fluentd/
∟ conf/
∟ fluentd.conf
∟ pos/
∟ service.pos
∟ Dockerfile
spring/
∟ log/
∟ simplelogging.log
∟ ......
fluentd.conf 를 다음과 같이 수정한다.
<source>
@type tail
format json
path /var/log/*.log, [WHATEVER_YOU_WANT]
pos_file /var/pos/service.pos
tag fluentdlog.*
</source>
<match **>
@type stdout
</match>
path 는 , 를 사용해 여러 경로를 지정할 수 있다. 원하는대로 쓰면 된다.
<예시>
<source>
....
path /var/log/*.log, /a/b/*.log
....
</source>
pos_file 을 사용해 fluentd 가 파일을 어디까지 읽었는지 저장하도록 한다. 일종의 책갈피 역할을 하는 셈이다. Volume 설정을 하면 Docker Container 를 껐다켜도 pos_file 이 날아가지 않아 정확히 그 다음 지점부터 파일을 읽어들인다. pos_file 을 열면 다음과 같은 형태로 File 의 읽은 위치가 저장되어있다.
다음과 같이 실행한다.
~$ sudo docker build -f Dockerfile -t <ID>/fluentd .
~$ sudo docker run -d -e FLUENTD_CONF=fluentd.conf -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 -v /home/ubuntu/fluentd/pos:/var/pos -v /home/ubuntu/spring/log:/var/log --name fluentd toast1ng/fluentd
그리고 Spring 을 실행시켜 로그를 발생시키면, 콘솔창에 다음과 찍힐 것이다.
~$ sudo docker logs -f -n 10 fluentd
~$ curl -XPOST 'localhost:8080/loop?msg=hello&loopTimes=10&term=1'
만약 여기까지 하는데 어떤 문제가 생긴다면 service.pos 혹은 *.log 파일의 권한 문제일 확률이 높다. docker 가 파일을 수정하거나 읽을 수 있도록 권한을 조정해주면 문제가 해결될 것이다.
이번엔 Elasticsearch 에다가 로그를 보내보도록 하자. 그러려면 우선, Elasticsearch 를 구축해야한다. 이번에도 역시 Docker 를 사용한다.
전체 파일 구조에 다음과 같이 추가된다.
elasticsearch/
∟ backup/
∟ config/
∟ elasticsearch.yml
∟ data/
∟ docker-compose.yml
fluentd/
∟ buffer/
∟ conf/
∟ fluentd.conf
∟ pos/
∟ service.pos
∟ Dockerfile
spring/
∟ log/
∟ simplelogging.log
∟ ......
fluentd 에 buffer/ 폴더가 추가되었다. 이에 관한 내용은 아래에서 다룬다.
elasticsearch 의 backup/ 과 data/ 폴더는 host machine 에 꼭 만들어서 docker volume 으로 연결해줘야한다. 그렇게 하지 않으면 elasticsearch docker container 를 껐을 때 모든 데이터가 다 날아간다... 처음에 구축할 때 이거 때문에 삽질 많이 했다.. 데이터가 날아가면 이후에 진행할 첫 셋팅부터 하나 하나 다시 해야한다.
elasticsearch.yml
---
## Default Elasticsearch configuration from Elasticsearch base image.
## https://github.com/elastic/elasticsearch/blob/master/distribution/docker/src/docker/config/elasticsearch.yml
#
cluster.name: "elasticsearch"
network.host: 0.0.0.0
path.repo: ["/usr/share/elasticsearch/backup"]
## X-Pack settings
## see https://www.elastic.co/guide/en/elasticsearch/reference/current/setup-xpack.html
#
xpack.license.self_generated.type: trial
xpack.security.enabled: true
xpack.monitoring.collection.enabled: true
## Use single node discovery in order to disable production mode and avoid bootstrap checks
## see https://www.elastic.co/guide/en/elasticsearch/reference/current/bootstrap-checks.html
#
discovery.type: single-node
일단은 clustering 없이 간단히 Single Mode (1 node) 로 구축한다. xpack security 를 enable 시켜 아이디 - 비밀번호를 사용해 접근할 수 있도록 세팅한다.
X-Pack 은 Basic 라이센스 이상에서 사용할 수 있다. 필자가 사용할 ES 버전에서는 Basic 라이센스가 무료로 제공된다. 더 자세한 것은 아래 링크를 참조하기 바란다.
https://www.elastic.co/kr/blog/security-for-elasticsearch-is-now-free
Security for Elasticsearch is now free
Elastic Stack의 핵심 보안 기능이 이제 무료 제공된다는 기쁜 소식을 전해 드립니다. 이제 사용자가 네트워크 트래픽을 암호화하고, 사용자들을 생성 및 관리하며, 인덱스와 클러스터 수준의 액세
www.elastic.co
docker-compose.yml
version: '3.4'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
container_name: elasticsearch
environment:
- "ES_JAVA_OPTS=-Xmx512m -Xms512m"
- "ELASTIC_PASSWORD=<YOUR_PASSWORD>"
volumes:
- ./config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
- ./data:/usr/share/elasticsearch/data
- ./backup:/usr/share/elasticsearch/backup
ports:
- 9200:9200
- 9300:9300
networks:
- efk
networks:
efk:
driver: bridge
그리고 다음과 같이 실행시킨다.
~$ sudo docker-compose -f docker-compose.yml up -d
~$ curl -uelastic:<YOUR_PASSWORD> -XGET 'localhost:9200/_cat/indices?v'
Elasticsearch 가 성공적으로 실행되었다.
이제 Fluentd 가 Index 를 생성할 수 있게, ID 를 만들어줘야한다. Kibana 를 사용하면 쉽게 만들 수 있지만, 일단 curl 을 사용해 생성하도록 하겠다.
~$ curl -uelastic:<YOUR_PASSWORD> -XPUT http://localhost:9200/_xpack/security/role/fluentd_writer -H 'Content-Type: application/json' -d'
{
"cluster": ["manage_index_templates", "monitor", "manage_ilm"],
"indices": [
{
"names": [ "*" ],
"privileges": ["write","delete","create_index","manage","manage_ilm"]
}
]
}'
~$ curl -uelastic:<YOUR_PASSWORD> -XPUT http://localhost:9200/_xpack/security/user/fluentd_user -H 'Content-Type: application/json' -d'
{
"password" : "<YOUR_PASSWORD>",
"roles" : [ "fluentd_writer"],
"full_name" : "Fluentd User"
}'
<Example>
~$ curl -uelastic:1234 -XPUT http://localhost:9200/_xpack/security/role/fluentd_writer -H 'Content-Type: application/json' -d'
{
"cluster": ["manage_index_templates", "monitor", "manage_ilm"],
"indices": [
{
"names": [ "*" ],
"privileges": ["write","delete","create_index","manage","manage_ilm"]
}
]
}'
Return Value : {"role":{"created":true}}
~$ curl -uelastic:1234 -XPUT http://localhost:9200/_xpack/security/user/fluentd_user -H 'Content-Type: application/json' -d'
{
"password" : "12345678",
"roles" : [ "fluentd_writer"],
"full_name" : "Fluentd User"
}'
Return Value : {"created":true}
첫번째로 호출하는 API 는 Role 을 만드는 것이고, 두번째로 호출하는 API 는 User 를 만드는 것이다.
먼저 Role 부터 살펴보자.
fluentd_writer
+ cluster ( elasticsearch cluster )
- manage_index_template : index template 을 manage 할 수 있음.
- monitor
- manage_ilm : Index Lifecycle Management (ilm) 를 manage 할 수 있음.
+ indices ( index 들 )
- names : 해당하는 이름에 대해서 privileges 부여
- privileges : 해당하는 권한 부여.
fluentd_writer 라는 role 은 elasticsearch cluster 에 대해 index template 을 manage 할 수 있고, monitor 할 수 있으며, Index Lifecycle Management (ilm) 를 manage 할 수 있다.
그리고 elasticsearch 의 모든 index 들에 대해서 ( "names": [ "*" ] ) write, delete, create, manage, manage_ilm (manage index lifecycle) 이 가능하다.
다음으로는 User 이다.
fluentd_user
+ password : 이 유저에 대한 비밀번호를 설정한다.
+ roles : 이 유저에게 role 들을 부여한다.
+ full_name : (optional) 이 유저의 이름을 부여한다.
더 자세한건 공식 레퍼런스를 참조하면 된다.
Security APIs | Elasticsearch Guide [7.14] | Elastic
To use the security APIs, you must set xpack.security.enabled to true in the elasticsearch.yml file. You can use the following APIs to perform security activities. Application privilegesedit You can use the following APIs to add, update, retrieve, and remo
www.elastic.co
이제 Fluentd 설정만 남았다.
fluentd 에서 elasticsearch 로 보낼 수 있도록 공식적인 플러그인을 제공해준다. 이 플러그인을 사용하기 위해서 Dockerfile 을 다음과 같이 수정해준다.
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
fluentd.conf 를 다음과 같이 수정한다.
<source>
@type tail
format json
path /var/log/*.log
pos_file /var/pos/service.pos
tag fluentdlog.*
</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>
<buffer></buffer> Tag 안의 설정은 아래에 더 자세히 나와있다.
Buffer Plugins
docs.fluentd.org
이제 Fluentd 를 다음과 같이 실행시킨다.
~$ 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
Buffer Path 와 Network 가 추가되었다. network 는 ES Docker Container 와 Fluentd Container 가 서로 통신하기 위해서 추가했고, Buffer Path 는 모종의 이유로 Fluentd 자체가 Down 됐을 경우에 대비하기 위해 만들었다.
만약 File Buffer 를 사용하지 않고 Ram 을 이용한 Buffer 를 사용하게 된다면, 아직 처리되지 못해 Fluentd 에서 쌓여있던 모든 Log 들이 (Elasticsearch 로 가기 전 상태인 것들) 휘발되게 된다. File Buffer 를 사용하면 File 로 남아있기 때문에 Data 의 유실 위험성이 줄어든다.
Buffer 폴더에 대한 권한 설정을 잘못하면 아래와 같은 에러가 뜰것이다.
chmod 로 폴더 권한을 잘 설정해주면 아래와 같이 정상적으로 Fluentd 를 실행시킬 수 있다.
이제, Log 를 발생시키고 Elasicsearch 에게 다음과 같이 명령을 날린다.
~$ curl -uelastic:<YOUR_PASSWORD> -XGET 'localhost:9200/<INDEX_NAME>*/_search?pretty'
~$ curl -uelastic:1234 -XGET 'localhost:9200/fluentd*/_search?pretty'
위의 명령은 Index 이름으로 그 Index 에 속하는 모든 Document 를 검색하는 API Call 이다. 이에 대한 응답은 아래와 같은 형태로 뜬다.
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 2,
"successful" : 2,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 13,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
.....
{
"_index" : "fluentd-simplelogging-20210905",
"_type" : "_doc",
"_id" : "st7utXsBbP9_lGQpmZ2p",
"_score" : 1.0,
"_source" : {
"@timestamp" : "2021-09-05T21:28:31.907+0900",
"level" : "INFO",
"service" : "simplelogging",
"trace" : "2cf4d003ad4baaa6",
"span" : "2cf4d003ad4baaa6",
"thread" : "http-nio-8080-exec-5",
"logger" : "com.toast1ng.simplelogging.service.LoggingService",
"message" : "hello",
"@log_name" : null
}
},
.....
]
}
}
_source 안에 우리가 보낸 로그의 내용이 Json 형태로 저장되어있는 것을 볼 수 있다.
이번 포스팅에서는 간단히 Service -> Fluentd -> Elasticsearch 까지 구성해봤다.
만약 여러 Service 에서 ( 물리적으로 다른 공간들) 로그를 수집해 Elasticsearch 로 보낸다면 어떻게 될까? Elasticsearch 하나가 이를 다 버틸 수 있을까?
못 버틴다면 어떻게 해야할까?
다음 포스팅에서는 위에 대한 문제를 해결하기 위하여 Fluentd Aggregator 와 Elasticsearch Clustering ( + Kibana ) 에 대해 다루게 될 것이다.
'로깅시스템' 카테고리의 다른 글
[EFK] 4. 쓸만한 EFK 구축 (2) - Elasticsearch (0) | 2022.04.09 |
---|---|
[EFK] 3. 쓸만한 EFK 구축 (1) - Fluentd Aggregator (0) | 2021.09.25 |
[EFK] 1. 간단한 EFK 구축 (1) (0) | 2021.08.21 |
[EFK] 0. 로그 관제 시스템? EFK? (0) | 2021.08.16 |