Giriş
Modern mikroservis mimarilerinde bir isteğin sistem içinde nasıl yol aldığını anlamak, performans sorunlarını çözmek ve kök neden analizi yapmak için dağıtık izleme artık bir zorunluluk. OpenTelemetry (OTel), dil bağımsız açık standartları ve zengin SDK’ları ile Node.js uygulamalarınızda izleme (tracing) kurulumunu kolaylaştırır. Bu yazıda, Docker + OpenTelemetry Collector + Jaeger kullanarak Node.js tabanlı bir serviste uçtan uca izlemeyi adım adım kuracağız. Amaç, üretime yakın bir geliştirme deneyimi sağlamak, gecikmeleri ölçmek ve bağımlılıkları görünür kılmaktır.
Mimari ve Bileşenler
Kuracağımız basit topolojide üç temel bileşen bulunuyor: 1) Otomatik enstrümantasyonla iz verisi üreten Node.js servisi, 2) OTLP üzerinden iz kabul edip yöneten OpenTelemetry Collector, 3) Sorgulama ve görselleştirme için Jaeger. Collector, gelecekte Grafana Tempo, Honeycomb veya Zipkin gibi hedeflere geçişi kolaylaştıran bir ara katman görevi görür.
Node.js Projesini Hazırlama
Yeni bir proje başlatın ve gerekli bağımlılıkları kurun. Örnek bir Express API üzerinden gideceğiz, fakat otomatik enstrümantasyon HTTP, gRPC, MySQL, Redis gibi birçok paketi destekler.
# Projeyi başlat
npm init -y
# Express ve OpenTelemetry paketleri
npm i express
npm i @opentelemetry/sdk-node @opentelemetry/api @opentelemetry/resources \
@opentelemetry/semantic-conventions @opentelemetry/auto-instrumentations-node \
@opentelemetry/exporter-otlp-grpc
Ardından uygulama girişinde OpenTelemetry’yi başlatacak bir dosya oluşturun. Bu dosya, servis adı ve ortam gibi meta bilgileri de ekler.
// tracing.js
'use strict';
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-otlp-grpc');
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'node-api',
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV || 'dev',
}),
traceExporter: new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://otel-collector:4317'
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start()
.then(() => console.log('OpenTelemetry başlatıldı'))
.catch((err) => console.error('OTel hatası:', err));
process.on('SIGTERM', () => {
sdk.shutdown().finally(() => process.exit(0));
});
Basit bir Express sunucusu ekleyelim. tracing.js, uygulamadan önce yüklenmelidir ki tüm modüller doğru enstrümante edilsin.
// index.js
'use strict';
require('./tracing'); // OTel ön yükleme
const express = require('express');
const app = express();
app.get('/health', (req, res) => {
res.json({ ok: true, ts: Date.now() });
});
app.get('/slow', async (req, res) => {
await new Promise(r => setTimeout(r, 300)); // yapay gecikme
res.send('yavaş yanıt');
});
app.listen(3000, () => console.log('API 3000 portunda'));
OpenTelemetry Collector ve Jaeger ile Docker Compose
Collector, uygulamadan gelen OTLP verilerini alıp Jaeger’a iletecek. Aşağıda temel bir docker-compose yapısı ve Collector konfigürasyonu bulunuyor.
# docker-compose.yml
version: '3.9'
services:
api:
build: .
command: node index.js
environment:
NODE_ENV: dev
OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4317
OTEL_TRACES_SAMPLER: parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG: '0.5'
ports:
- "3000:3000"
depends_on:
- otel-collector
otel-collector:
image: otel/opentelemetry-collector-contrib:0.103.0
command: ["--config=/etc/otelcol-config.yaml"]
volumes:
- ./otelcol-config.yaml:/etc/otelcol-config.yaml:ro
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP (opsiyonel)
depends_on:
- jaeger
jaeger:
image: jaegertracing/all-in-one:1.57
ports:
- "16686:16686" # Jaeger UI
Collector’ın konfigürasyon dosyası, OTLP alıcıyı etkinleştirir ve verileri Jaeger’a yollar. İleride Zipkin, Tempo veya başka hedeflere ek ihracatçılar tanımlayabilirsiniz.
# otelcol-config.yaml
receivers:
otlp:
protocols:
grpc:
http:
exporters:
jaeger:
endpoint: jaeger:14250
tls:
insecure: true
processors:
batch:
timeout: 1s
send_batch_size: 512
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [jaeger]
Çalıştırma ve Doğrulama
Proje köküne basit bir Dockerfile ekleyin. Node tabanlı minimal bir imaj, üretime giden yolda iyi bir başlangıçtır.
# Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
Artık ortamı ayağa kaldırabilirsiniz. Aşağıdaki komut, API, Collector ve Jaeger’ı birlikte çalıştırır.
docker compose up --build
Tarayıcıdan http://localhost:16686 adresine gidip Jaeger UI’ı açın. Service menüsünde “node-api” servis adını göreceksiniz. Ayrıntılı izler için bir iki istek atın:
curl http://localhost:3000/health
curl http://localhost:3000/slow
Jaeger üzerinden isteklerin gecikme dağılımını, span ağaçlarını, endpoint bazlı hataları ve bağımlılık grafini analiz ederek performans darboğazlarını hızla teşhis edebilirsiniz.
En İyi Uygulamalar ve İpuçları
Örnek konfigürasyonda örnekleme oranını yüzde 50 olarak ayarladık. Üretimde, trafik seviyesine göre oranı düşürmek ve belirli endpoint’lerde dinamik örnekleme uygulamak mantıklıdır. Ayrıca, Resource etiketlerine versiyon, bölge ve takım bilgisi eklemek arama ve filtrelemeyi kolaylaştırır. Kolektörde attributes veya transform işlemcileri ile PII verileri kırpma/anonimleştirme adımları ekleyebilirsiniz. Gecikmeleri daha iyi yorumlamak için kritik yerlerde manuel span eklemek (ör. yoğun CPU işlemi, harici API çağrıları) fayda sağlar.
Güvenlik açısından Collector ile uygulama arasındaki trafiği mTLS ile şifrelemek ve dış ağlara ihracatta TLS’i etkinleştirmek önemlidir. Gözlemlenebilirlik verisi de kritiktir; erişim kontrolü, saklama süresi ve maliyet optimizasyonu (ör. örnekleme, toplu gönderim ayarları) planlanmalıdır. CI/CD’de, tracer başlatma hatalarını görünür kılmak için sağlık kontrolleri ve basit duman testleri ekleyin.
Sonuç
OpenTelemetry, Node.js servisleriniz için satıcı bağımsız, geleceğe dönük bir izleme altyapısı kurmanızı sağlar. Docker ile izleme yığınını dakikalar içinde ayağa kaldırabilir, Collector aracılığıyla hedef sistemleri esnekçe değiştirebilir, Jaeger ile sorunları hızla teşhis edebilirsiniz. Bugünkü kurulum, üretime geçişte ihtiyaç duyacağınız dinamik örnekleme, ek işlemciler, metrik ve log toplama gibi yeteneklerin de temelini oluşturur. İlk adımı attınız; şimdi span’ları zenginleştirip gerçek kullanıcı senaryolarını görünür kılma zamanı.