containerd 自 v1.6.0 起支持 OpenTelemetry 跟踪。
跟踪目前只针对 gRPC 调用。
从 containerd 守护进程发送跟踪结果
通过配置 io.containerd.tracing.processor.v1.otlp
插件。
containerd 守护进程可以将跟踪信息发送到指定的 OpenTelemetry 端点。
version = 2
[plugins."io.containerd.tracing.processor.v1.otlp"]
endpoint = "http://localhost:4318"
支持以下选项。
endpoint
接收 OpenTelemetry Protocol 的服务器地址。protocol
: OpenTelemetry 支持多种协议。
默认值为 “http/protobuf”。也支持 “grpc”。insecure
: 当协议为 "grpc "时禁用传输安全。默认值为 false。 "http/protobuf "始终使用端点提供的模式,该设置的值将被忽略。
此设置的值将被忽略。
func clientWithTrace() error {
exp, err := otlptracehttp.New(ctx,
otlptracehttp.WithEndpoint("localhost:4318"),
otlptracehttp.WithInsecure(),
)
if err != nil {
return err
}
res, err := resource.New(ctx, resource.WithAttributes(
semconv.ServiceNameKey.String("CLIENT NAME"),
))
if err != nil {
return err
}
provider := trace.NewTracerProvider(
trace.WithSampler(trace.AlwaysSample()),
trace.WithSpanProcessor(trace.NewSimpleSpanProcessor(exp)),
trace.WithResource(res),
)
otel.SetTracerProvider(provider)
otel.SetTextMapPropagator(propagation.TraceContext{})
...
dialOpts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()),
grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()),
}
client, ctx, cancel, err := commands.NewClient(context, containerd.WithDialOpts(dialOpts))
if err != nil {
return err
}
defer cancel()
ctx, span := tracing.StartSpan(ctx, "OPERATION NAME")
defer span.End()
...
}
跟踪上的采样率和服务名称可以通过
io.containerd.internal.v1.tracing
插件配置。
version = 2
[plugins."io.containerd.internal.v1.tracing"]
sampling_ratio = 1.0
service_name = "containerd"
从 containerd 客户端发送跟踪信息
通过配置其底层 gRPC 客户端,containerd 的 Go 客户端可以向 OpenTelemetry 端点发送
跟踪到 OpenTelemetry 端点。
请注意,Go客户端的方法和 gRPC 调用不是 1:1。单个方法调用会发出多个 gRPC 调用。
func clientWithTrace() error {
exp, err := otlptracehttp.New(ctx,
otlptracehttp.WithEndpoint("localhost:4318"),
otlptracehttp.WithInsecure(),
)
if err != nil {
return err
}
res, err := resource.New(ctx, resource.WithAttributes(
semconv.ServiceNameKey.String("CLIENT NAME"),
))
if err != nil {
return err
}
provider := trace.NewTracerProvider(
trace.WithSampler(trace.AlwaysSample()),
trace.WithSpanProcessor(trace.NewSimpleSpanProcessor(exp)),
trace.WithResource(res),
)
otel.SetTracerProvider(provider)
otel.SetTextMapPropagator(propagation.TraceContext{})
...
dialOpts := []grpc.DialOption{
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()),
grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()),
}
client, ctx, cancel, err := commands.NewClient(context, containerd.WithDialOpts(dialOpts))
if err != nil {
return err
}
defer cancel()
ctx, span := tracing.StartSpan(ctx, "OPERATION NAME")
defer span.End()
...
}