저번 글에서 ELK, EFK, PLG 스택을 비교해봤고, 그 중 가장 먼저 ELK를 선택했다고 했다. 레퍼런스도 많고, 커뮤니티도 활발하고.. 일단 해보고 안되면 바꾸자는 마음으로.
ELK, 어떤 버전으로 구축할까?
ELK를 선택했는데 여기서 또 선택지가 생긴다.
ELK는 크게 두 가지 버전이 있다.
버전 라이선스 비고
| 유료 버전 (Elastic License) | 상업적 이용 제한 | 모든 기능 사용 가능 |
| 오픈소스 버전 | Apache 2.0 / AGPL | 버전마다 다름 |
재직중인 회사는 외부 고객사에 납품하는 구조라 상업적으로 자유롭게 쓸 수 있는 Apache 2.0 라이선스가 필요했다. 그러니 오픈소스 버전으로 가야 했는데.. 일단 최신 버전부터 구축해봤다.
먼저 최신 오픈소스 버전으로 구축
Elastic은 2024년에 다시 오픈소스 전환을 했다. 8.x 버전도 오픈소스로 사용이 가능해진 것.
그래서 일단 8.x 최신 버전으로 구축해봤다.
docker-compose.yml
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
container_name: elasticsearch
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms512m -Xmx512m
ports:
- "9200:9200"
volumes:
- es_data:/usr/share/elasticsearch/data
networks:
- elk
logstash:
image: docker.elastic.co/logstash/logstash:8.13.0
container_name: logstash
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
ports:
- "5000:5000/tcp"
- "5000:5000/udp"
- "9600:9600"
networks:
- elk
depends_on:
- elasticsearch
kibana:
image: docker.elastic.co/kibana/kibana:8.13.0
container_name: kibana
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
networks:
- elk
depends_on:
- elasticsearch
apm-server:
image: docker.elastic.co/apm/apm-server:8.13.0
container_name: apm-server
volumes:
- ./apm-server/apm-server.yml:/usr/share/apm-server/apm-server.yml
ports:
- "8200:8200"
networks:
- elk
depends_on:
- elasticsearch
- kibana
volumes:
es_data:
networks:
elk:
driver: bridge
logstash/pipeline/logstash.conf
input {
tcp {
port => 5000
codec => json_lines
}
}
filter {
date {
match => ["@timestamp", "ISO8601"]
target => "@timestamp"
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "myservice-logs-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
apm-server/apm-server.yml
apm-server:
host: "0.0.0.0:8200"
output.elasticsearch:
hosts: ["http://elasticsearch:9200"]
kibana:
host: "http://kibana:5601"
enabled: true
📂 [추가 내용 예시] 도커 없이? 온프레미스 직접 설치하기 (v7.10.2 OSS)
회사의 보안 정책이나 인프라 상황에 따라 도커를 사용하지 못하는 경우가 있습니다. 이럴 때는 각 컴포넌트의 OS별 아카이브(zip/tar.gz) 파일을 내려받아 직접 실행해야 합니다.
1. Elasticsearch 설정 (elasticsearch.yml)
설치 경로의 config/elasticsearch.yml을 수정합니다.
# 네트워크 설정 (외부 접속 허용 시)
network.host: 0.0.0.0
http.port: 9200
# 단일 노드 모드 설정 (테스트/소규모 환경)
discovery.type: single-node
# 보안 설정 (OSS 버전에서는 기본적으로 비활성화되어 있거나 간소화됨)
xpack.security.enabled: false
2. Logstash 설정 (logstash.conf)
Docker와 동일하게 파이프라인 파일을 만들되, 실행 시 -f 옵션으로 경로를 지정해줍니다.
# 실행 예시
bin/logstash -f config/logstash.conf
3. Kibana 설정 (kibana.yml)
config/kibana.yml에서 Elasticsearch 주소를 연결해줍니다.
server.port: 5601
server.host: "0.0.0.0"
elasticsearch.hosts: ["http://localhost:9200"]
4. 서비스 등록 (Windows/Linux)
- Windows: nssm 같은 도구를 사용해 Windows Service로 등록하면 재부팅 시에도 자동 실행됩니다.
- Linux: systemd 서비스 유닛 파일을 작성하여 systemctl로 관리하는 것이 정석입니다.
5. JAVA버전 설정
- 시스템 환경에 이미 JAVA가 설정되어있다면 버전이 맞지않아 문제가 발생할 수 있다(JAVA11로 실행 필수), 기본적으로 내장으로 자바를 파일 내에 가지고 있지만 이미 설정된 환경변수가 있는경우 오류가 발생하면서 실행이 안될 수 있다.
- JAVA_HOME 충돌 문제 해결을 위해서 아래와 같이 자바의 실행 경로를 추가해주는것이 좋다.
Elasticsearch (bin/elasticsearch)
# bin/elasticsearch 파일 상단에 추가
export ES_JAVA_HOME=$ES_HOME/jdk
Logstash (bin/logstash)
# bin/logstash 파일 상단에 추가
export LS_JAVA_HOME=$LS_HOME/jdk
로그는 Logback으로 직접 쏜다
파일을 읽는 방식 말고, 애플리케이션에서 Logstash로 직접 전송하는 방식을 택했다. 실시간성도 좋고, 파일 파싱 과정도 생략할 수 있어서.
logstash-logback-encoder 라이브러리를 사용했다. 이 라이브러리는 Elastic이랑 전혀 무관한 별개의 오픈소스라, ELK 버전에 상관없이 동일하게 쓸 수 있다.
<!-- pom.xml -->
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Logstash로 직접 전송 -->
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>localhost:5000</destination>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"service_name":"my-service"}</customFields>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="LOGSTASH"/>
</root>
</configuration>
이러면 평소처럼 로거 쓰면 자동으로 Logstash로 날아간다.
@Slf4j
@RestController
public class SampleController {
@GetMapping("/hello")
public String hello() {
log.info("hello 요청 들어옴");
log.warn("뭔가 수상한 상황");
log.error("이건 진짜 문제");
return "hello";
}
}
APM으로 Trace까지 붙이기
Trace는 APM 에이전트로 붙였다.
<!-- pom.xml -->
<dependency>
<groupId>co.elastic.apm</groupId>
<artifactId>apm-agent-attach</artifactId>
<version>1.48.0</version>
</dependency>
ElasticApmAttacher.attach(Map.of(
"service_name", "my-service",
"server_url", "http://localhost:8200",
"application_packages", "com.example"
));
[이미지 첨부 예정 - Kibana 대시보드 화면]
[이미지 첨부 예정 - APM Trace 화면]
로그도 잘 들어오고, Trace도 잘 잡히고.. "오 이거 생각보다 되는데?" 싶었던 순간이었다.
근데 잠깐, 라이선스를 다시 확인해보자
여기서 한 가지 찜찜한 게 생겼다. 8.x가 오픈소스로 전환됐다고는 하는데, 정확히 어떤 라이선스냐가 문제였다.
라이선스 히스토리를 정리하면 이렇다.
시기 라이선스
| 초기 ~ 7.10.2 | Apache 2.0 ✅ |
| 7.11 ~ 8.x 초반 | SSPL + Elastic License ❌ |
| 2024년 이후 (8.16~) | AGPLv3 + SSPL + Elastic License |
여기서 문제가 생겼다. 회사에서 필요한 건 Apache 2.0이었다. AGPLv3는 OSI 승인 오픈소스 라이선스긴 한데, 네트워크로 서비스를 제공하는 경우에도 소스코드 공개 의무가 생긴다. 외부 고객사에 납품하는 구조에서는 이게 매우 부담스러운 조건이었다.
결론은 하나.
Apache 2.0으로 사용 가능한 마지막 버전은 7.10.2.
그래서 7.10.2 OSS로 다시 구축했다
-oss 빌드로 내려가서 다시 구축했다. Logback 설정은 버전 무관하게 동일하게 쓸 수 있어서 그대로 재사용했다.
docker-compose.yml
version: '3.7'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2
container_name: elasticsearch
environment:
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms512m -Xmx512m
ports:
- "9200:9200"
volumes:
- es_data:/usr/share/elasticsearch/data
networks:
- elk
logstash:
image: docker.elastic.co/logstash/logstash-oss:7.10.2
container_name: logstash
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
ports:
- "5000:5000/tcp"
- "5000:5000/udp"
- "9600:9600"
networks:
- elk
depends_on:
- elasticsearch
kibana:
image: docker.elastic.co/kibana/kibana-oss:7.10.2
container_name: kibana
ports:
- "5601:5601"
environment:
ELASTICSEARCH_HOSTS: '["http://elasticsearch:9200"]'
networks:
- elk
depends_on:
- elasticsearch
apm-server:
image: docker.elastic.co/apm/apm-server-oss:7.10.2
container_name: apm-server
volumes:
- ./apm-server/apm-server.yml:/usr/share/apm-server/apm-server.yml
ports:
- "8200:8200"
networks:
- elk
depends_on:
- elasticsearch
- kibana
volumes:
es_data:
networks:
elk:
driver: bridge
그리고 결과는..
[이미지 첨부 예정 - APM 오류 화면]
Trace가 제대로 동작하지 않았다. Kibana APM 탭이 정상적으로 뜨지 않거나, 라이선스 관련 오류가 발생했다. 7.10.2 OSS 빌드에서는 APM의 Trace 기능에 필요한 일부 컴포넌트가 빠져있었던 것.
대충.. 멘탈이 나가는 순간이었다.
정리하면 상황이 이렇다.
스택 로그 Trace Apache 2.0
| ELK 8.x | ✅ | ✅ | ❌ |
| ELK 7.10.2 OSS | ✅ | ❌ | ✅ |
이도 저도 안되는 상황이 었다..
댓글