Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Expose OpenTelemetry Collector configuration #208

Open
denniszielke opened this issue May 3, 2022 · 10 comments
Open

Feature Request: Expose OpenTelemetry Collector configuration #208

denniszielke opened this issue May 3, 2022 · 10 comments
Labels
enhancement New feature or request

Comments

@denniszielke
Copy link

denniszielke commented May 3, 2022

Is your feature request related to a problem? Please describe.
I want to use my own observability solution and not azure monitor. To connect I need the ability to configure my own otel processors and exporters.

Describe the solution you'd like.
I would like the ability to configure receivers, processors, (extensions?), the sampling rate and exporters.

Describe alternatives you've considered.
The alternative would be to run my own otel collector as ACA service and manually change all other ACA apps to use them. This does not seem like a scalable good idea.

Additional context.

@denniszielke denniszielke added the enhancement New feature or request label May 3, 2022
@ghost ghost added the Needs: triage 🔍 Pending a first pass to read, tag, and assign label May 3, 2022
@kendallroden
Copy link
Contributor

Thanks for this. It is a consideration moving forward definitely

@kendallroden kendallroden removed the Needs: triage 🔍 Pending a first pass to read, tag, and assign label May 5, 2022
@JennyLawrance
Copy link

@denniszielke, have you considered OTEL as a side car option?

@denniszielke
Copy link
Author

denniszielke commented Jun 4, 2022

@JennyLawrance yes that is what we are doing today but on the long run this does not scale (we need to maintain the same config , we need to make sure every dev creates the right config for each microservice and this is not what a PaaS should enforce). Also the performance overhead is significant as long ACA is limited to 4GB per replica (app+sidecar)

@edeandrea
Copy link

edeandrea commented Aug 30, 2022

Adding onto this (& tagging @agoncal as well) - If I wanted to run an OTel collector instance as its own containerapp its currently very difficult to inject the configuration, since ContainerApps does not expose a ConfigMap that can be mounted as a volume.

For example, if I wanted to run the Otel collector on kubernetes, I could just deploy this:

apiVersion: v1
kind: ConfigMap
metadata:
  name: otel-collector-config
  labels:
    app: otel-collector
    role: monitoring
data:
  otel-collector-config.yml: |2
    receivers:
      otlp:
        protocols:
          grpc:

    exporters:
      jaeger:
        endpoint: jaeger:14250
        tls:
          insecure: true

    processors:
      batch:

    extensions:
      health_check:

    service:
      extensions:
        - health_check
      pipelines:
        traces:
          receivers:
            - otlp
          processors:
            - batch
          exporters:
            - jaeger
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: otel-collector
  labels:
    name: otel-collector
    app: otel-collector
    role: monitoring
    app.kubernetes.io/part-of: monitoring
spec:
  replicas: 1
  selector:
    matchLabels:
      name: otel-collector
  template:
    metadata:
      labels:
        name: otel-collector
        app: otel-collector
        role: monitoring
    spec:
      containers:
        - image: otel/opentelemetry-collector:0.53.0
          name: otel-collector
          args:
            - "--config=/conf/otel-collector-config.yml"
          ports:
            - name: health-check
              containerPort: 13133
            - name: otlp-receiver
              containerPort: 4317
          volumeMounts:
            - name: otel-collector-config
              mountPath: /conf
      volumes:
        - name: otel-collector-config
          configMap:
            name: otel-collector-config

I haven't yet found a good way to do this in Azure ContainerApps. I found https://docs.microsoft.com/en-us/azure/container-apps/storage-mounts?pivots=aca-cli#azure-files but that means I have to maintain a separate yaml file specific to azure containerapps, which contains most of the same fields as a kubernetes yaml. That doesn't seem like a scalable solution, especially if all my CI/CD automation uses the az cli.

@alhardy
Copy link

alhardy commented Dec 13, 2022

This approach works https://www.honeycomb.io/blog/opentelemetry-collector-azure-container-apps

@Depechie
Copy link

Depechie commented Dec 13, 2022

hey @alhardy I followed that guide, it works, but the effort to do it is huge and needs manual intervention ( downloading config and editing ).
So we would hope the team can better the experience.

