애플리케이션의 Observability를 높인다고 하면, 메트릭, 트레이스 그리고 로그의수집을 말한다.
OpenTelemetry는 이러한 메트릭, 트레이스, 로그 수집을 위한 프레임워크 또는 표준이라고 볼 수 있다. 특정 언어나 프레임워크나 기술에 치우지지 않고 표준화된 프레임워크인 것이다.
예를 들어서, OpenTelemetry 진영의 기술 및 라이브러리를 이용해서 원하는 데이터를 애플리케이션으로 부터 뽑아내고, 이를 원하는 데이터 저장 도구로 전달할 수 있는 것이다. 이러한 데이터를 저장하고 분석하는 도구 중 가장 대표적인 것이 바로 프로메테우스이다.
Prometheus는 자체적인 에이전트 또는 라이브러리를 지원하는데, 이 것이 애플리케이션 메트릭을 주기적으로 스크랩핑하여 데이터 저장 도구(프로메테우스 서버)로 전달하는 방식을 Prometheus 계측이라한다.
OpenTelemetry 계측도 결과적으로는 데이터 저장 도구(Ex. 프로메테우스 서버)에 메트릭을 전달하는 것이지만, 에이전트가 메트릭을 주기적으로 스크랩핑하는 것이 아니라 OpenTelemetry 에이전트가 OTel Collector(OpenTelemetry Collector)에게 메트릭을 Export하고, OTel Collector가 이를 모아서, 주기적으로 데이터 저장 도구(Ex. 프로메테우스 서버)가 이해할 수 있는 방식으로 노출 및 전달하는 방식으로 동작한다.
오히려 한 단계가 추가된 것이라고 생각될 수 있지만, 이렇게 추가된 한 단계를 통해서 애플리케이션에서는 메트릭, 트레이스, 로그를 OTel Collector에게 잘 전달만 하면, 다양한 데이터 저장소(프로메테우스, 데이터독, New Relic 등등)에 맞게 알아서 전달을 해주기에 애플리케이션 입장에서는 유연함과 확장성과 일관성을 확보할 수 있게 된다.
implementation 'io.micrometer:micrometer-registry-otlp'
기본적인 Spring boot 관련 설정들은 돼있다는 전제하에 위 라이브러리만 추가해주면 된다.
management:
otlp:
metrics:
export:
url: http://localhost:4318/v1/metrics
step: 30s
base-time-unit: seconds
애플리케이션에는 위와 같은 설정을 추가해준다.
step은 OTel Collector에게 메트릭을 전달하는 주기인데, 15초, 30초, 60초가 가장 일반적인 것 같다.
메트릭을 촘촘히 보고 싶다면 15초로 하고, 추세만 봐도 된다면 60초로 설정하고, 그 중간 정도를 보고 싶다면 30초로 설정하면 된다.
base-time-unit은 기본 값은 밀리 세컨드인데, 이 것은 각자가 보기 편한 단위를 설정해주면 된다.
이렇게만 하면 설정은 완료된다.
이제 로컬에서 프로메테우스 서버와 그라파나를 구동해서 메트릭을 눈으로 확인해보도록 하겠다.
services:
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--web.enable-lifecycle'
otel-collector:
image: public.ecr.aws/aws-observability/aws-otel-collector:latest
ports:
- "4317:4317" # gRPC
- "4318:4318" # HTTP
- "8889:8889" # Prometheus 스크레핑용 포트
volumes:
- ./otel-config.yaml:/etc/otel-config.yaml
command: [ "--config", "/etc/otel-config.yaml" ]
environment:
- AWS_REGION=ap-northeast-2
프로메테우스 서버, OTel Collector을 띄울 수 있도록 docker compose를 작성한다.
OTel Collector 중에서 gRPC 통신은 사용하지 않을 거여서 4317포트는 열어주지 않아도 되지만, HTTP 통신으로 데이터를 전달하는 방법 뿐만 아니라 gRPC 통신으로도 전달이 가능하다는 것만 알면 될 것 같다.
receivers:
otlp:
protocols:
http:
endpoint: "0.0.0.0:4318"
grpc:
endpoint: "0.0.0.0:4317"
processors:
batch:
exporters:
debug:
verbosity: detailed
prometheus:
endpoint: "0.0.0.0:8889"
service:
pipelines:
metrics:
receivers: [otlp]
processors: [batch]
exporters: [debug, prometheus]
docker compose 파일에서도 알 수 있듯이 OTel Collector의 동작에 대한 정의를 해줘야하는데, 해당 설정은 위와 같이 작성해주면 된다.
global:
scrape_interval: 10s
scrape_configs:
- job_name: 'otel'
scrape_interval: 5s
static_configs:
- targets: [ 'otel-collector:8889' ]
OTel Collector에서 노출되는 메트릭 수집 엔드포인트를 프로메테우스에게 알려줘서 스크랩핑할 수 있도록 해준다.
scrape_interval을 5초로 설정하였지만, 위에서 OTel Collector에 메트릭을 전달하는 주기를 30초로 하였기 때문에 메트릭은 30초에 한 번씩 수집되는 것과 마찬가지가 된다.

