π ELK Β· API Gateway Β· Logback μ€μ κ΄λ¦¬μ μλ² κ΅¬μΆ
π ELK Β· API Gateway Β· Logback μ€μ κ΄λ¦¬μ μλ² κ΅¬μΆ
ELK
Β· API Gateway
λμ
κ·Όκ±°
β
ELK
- μμ€ν κ³Ό μλΉμ€ λ‘κ·Έλ₯Ό μ€μμμ ν΅ν© μμ§ λ° μ μ₯ν μ μλ€.
Kibana
λ₯Ό ν΅ν΄ μ€μκ° λμ보λ λ° μκ°νλ₯Ό ꡬμ±νμ¬ μ΄μ νν©μ λͺ¨λν°λ§ ν μ μλ€.- μλΉμ€ μ₯μ λ μ€λ₯ λ°μ μ, λ‘κ·Έ κ²μμ ν΅ν΄ λΉ λ₯΄κ² μμΈμ νμ νκ³ λμν μ μλ€.
β
API Gateway
JWT
μΈμ¦ λ° μΈκ°λ₯Ό μ λ΄ν μ μλ€.- λ무 λ§μ μμ²μ 보λ΄λ ν΄λΌμ΄μΈνΈλ₯Ό μ°¨λ¨ λ° μ μ΄ κ°λ₯νλ€.
API
λ²μ κ΄λ¦¬ κ°λ₯νλ€.- μλΉμ€ λ³ μμ΄ν
API
κ³μ½μ νμ€ν νμ¬ μΈλΆμ μ 곡νλ€.
β
Logback
- λ‘κ·Έ νμΌ λ‘€λ§ λ° λ³΄μ‘΄ μ€μ μ΄ μ μ°νκ² κ°λ₯νλ€.
μ½λ μμ±
β
ELK
Docker-compose.yml
λ° μ€μ νμΌ
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# docker-compose.yml
services:
elasticsearch:
Β Β image: docker.elastic.co/elasticsearch/elasticsearch:7.17.18
Β Β container_name: elasticsearch
Β Β environment:
Β Β - discovery.type=single-node
Β Β - ES_JAVA_OPTS=-Xms512m -Xmx512m
Β Β volumes:
Β Β - esdata:/usr/share/elasticsearch/data
Β Β ports:
Β Β - "9200:9200"
Β Β networks:
Β Β - efk
Β
Β kibana:
image: docker.elastic.co/kibana/kibana:7.17.18
container_name: kibana
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
depends_on:
- elasticsearch
networks:
- efk
logstash:
image: docker.elastic.co/logstash/logstash:7.17.18
container_name: logstash
volumes:
- ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
- ./logstash/pipeline:/usr/share/logstash/pipeline
- ./sentinel-app/logs:/app/logs
ports:
- "5044:5044"
- "9600:9600"
depends_on:
- elasticsearch
networks:
- efk
gateway:
build:
context: ./sentinel-app
container_name: sentinel-app
ports:
- "8080:8080"
volumes:
- ./sentinel-app/logs:/app/logs
networks:
- efk
volumes:
esdata:
networks:
efk:
Β Β
# logstash.yml
http.host: "0.0.0.0"
xpack.monitoring.enabled: false
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
# logstash.conf
input {
file {
path => "/app/logs/*.log"
start_position => "beginning"
sincedb_path => "/dev/null"
codec => json
}
}
filter {
mutate {
add_field => {
"log_message" => "%{message}"
"server_role" => "gateway"
}
remove_field => ["parsed", "host", "path", "message"]
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "sentinel-logs-%{+YYYY.MM.dd}"
}
stdout {
codec => rubydebug
}
}
Logback
μ€μ νμΌ
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
# logback-spring.xml
<configuration>
<include resource="net/logstash/logback/logback.xml"/>
<property name="LOG_PATH" value="./logs"/>
<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/app-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<fieldNames>
<timestamp>@timestamp</timestamp>
<level>level</level>
<logger>logger</logger>
<thread>thread</thread>
<message>message</message>
</fieldNames>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="JSON_FILE"/>
</root>
</configuration>
Logback
μ μ¬μ©νμ¬ λ‘κ·Έ νμΌμ μμ±νλ€.<include resource="net/logstash/logback/logback.xml"/>
λΌμΈμ ν΅ν΄Logstash
μ λ§λJSON
νμμ λ‘κ·Έ νμΌμ μΆλ ₯νλ€.<encoder class="net.logstash.logback.encoder.LogstashEncoder"> ... </encoder>
λΌμΈμ ν΅ν΄ λ‘κ·Έμ κ° νλͺ©μ λνλΈλ€.- μ΄ νλͺ©λ€μ
Elasticsearch
μμ νν°λ§ ν μ μλMetadata
κ° λλ κ²μ΄λ€. Logstash
λ λ‘κ·Έ νμΌμ μ½μ΄Elasticsearch
λ‘ μ λ¬νλ€.logstash.yml
μhttp.host
ν€λ₯Ό ν΅ν΄ ν μλ²μμλ λ‘κ·Έλ₯Ό μ μ‘ν μ μλ€.logstash.conf
μ€μ μ ν΅ν΄ κ°κ³΅ λ° νν°λ§ νμ¬ μΈλ±μ€λ‘ μμ± λ° λ°μ΄ν°λ₯Ό μ£Όμ νλ€.
β
API Gateway
μ€μ νμΌμΌ
1
implementation 'org.springframework.cloud:spring-cloud-starter-gateway:4.2.0'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# application.yml
spring:
application:
name: gateway
cloud:
gateway:
routes:
- id: 332-project-management-service
uri: http://127.0.0.1:8081
predicates:
- Path=/project-management/**
filters:
- StripPrefix=1
- id: 332-service-desk
uri: http://127.0.0.1:8082
predicates:
- Path=/service-desk/**
filters:
- StripPrefix=1
server:
port: 8080
Spring Cloud Gateway
λ₯Ό μ¬μ©νλ€.predicates
ν€λ₯Ό ν΅ν΄ κ²½λ‘Endpoint
λ₯Ό μ€μ νλ€.filters
ν€μStripPrefix=1
κ°μ ν΅ν΄predicates
ν€μμ μ€μ ν μλν¬μΈνΈμ/**
μ μ€μ API μμ² κ²½λ‘λ‘ μ§μ νλ€.- κ°λ Ή
http://localhost:8080/project-management/project
λ‘POST
λ°μμ μμ²μ΄ λ€μ΄μ€λ©΄API Gateway
κ° μμ²μhttp://localhost:8081/project
λ‘Redirect
νλ€.Β
λ‘κ·Έ λΆμ
β νλ‘μ νΈ μ€ν λ° λ‘κ·Έ νμΌ νμΈ
β
Kibana UI
νμΈ
- λ‘κ·Έ νμΌκ³Ό λμΌν μΌμμ λ°μ΄ν°κ° μ‘΄μ¬νλ κ²μ νμΈν μ μλ€.
logback-spring.xml
μμlevel
μ νλμ μΆκ°νκΈ° λλ¬ΈμElasticsearch
λ°Kibana
μμ λ‘κ·Έ λ 벨 λ³ νν°λ§μ ν μ μκ² λμλ€.
νκ³
- μ΄μ κΈ°μ‘΄ νλ‘μ νΈλ€μ
JWT
μΈμ¦ λ‘μ§μAPI Gateway
μλ²μμ μ λ΄νλλ‘ μμ ν΄μΌ νλ€. - λν νλ‘μ νΈλ€μ λ‘κ·Έλ₯Ό
API Gateway
μλ²λ‘ μ μ‘νμ¬ ν΅ν© κ΄λ¦¬νλλ‘ μμ ν κ²μ΄λ€.
This post is licensed under CC BY 4.0 by the author.