I even needed to do 'more' and detailed it here https://blog.depechie.com/posts/2022-10-13-opentelemetry-on-azure-container-apps/

@edeandrea
Copy link

Thank you @alhardy ! That still seems way more complicated than it should!

@denniszielke
Copy link
Author

Agree.

@Depechie
Copy link

Depechie commented Dec 20, 2022

I found out that if you do not use the az cli but instead opt to deploy to azure using Bicep the volume mount does work! Meaning I can now deploy OpenTelemetry Collector fully automated from CI/CD without manually needing to download the config file after creation...

Example part of the Bicep for the container app ( almost the same as the kubernetes one from @edeandrea

resource containerAppOtel 'Microsoft.App/containerApps@2022-03-01' = {
  name: 'ca-${env}-${resourceLocationShort}-otel'
  location: resourceLocationLong
  properties: {
    managedEnvironmentId: environment.id
    configuration: {
      ingress: {
        external: true
        targetPort: 4318
      }
    }
    template: {
      containers: [
        {
          image: 'otel/opentelemetry-collector-contrib:latest'
          name: 'ca-${env}-${resourceLocationShort}-otel'
          args: [
            '--config=/etc/otel-config-test.yml'
          ]
          resources: {
            cpu: json('0.5')
            memory: '1.0Gi'
          }
          volumeMounts: [
            {
              mountPath: '/etc'
              volumeName: 'config'
            }
          ]
        }
      ]
      scale: {
        minReplicas: 1
        maxReplicas: 1
      }
      volumes: [
        {
          name: 'config'
          storageName: environment::azurefilestorage.name
          storageType: 'AzureFile'
        }
      ]
    }
  }
}

@dickiebowuk
Copy link

dickiebowuk commented Oct 16, 2023

I'm looking for some assistance. I started with the Honeycomb article to build a collector in an Azure Container App and it wasn't starting correctly until I found this post, pointing to the second article and added the args section to point to my mounted config file. The collector is running and listening for otlp http traffic on port 4318 with the ingress set to allow external traffic. However, I cannot get it to receive any data from my .Net Core 7 api. I can get it all working on my laptop with the otel collector contrib running in docker desktop set for http on port 4318.

Here is the config file for the container:

receivers:
  otlp:
    protocols:
      http:

exporters:
  otlphttp/withauth:
    auth:
      authenticator: oauth2client
    logs_endpoint: $CNAO_LOGS_ENDPOINT
    metrics_endpoint: $CNAO_METRICS_ENDPOINT
    traces_endpoint: $CNAO_TRACES_ENDPOINT

  logging:
    loglevel: debug

processors:
  batch:
    send_batch_size: 8192
    timeout: 10s
  attributes/collector_info:
    actions:
      - key: collector.hostname
        value: $HOSTNAME
        action: insert
      - key: azure.container_app.revision
        value: $CONTAINER_APP_REVISION
        action: insert
      - key: azure.container_app.name
        value: $CONTAINER_APP_NAME
        action: insert
      - key: source.blog
        value: "true"
        action: insert
  filter/healthcheck:
    spans:
      exclude:
        match_type: strict
        attributes:
          - Key: http.target
            Value: /health

extensions:
  oauth2client:
    client_id: $CNAO_CLIENT_ID
    client_secret: $CNAO_CLIENT_SECRET
    token_url: $CNAO_TOKEN_URL

service:
  extensions: [oauth2client]
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch,filter/healthcheck,attributes/collector_info]
      exporters: [logging, otlphttp/withauth]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp/withauth]
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp/withauth]
  telemetry:
    logs:
      level: "debug"

The log stream on the container shows that it has started successfully giving this output:

2023-10-16T10:41:15.15488  Connecting to the container 'collector'...