간략히 데이터의 흐름을 본다면, 위와 같다.
로컬에서 구동하는 방식은 OTel Collector에서 프로메테우스 엔드포인트를 노출하고 프로메테우스가 이를 스크랩핑(Pull)하는 방식인데, 아래에서 ECS로 메트릭 수집 환경을 구성할 때에는 OTel Collector가 프로메테우스에 직접 데이터를 전송(Remote write)하는 방식으로 설정해보도록 하겠다.
자, 이제 정상적으로 설정되었는지도 확인해보자.
localhost:9090로 접속하면, 프로메테우스 서버에 접속할 수 있고 PromQL로 아무 메트릭이나 조회해보면 정상적으로 조회되는 것을 확인할 수 있다.
ECS에 메트릭 수집 환경을 구축하기 위해서는 OTel Collector를 사이드카로 구성해주면 되는데, 직접 구성해줄 필요 없이 딸-깍으로 설정이 가능하다. 바로 알아보자!

테스크 정의 가장 하단에 보면, '모니터링'이라는 섹션이 존재하는데 여기에서 메트릭과 트레이스 관련 설정을 활성화해줄 수 있다.
지금 할 것은 메트릭 수집 환경을 구성하는 것이기 때문에 '지표 수집 사용'을 체크해주고, 'OpenTelemetry 계측'으로 수집 방식을 선택해준다.
그리고, 이전 섹션에서 말했듯이 이번에는 메트릭 Pull 방식이 아니라 Remote write 방식을 사용할 것이므로, 프로메테우스 서버의 쓰기 엔드포인트를 설정해준다.
이렇게 하면, OTel Collector 사이드카가 뚝딱 만들어진다.
새롭게 만든 Task definition을 구동하면 이렇게 사이드카가 생성된 것을 확인할 수 있다.
또, 로그도 정상적으로 찍히는 것도 볼 수 있다.
로컬에서 구동한 것과 전반적인 흐름은 동일하다. 다만, 다른 점은 OTel Collector가 프로메테우스에 직접 데이터를 전달하는 것이다.
이렇게 하면, 애플리케이션 입장에서는 메트릭 수집을 위해서 인바운드 트래픽을 허용해주지 않아도 돼서, 보안적으로 훨씬 안전하다는 장점 또한 가질 수 있다. 👍
프로메테우스를 직접 설정해서 구동중이라면, 프로메테우스 서버에 직접 접속해서 이런 저런 쿼리를 실행해서 정상 동작하는 것을 확인할 수 있고, AMP(Amazon managed Prometheus)를 사용하고 있다면 프로메테우스 서버에 직접 접속이 되지 않으므로 그라파나같은 별도의 도구로 정상적으로 메트릭이 수집되는 것을 확인할 수 있다.