๋ชจ๋ํฐ๋ง์ ์ํด ์ต๊ทผ prometheus์ grafana๋ฅผ ํตํด metric์ ์์งํ๋ค.
์ด๋ฒ์ ๋ก๊ทธ ์์ง์ ์ํด elastic stack (elastic search + logstash + kibana) + filebeat ๋ก ๋ก๊ทธ ๊ด๋ฆฌ ์์คํ ์ ๊ตฌ์ถํด๋ณด์๋ค.
๋ก๊ทธ๋ฅผ ์์งํ๊ฒ ๋๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ด ์๋ค.
- 1. ์ฌ์ฉ์ ํ๋ ๋ถ์ ๋ก๊ทธ ๋ฐ์ดํฐ๋ฅผ ํตํด ์ฌ์ฉ์์ ํ๋ ํจํด์ ํ์ ํ๊ณ ์ด๋ฅผ ๋ฐํ์ผ๋ก ์๋น์ค ๊ฐ์ ๋ฐ ๋ง์ผํ ์ ๋ต์ ์ธ์ธ ์ ์๋ค.
- 2. ์ค๋ฅ ๋ฐ ๋ฒ๊ทธ ์ถ์ ๋ก๊ทธ๋ฅผ ํตํด ์์คํ ๋ด ๋ฐ์ํ ์ค๋ฅ๋ ๋ฌธ์ ๋ฅผ ํ์ธํ๊ณ ์ถ์ ํ ์ ์์ด, ์ํํธ์จ์ด์ ์์ ์ฑ๊ณผ ํ์ง์ ๊ฐ์ ํ ์ ์๋ค.
- 3. ์ฑ๋ฅ ์ต์ ํ ๋ก๊ทธ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ์ฌ ๋ฐ์ดํฐ ๋ฒ ์ด์ค ์์ , API ํธ์ถ, ์์คํ ๋ฆฌ์์ค ์ฌ์ฉ ๋ฑ ์์คํ ์ ์ฑ๋ฅ ์ํ๋ฅผ ํ์ ํ๊ณ , ์ด๋ฅผ ํตํด ์ฑ๋ฅ ๋ฌธ์ ์ ์ ์ฐพ์ ์์ ํ ์ ์๋ค.
- 4. ๋ณด์ ๊ฐ์ ๋ก๊ทธ๋ฅผ ํตํด ์์คํ ๋ด์ ๋น์ ์์ ์ธ ํ๋, ํดํน ์๋, ์ธ์ฆ ์คํจ ๋ฑ์ ์๋ณํ๊ณ , ๋ณด์ ์ทจ์ฝ์ ์ ์ฐพ์๋ผ ์ ์๋ค. ์ด๋ ์์คํ ๋ณด์์ ์ ์ง๋ฅผ ๋์ธ ๋ฟ๋ง ์๋๋ผ, ์ฌ์ด๋ฒ ๊ณต๊ฒฉ์ ๋ํ ๋์ ์ญ์ ๊ฐ๋ฅํ๊ฒ ํ๋ค.
๋ก๊ทธ ์์ง์ ํด์ผ๊ฒ ๋ค ๋๋ ๊ฐ์ฅ ํฐ ์ด์ ๋ " ๋ก๊ทธ๋ฅผ ํตํด ์์คํ ๋ด ๋ฐ์ํ ์ค๋ฅ๋ ๋ฌธ์ ๋ฅผ ํ์ธํ๊ณ ์ถ์ ํ์ฌ ์ฅ์ ์ ๋์ฒํ๊ณ , ์๋น์ค์ ์์ ์ฑ๊ณผ ์ฑ๋ฅ์ ๊ฐ์ " ํ ์์๊ธฐ ๋๋ฌธ์ด์๋ค.
โป ELK ์คํ ์ด๋?
Elasticsearch: JSON ๊ธฐ๋ฐ์ ๋ถ์ฐํ ์คํ ์์ค ๊ฒ์ ๋ฐ ๋ถ์ ์์ง, ์ฃผ๋ก REST API๋ฅผ ํตํด ์ฒ๋ฆฌํ๋ค.
Logstash: ์ฌ๋ฌ ์์ค์์ ๋์์ ๋ฐ์ดํฐ๋ฅผ ์์งํ์ฌ ๋ณํํ ํ, Elasticsearch ๊ฐ์ "stash"๋ก ์ ์กํ๋ ์๋ฒ์ฌ์ด๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ์ ๋งํ๋ค.
Kibana: Elasticsearch์์ ์์ธ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๊ณ ๋ณด๊ณ ์๊ฐํํ๋ฉฐ ๋ง๋ ์ฐจํธ, ์ํ ์ฐจํธ, ํ, ํ์คํ ๊ทธ๋จ, ์ง๋ ๋ฑ์ ์์ฑํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ ์ ์๊ฒ ํด์ค๋ค.
Filebeat:
- Filebeat๋ ๊ฒฝ๋ํ๋ ์ค๊ณ๋ก ์๋ํ๋ฉฐ, ์์คํ ์์์ ์ ๊ฒ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์์งํ์ฌ ์ฑ๋ฅ์์ ์ด์ ์ด ์๋ค.
- ์์งํ ๋ก๊ทธ ๋ฐ์ดํฐ๋ฅผ ElasticSearch ๋๋ Logstash์ ๊ฐ์ ์ ์ฅ์๋ก ์ค์๊ฐ์ผ๋ก ์ ์กํ๋ค. ์ด๋ ๊ฒ ํจ์ผ๋ก์จ ์ค์ ์ง์คํ๋ ๋ก๊ทธ ์์คํ ์์ ๋ก๊ทธ ๋ฐ์ดํฐ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ณ ๋ถ์ํ ์ ์๋ค.
๋ค์ด๊ฐ๊ธฐ ์์ ์ํคํ ํธ๋ ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ๋ค.
log file๋ค์ Filebeat์์ ์ฝ์ด Logstash๋ก ๋ณด๋ด์ค๋ค.
Logstash๋ ์์งํ log๋ฅผ ํํฐ๋ฅผ ๊ฑฐ์ณ Elasticsearch๋ก ๋ณด๋ด์ฃผ๊ณ
kibana์์ ์ด๋ฅผ ์๊ฐํ ํด์ค๋ค.
1. Application ๋ก๊ทธ ์์ง
๋จผ์ Spring Boot Application์์ ๋ก๊ทธ๋ฅผ ์์งํด์ผ ํ๋ค. logback ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ console์ ์ฐํ๋ ๋ก๊ทธ๋ค์ ํ์ผ๋ก ๋ฐฑ์ ํด์ฃผ์๋ค.
์ง๊ธ์ ์ฝ์์ ์ฐํ๋ log ์ ๋ถ๋ฅผ logback ํด์ฃผ์์ง๋ง ์ถํ์ aop๋ฅผ ํ์ฉํด์ request, error, respones์ ๋ํ ๋ก๊ทธ๋ง ์ฐ์ด๋ ๊ด์ฐฎ๊ฒ ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
- logback-spring.xml
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %clr(%5level) %cyan(%logger) - %msg%n" />
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger - %msg%n" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>./log/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<springProfile name="local">
<logger name="com.feelcoding.logbackdemo" level="DEBUG" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</springProfile>
<!-- <springProfile name="dev|stg">-->
<!-- <root level="INFO">-->
<!-- <appender-ref ref="CONSOLE" />-->
<!-- <appender-ref ref="FILE" />-->
<!-- </root>-->
<!-- </springProfile>-->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</springProfile>
</configuration>
2. Docker๋ก ELK ์คํ ๋ฐ ์ค์
https://github.com/deviantony/docker-elk
์ repository์์ clone๋ถํฐ ํด์ฃผ์.
- docker-compose.yml
version: '3.2'
services:
elasticsearch:
build:
context: elasticsearch/
args:
ELK_VERSION: $ELK_VERSION
volumes:
- type: bind
source: ./elasticsearch/config/elasticsearch.yml
target: /usr/share/elasticsearch/config/elasticsearch.yml
read_only: true
- type: volume
source: elasticsearch
target: /usr/share/elasticsearch/data
ports:
- "9200:9200"
- "9300:9300"
environment:
ES_JAVA_OPTS: "-Xmx256m -Xms256m"
ELASTIC_PASSWORD: elastic
# 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
networks:
- elk
logstash:
build:
context: logstash/
args:
ELK_VERSION: $ELK_VERSION
volumes:
- type: bind
source: ./logstash/config/logstash.yml
target: /usr/share/logstash/config/logstash.yml
read_only: true
- type: bind
source: ./logstash/pipeline
target: /usr/share/logstash/pipeline
read_only: true
ports:
- "5044:5044"
- "5000:5000/tcp"
- "5000:5000/udp"
- "9600:9600"
environment:
LS_JAVA_OPTS: "-Xmx256m -Xms256m"
networks:
- elk
depends_on:
- elasticsearch
kibana:
build:
context: kibana/
args:
ELK_VERSION: $ELK_VERSION
volumes:
- type: bind
source: ./kibana/config/kibana.yml
target: /usr/share/kibana/config/kibana.yml
read_only: true
ports:
- "5601:5601"
networks:
- elk
depends_on:
- elasticsearch
filebeat:
build:
context: filebeat/
args:
ELK_VERSION: $ELK_VERSION
volumes:
- /home/kevin/jikgong/logs:/var/log/host_logs:ro
- ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml
networks:
- elk
depends_on:
- logstash
networks:
elk:
driver: bridge
volumes:
elasticsearch:
์ฌ๊ธฐ์ ์ฃผ์ํด์ผํ ๊ฒ๋ค์ filebeat ๋ถ๋ถ์ด๋ค.
๋ค๋ค elk yml ํ์ผ์ ์ธํ ํด๋ repository์์ clone ํ elk๋ฅผ ์์ํ์คํ ๋ฐ ๊ทธ๋ผ filebeat ์ปจํ ์ด๋ ์ค์ ๋ถ๋ถ์ ์๋ค.
logstash๋ก ๋ก๊ทธ๋ฅผ ๋ณด๋ด๋ ๋ฐฉ๋ฒ์ redis, kafka ๋ฑ ์ฌ๋ฌ๊ฐ์ง ์์ง๋ง ์ ๋ filebeat๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ docker compose ํ์ผ์ ๋ฐ๋ก ์์ฑํด๋์๋ค.
์ฌ์ค ์ง๊ธ์์ ์๊ฐํด๋ณด๋ฉด ๊ตณ์ด filebeat๋ฅผ docker๋ก ๋์ ์ด์ผ ํ๋ ์ถ๋ค. ์ด ๊ธ์ ๋ณด๊ณ ๊ณ์ ๋ถ์ด๋ผ๋ฉด filebeat๋ ๊ทธ๋ฅ ์๋ฒ ํ๊ฒฝ์ ์ค์นํด์ ์ฐ์..
๋๋ docker๋ก ๋์ ๊ธฐ ๋๋ฌธ์
[์คํ๋ง ์ปจํ ์ด๋ ๋ก๊ทธ ํ์ผ] - [์ฐ๋ถํฌ ํ์ผ] - [filebeat ์ปจํ ์ด๋] ์ด๋ ๊ฒ ๋ณผ๋ฅจ์ ๊ฑธ์ด๋๋ค.
์ค์ ํ์ผ์ ํ๋ํ๋ ์ดํด๋ณด์
ElasticSearch
- Dockerfile
ARG ELK_VERSION
# https://www.docker.elastic.co/
FROM docker.elastic.co/elasticsearch/elasticsearch:${ELK_VERSION}
# Add your elasticsearch plugins setup here
# Example: RUN elasticsearch-plugin install analysis-icu
RUN elasticsearch-plugin install analysis-nori
- 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: "docker-cluster"
network.host: 0.0.0.0
Logstash
- Dockerfile
ARG ELK_VERSION
# https://www.docker.elastic.co/
FROM docker.elastic.co/logstash/logstash:${ELK_VERSION}
# Add your logstash plugins setup here
# Example: RUN logstash-plugin install logstash-filter-json
- config/logstash.yml
---
## Default Logstash configuration from Logstash base image.
## https://github.com/elastic/logstash/blob/master/docker/data/logstash/config/logstash-full.yml
#
http.host: "0.0.0.0"
# xpack.monitoring.elasticsearch.hosts: [ "http://elasticsearch:9200" ]
- pipeline/logstash.yml
input {
beats {
port => 5044
}
}
## Add your filters / logstash plugins configuration here
output {
elasticsearch {
hosts => "elasticsearch:9200"
index => "logstash-%{+yyyy.MM.dd}"
user => "elastic"
password => "elastic"
ecs_compatibility => disabled
}
}
์ฌ๊ธฐ์ input ์ port๋ logstash๊ฐ filebeat๋ก ๋ถํฐ ๋ฐ์ port์ฌ์ผํ๋ค.
๋์ค์ filebeat ์ค์ ํ์ผ์์ output port์ ๋ง์ถฐ์ฃผ๋ฉด ๋๋ค.
Kibana
- Dockerfile
ARG ELK_VERSION
# https://www.docker.elastic.co/
FROM docker.elastic.co/kibana/kibana:${ELK_VERSION}
# Add your kibana plugins setup here
# Example: RUN kibana-plugin install <name|url>
- 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://elasticsearch:9200" ]
monitoring.ui.container.elasticsearch.enabled: true
filebeat
- Dockerfile
ARG ELK_VERSION
FROM docker.elastic.co/beats/filebeat:${ELK_VERSION}
COPY filebeat.yml /usr/share/filebeat/filebeat.yml
USER root
RUN mkdir /var/logs
RUN chown -R root /usr/share/filebeat
filebeat ๋ Dockerfile ์์ฑํ ๋ ๋ฒ์ ์ ELK_VERSION์ผ๋ก ๊ฐ์ด ๋ง์ถฐ์ค์ผํ๋ค.
๋๋ ๋ฒ์ ์ ๋ง์ถฐ์ 1์๊ฐ์ ๊น๋จน์ ๊ฒ ๊ฐ์๋ฐ.. ์ฌ์ค ๋ก๊ทธ ๋ดค์ผ๋ฉด ๋นจ๋ฆฌ ํด๊ฒฐํ ์ ์๋ ๋ฌธ์ ์ธ๋ฐ ํ๋ฃจ ์ข ์ผ ํ๊ฒฝ ๊ตฌ์ถํ๋ฉด์ ์๋ฌ๋ ์ธ์ฐ๋ ๋จธ๋ฆฌ๋ ์ ๋์๊ฐ๊ณ ์์ธ ํ์ ์ด ์ฝ์ง ์์๋ ๊ฒ ๊ฐ๋ค..
- filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/host_logs/*.log
output.logstash:
hosts: ["logstash:5044"]
์ฌ๊ธฐ์ pahts๋ ๋ณธ์ธ์ด ์ฝ์ผ๋ ค๊ณ ํ๋ log์ ์์น๋ฅผ ์์ฑํด์ฃผ๋ฉด ๋๋ค.
๋๋ host_logs/ ๋ฐ์ access_log.{๋ ์ง}.log ์ info.log ๋๊ฐ์ง log ํ์ผ์ ์ฝ์ด์ฃผ๊ธฐ ์ํด ์์ ๊ฐ์ด ์์ฑํ๋ค.
์ฌ๊ธฐ๊น์ง ์ธํ ํ๋ค๋ฉด docker-compose.yml ํ์ผ ์์น๋ก ๋์๊ฐ ์คํํด์ค๋ค.
elastic search => logstash, kibana => filebeat ์์ผ๋ก ์ปจํ ์ด๋๊ฐ ๋์์ ธ์ผ ์ ์คํ๋๋ค. ํน์๋ docker compose๋ก ์คํํ์ง ์๋ ๋ถ์ด๋ผ๋ฉด ์ฐธ๊ณ ํ์๊ธธ
์ปจํ ์ด๋๊ฐ ์ ๋์์ก๋ค๋ฉด 5601 ํฌํธ๋ก ๋ค์ด๊ฐ๋ณด์. kibana ์น ํ์ด์ง๋ฅผ ๋ณผ ์ ์์ ๊ฒ์ด๋ค.
์ด์ index pattern์ ๋ฑ๋กํ๋ฌ ๊ฐ๋ณด์
์ด์ ์ logstash ์ค์ ํ์ผ์์ ๋ฑ๋กํด์ค index pattern ๋ค์ด ๋ณด์ผ ๊ฒ์ด๋ค.
๋ฑ๋กํด์ฃผ๊ณ ์ถ์๊ฒ๋ง ๋ฑ๋กํด์ฃผ๋ฉด ๋๋ค.
๋ฑ๋ก ํ discover ํญ์ผ๋ก ๋ค์ด๊ฐ๋ฉด!!!
๋๋์ด ๊ทธํ ๋ก ๋ณด๊ณ ์ถ์๋ ๋ก๊ทธ๋ค์ด ๋ณด์ด๊ธฐ ์์ํ๋ค.
Docker ๋ณผ๋ฅจ ์ค์ ํ๋ ๊ฒ ๋ถํฐ, elk ๋ค์ํ ์ค์ ํ์ผ ์์ ํ๋ ๊ฒ ๊น์ง ๊ฝค๋ ๋ง์ ์ํ์ฐฉ์ค๋ฅผ ๊ฒช์๋ค.
docker compose ํ์ผ์์ network๋ฅผ elk๋ก ์ก์๋์ง๋ง {๋๋ ํ ๋ฆฌ๋ช }_elk ๋ก ์๊ฒจ elk network์ ๋์๋์ filebeat์ ๋ค๋ฅธ network์ elk ์ปจํ ์ด๋๊ฐ ๋จ๋ ๋ฑ ์ฌ์ํ ๋ฌธ์ ๋ค์ด ๋ง์์ง๋ง ์๋ฌดํผ ์ฐ๋๊น์ง ์ฑ๊ณตํ๋ค.
์ด๋ฒ์๋ ๋๊ผ์ง๋ง ์ ๋ฐ ๋ก๊ทธ์ข ์ ๋ณด์!! ๋ก๊ทธ๋ง ์์ธํ ์ดํด๋ดค์ด๋ ์ด๋ณด๋จ ํจ์ฌ ๋นจ๋ฆฌ ๊ตฌ์ถํ ์ ์์์ ๊ฒ ๊ฐ๋ค.
elastic stack์ด ๋ฌ๋์ปค๋ธ๊ฐ ๊ต์ฅํ๋ค๊ณ .. ๋ค์๋๋ฐ ๋ก๊ทธ ๋ถ์๋ถํฐ ์ฐจ๊ทผ์ฐจ๊ทผ ๊ณต๋ถํด์ ์ฅ์ ๋์ฒ์ ๋ฅ์ํ ๋ฐฑ์๋ ๊ฐ๋ฐ์๊ฐ ๋๋๋ก ๋ ธ๋ ฅํด์ผ๊ฒ ๋ค