2023-10-16T10:41:15.17288  Successfully Connected to container: 'collector' [Revision: 'collector--1', Replica: 'collector--1']
2023-10-13T15:37:36.605516952Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:92	Processor is starting...	{"kind": "processor", "name": "batch", "pipeline": "logs"}
2023-10-13T15:37:36.605528072Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:96	Processor started.	{"kind": "processor", "name": "batch", "pipeline": "logs"}
2023-10-13T15:37:36.605566835Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:92	Processor is starting...	{"kind": "processor", "name": "attributes/collector_info", "pipeline": "traces"}
2023-10-13T15:37:36.605573347Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:96	Processor started.	{"kind": "processor", "name": "attributes/collector_info", "pipeline": "traces"}
2023-10-13T15:37:36.605622865Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:92	Processor is starting...	{"kind": "processor", "name": "filter/healthcheck", "pipeline": "traces"}
2023-10-13T15:37:36.605652090Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:96	Processor started.	{"kind": "processor", "name": "filter/healthcheck", "pipeline": "traces"}
2023-10-13T15:37:36.605657580Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:92	Processor is starting...	{"kind": "processor", "name": "batch", "pipeline": "traces"}
2023-10-13T15:37:36.605698870Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:96	Processor started.	{"kind": "processor", "name": "batch", "pipeline": "traces"}
2023-10-13T15:37:36.605707717Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:92	Processor is starting...	{"kind": "processor", "name": "batch", "pipeline": "metrics"}
2023-10-13T15:37:36.605711765Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:96	Processor started.	{"kind": "processor", "name": "batch", "pipeline": "metrics"}
2023-10-13T15:37:36.605715602Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:100	Starting receivers...
2023-10-13T15:37:36.605736781Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:104	Receiver is starting...	{"kind": "receiver", "name": "otlp", "pipeline": "metrics"}
2023-10-13T15:37:36.605758522Z 2023-10-13T15:37:36.605Z	warn	internal/warning.go:51	Using the 0.0.0.0 address exposes this server to every network interface, which may facilitate Denial of Service attacks	{"kind": "receiver", "name": "otlp", "pipeline": "metrics", "documentation": "https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/security-best-practices.md#safeguards-against-denial-of-service-attacks"}
2023-10-13T15:37:36.605821510Z 2023-10-13T15:37:36.605Z	info	otlpreceiver@v0.67.0/otlp.go:90	Starting HTTP server	{"kind": "receiver", "name": "otlp", "pipeline": "metrics", "endpoint": "0.0.0.0:4318"}
2023-10-13T15:37:36.605855915Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:108	Receiver started.	{"kind": "receiver", "name": "otlp", "pipeline": "metrics"}
2023-10-13T15:37:36.605861705Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:104	Receiver is starting...	{"kind": "receiver", "name": "otlp", "pipeline": "logs"}
2023-10-13T15:37:36.605888225Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:108	Receiver started.	{"kind": "receiver", "name": "otlp", "pipeline": "logs"}
2023-10-13T15:37:36.605897011Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:104	Receiver is starting...	{"kind": "receiver", "name": "otlp", "pipeline": "traces"}
2023-10-13T15:37:36.605920645Z 2023-10-13T15:37:36.605Z	info	service/pipelines.go:108	Receiver started.	{"kind": "receiver", "name": "otlp", "pipeline": "traces"}
2023-10-13T15:37:36.605927208Z 2023-10-13T15:37:36.605Z	info	service/service.go:105	Everything is ready. Begin running and processing data.

The code I am using for the otlp exporter in my .Net Core 7 project to hit the container app is as follows:

string endPoint = "https://collector.onazure.azurecontainerapps.io:4318/v1/traces";
                            Console.WriteLine($"AppD Endpoint: {endPoint}");
                            builder.AddOtlpExporter(options =>
                            {
                                AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

                                options.Protocol = OtlpExportProtocol.HttpProtobuf;
                                options.ExportProcessorType = ExportProcessorType.Batch;
                                options.Endpoint = new Uri(endPoint);
                            })
                            .AddConsoleExporter(options => options.Targets = ConsoleExporterOutputTargets.Console);

I have tried running the project locally on my laptop and also have the api in it's own container with an APIM in place to test the endpoints. I can see in the console logs that the Writeline is output when starting up the container and that telemetry is being sent to the Console through the Console Exporter. However, it is not being received by the collector.

EDIT: I sorted the issue. At present Azure Container Apps only open one port, so you cannot map multiple ports like you can with Docker. Port 80 and 443 are open by default and I thought 4318 had successfully been opened as it says it's available in the Container overview. I used Telnet to confirm which ports were open and found 4318 was not available, so I tried sending the data to port 443 and it worked. My new endpoint is:

https://collector.onazure.azurecontainerapps.io:433/v1/traces

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants