You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

容器化C# OpenTelemetry服务后/metrics端点外部访问无响应问题

问题:容器外部无法访问OpenTelemetry Prometheus指标接口,内部正常

按照Microsoft指标收集教程实现了C# OpenTelemetry指标功能,本地运行时通过curl localhost:9184/metrics可正常获取指标(如... hats_sold_Hats 12 ...)。但将应用容器化后,外部执行curl localhost:9184/metrics返回(52) Empty reply from server,而进入容器内部执行相同curl命令却能正常获取指标。

已排查内容

  • 确认Docker端口映射配置无误,具备Docker网络经验,排除端口问题;
  • 查看了PrometheusExporter、System.Net.HttpListener及MeterProviderSdk源码,未发现问题;
  • 确认端口未被占用,OpenTelemetry服务端口被占用时会静默不监听;
  • 尝试通过docker-compose部署,问题依旧;
  • 发现从容器访问宿主机的服务时需添加Host: localhost头,否则返回400,说明服务对请求头敏感;
  • 等待足够时间确保指标生成,排除无指标导致空响应的可能。

最小示例

项目文件

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net7.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="OpenTelemetry.Exporter.Prometheus" Version="1.3.0-rc.2" />
    </ItemGroup>
</Project>

Program.cs

using System;
using System.Diagnostics.Metrics;
using System.Threading;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.Metrics;
using System.Diagnostics.Tracing;

class Program
{
    static Meter s_meter = new Meter("HatCo.HatStore", "1.0.0");
    static Counter<int> s_hatsSold = s_meter.CreateCounter<int>(name: "hats-sold", 
                                                                unit: "Hats",
                                                                description: "The number of hats sold in our store");

    static void Main(string[] args)
    {
        using MeterProvider meterProvider = Sdk.CreateMeterProviderBuilder()
                .AddMeter("HatCo.HatStore")
                .AddPrometheusExporter(opt =>
                {
                    opt.StartHttpListener = true;
                    opt.HttpListenerPrefixes = new string[] { $"http://localhost:9184/" };
                    
                })
                .Build();

        Console.WriteLine("Press any key to exit");
        while (true)
        {
            // 模拟每秒卖出4顶帽子
            Thread.Sleep(1000);
            s_hatsSold.Add(4);
            Console.WriteLine("Sold hats");
        }
    }
}

Dockerfile

FROM mcr.microsoft.com/dotnet/sdk:7.0
WORKDIR /app
COPY . .
RUN dotnet build
CMD [ "dotnet", "run" ]

注:.dockerignore已包含bin、obj、.vs目录

问题原因及解决方法

原因

问题出在HttpListener的绑定前缀配置上:你设置了opt.HttpListenerPrefixes = new string[] { $"http://localhost:9184/" },这会让HttpListener仅监听目标地址为容器内部localhost的请求。

容器的网络空间是隔离的,外部通过端口映射访问容器时,请求的目标地址并非容器内的localhost(而是宿主机IP或localhost),HttpListener会拒绝处理这些请求,导致外部返回空响应;而容器内部访问时用的是容器自身的localhost,所以能正常获取指标。

解决方法

修改HttpListenerPrefixes为监听所有网络接口:

.AddPrometheusExporter(opt =>
{
    opt.StartHttpListener = true;
    // 使用*或0.0.0.0监听所有网络接口
    opt.HttpListenerPrefixes = new string[] { $"http://*:9184/" };
})

或者:

opt.HttpListenerPrefixes = new string[] { $"http://0.0.0.0:9184/" };

这样HttpListener会接受来自任何网络接口的请求,容器外部即可正常访问/metrics接口。

内容的提问来源于stack exchange,提问作者JBSnorro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:00:35