OpenTelemetry로 JavaScript 앱 계측하기

OpenTelemetry로 JavaScript 앱 계측하기

Docker 환경에서 OpenTelemetry를 사용해 JavaScript 어플리케이션을 계측하는 방법을 배워볼게요.

출처: 문서

본문

OpenTelemetry(OTel)는 어플리케이션에서 메트릭, 로그, 트레이스 같은 텔레메트리 데이터를 수집하기 위한 API, SDK, 도구 세트를 제공하는 오픈소스 관측성 프레임워크예요. OpenTelemetry로 개발자는 서비스가 프로덕션 또는 로컬 개발 중에 어떻게 성능을 내는지에 대한 귀중한 인사이트를 얻을 수 있어요.

OpenTelemetry의 핵심 구성 요소는 OTLP(OpenTelemetry Protocol)예요. 이는 텔레메트리 데이터를 효율적이고 안정적으로 전송하도록 설계된 범용의 벤더 중립 프로토콜이에요. OTLP는 HTTP 또는 gRPC를 통해 여러 데이터 타입(트레이스, 메트릭, 로그)을 지원하며, 계측된 어플리케이션, OpenTelemetry Collector, Jaeger나 Prometheus 같은 백엔드 사이의 통신을 위한 기본이자 권장 프로토콜이에요.

이 가이드는 간단한 Node.js 어플리케이션을 OpenTelemetry로 계측하고 Docker를 사용해 앱과 컬렉터를 함께 실행하는 과정을 안내해요. 이 설정은 Prometheus, Jaeger, Grafana 같은 외부 관측성 플랫폼과 통합하기 전에 관측성을 로컬 개발·테스트하는 데 이상적이에요.

이 가이드에서 배울 내용:

  • Node.js 앱에서 OpenTelemetry 설정하는 방법
  • Docker에서 OpenTelemetry Collector 실행하는 방법
  • Jaeger로 트레이스 시각화하는 방법
  • Docker Compose로 전체 관측성 스택 관리하는 방법

Docker에서 OpenTelemetry 사용하기

OpenTelemetry 공식 Docker 이미지 는 Dex 인스턴스를 배포·관리하는 편리한 방법을 제공해요. OpenTelemetry는 amd64, armv7, arm64 등 다양한 CPU 아키텍처를 지원해 여러 기기와 플랫폼과의 호환성을 보장해요. Jaeger Docker 이미지 도 마찬가지예요.

사전 요구사항

  • Docker Compose : 멀티 컨테이너 Docker 어플리케이션 관리에 권장돼요.
  • Node.js와 Docker에 대한 기본 지식.

프로젝트 구조

프로젝트 디렉터리를 만들어주세요:

mkdir otel-js-app
cd otel-js-app
otel-js-app/
├── docker-compose.yaml
├── collector-config.yaml
├── app/
│   ├── package.json
│   ├── app.js
│   └── tracer.js

간단한 Node.js 앱 만들기

기본 Node.js 앱을 초기화해주세요:

mkdir app && cd app
npm init -y
npm install express @opentelemetry/api @opentelemetry/sdk-node \
  @opentelemetry/auto-instrumentations-node \
  @opentelemetry/exporter-trace-otlp-http

이제 어플리케이션 로직을 추가해주세요:

// app/app.js
const express = require('express');
require('./tracer');
// Initialize OpenTelemetry

const app = express();
app.get('/', (req, res) => {
  res.send('Hello from OpenTelemetry demo app!');
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`App listening at http://localhost:${PORT}`);
});

OpenTelemetry 트레이싱 구성

트레이서 구성 파일을 만들어주세요:

// app/tracer.js
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'http://collector:4318/v1/traces',
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();

OpenTelemetry Collector 구성

루트에 collector-config.yaml 파일을 만들어주세요:

# collector-config.yaml
receivers:
  otlp:
    protocols:
      http:

exporters:
  logging:
    loglevel: debug
  jaeger:
    endpoint: jaeger:14250
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [logging, jaeger]

Docker Compose 구성 추가

docker-compose.yaml 파일을 만들어주세요:

services:
  app:
    build: ./app
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
    depends_on:
      - collector
  collector:
    image: otel/opentelemetry-collector:latest
    volumes:
      - ./collector-config.yaml:/etc/otelcol/config.yaml
    command: ["--config=/etc/otelcol/config.yaml"]
    ports:
      - "4318:4318" # OTLP
  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686" # UI
      - "14250:14250" # Collector gRPC

이제 app/ 폴더 안에 Dockerfile 을 추가해주세요:

# app/Dockerfile
FROM node:18
WORKDIR /usr/src/app
COPY . .
RUN npm install
CMD ["node", "app.js"]

스택 시작하기

Docker Compose로 모든 서비스를 시작해주세요:

docker compose up --build

서비스가 실행되면:

Jaeger에서 트레이스 검증

앱의 루트 엔드포인트를 방문한 후 Jaeger UI를 열고 서비스를 검색(명시적으로 이름을 붙이지 않았다면 기본값은 보통 unknown_service)하고 트레이스를 확인해주세요.

HTTP 요청, 미들웨어, 자동 계측된 라이브러리에 대한 스팬(span)이 보여야 해요.

결론

이제 Docker Compose를 사용하는 완전히 작동하는 OpenTelemetry 설정을 갖췄어요. 기본 JavaScript 앱을 계측해 트레이스를 내보내고 Jaeger로 시각화했다요. 이 아키텍처는 Prometheus, Grafana, 또는 클라우드 네이티브 익스포터를 사용하는 더 복잡한 어플리케이션과 관측성 파이프라인으로 확장 가능해요.

커스텀 스팬 생성, 메트릭, 로그 같은 고급 주제는 OpenTelemetry JavaScript 문서를 참고하세요.

더 알아보기 (Learn more)

  • OpenTelemetry 개요
  • Jaeger
  • Docker Compose