Skip to content

feat(amazon-cloudwatch-observability): ServiceMonitor/PodMonitor scraping via the Target Allocator - #376

Closed
Aakash-Dantre wants to merge 1 commit into
aws-observability:mainfrom
Aakash-Dantre:smpm/chart-smpm-scraping
Closed

Aakash-Dantre wants to merge 1 commit into
aws-observability:mainfrom
Aakash-Dantre:smpm/chart-smpm-scraping

Conversation

@Aakash-Dantre

@Aakash-Dantre Aakash-Dantre commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

ServiceMonitor/PodMonitor (monitoring.coreos.com/v1) scraping for OTEL Container Insights, through the Target Allocator's prometheusCR discovery, under a single switch: otelContainerInsights.prometheusScrape.

Supersedes #327, #329, #330, #331, #332 and #339. Those were successive revisions of one change: each later PR contained the earlier ones, and all targeted main while editing the same values.yaml and _helpers.tpl. This PR is #339's content rebased onto current main. #327 is included in full (its CRD-watch RBAC rule is identical here) without the unrelated file deletions in that branch.

What

  • Single switch otelContainerInsights.prometheusScrape.enabled turns on SM/PM scraping end to end: CRDs, Target Allocator, prometheusCR discovery, and RBAC.
  • Per-node allocation - prometheusScrape.allocationStrategy (default per-node). Targets are assigned to the agent on their node; node-less targets fall back to consistent hashing.
  • Bundled CRDs - prometheusScrape.crds.install: auto | always | never (default auto). The SM/PM CRDs are pinned to prometheus-operator v0.92.0 to match the operator's client.
    • Skipped if a copy not managed by this release already exists, so a prometheus-operator install is never overwritten.
    • Annotated helm.sh/resource-policy: keep, so helm uninstall does not delete every ServiceMonitor in the cluster.
  • Annotation routing - the clusterScraperAgent gets its own Target Allocator with scraperRole: cluster-scraper and a prometheusCR pipeline. Monitors annotated cloudwatch.aws.amazon.com/scraper: cluster-scraper go to it; the per-node agent keeps everything else.
  • RBAC - the TA ClusterRole/ClusterRoleBinding render once, since every TA shares target-allocator-service-acct. This fixes duplicate-named objects when two agents run a TA. The role adds get/list/watch on customresourcedefinitions, which the TA's CRD watch needs.
  • prometheusScrape.serviceMonitor.enabled / podMonitor.enabled limit discovery to one monitor type.
  • Units - both prometheusCR pipelines (per-node and cluster-scraper) apply the same unit normalization, so a monitor's units do not depend on which agent scrapes it.

Off by default until compatible images ship

This configures behaviour that exists only in aws/amazon-cloudwatch-agent-operator#414 and aws/amazon-cloudwatch-agent-operator#415 (CRD watch, per-node, scraper_role). With an operator or TA image that predates those PRs, the Target Allocator crashloops at startup instead of degrading. prometheusScrape.enabled therefore defaults to false, so enabling otelContainerInsights alone renders nothing new, and this PR can merge independently of the operator release. Planned sequence:

  1. fix(target-allocator): tolerate missing ServiceMonitor/PodMonitor CRDs aws/amazon-cloudwatch-agent-operator#414 (merged) and feat(target-allocator): per-node allocation and annotation-based SM/PM routing aws/amazon-cloudwatch-agent-operator#415 (open)
  2. operator and Target Allocator images released
  3. a follow-up chart change that bumps agent.prometheus.targetAllocator.image (currently cloudwatch-agent-target-allocator:1.0.0) and the operator image to those releases, and flips prometheusScrape.enabled to true

GitOps note

The skip-if-exists CRD guard uses lookup, which returns nothing under helm template. In render-then-apply flows (Argo CD, Flux) the bundled CRDs are therefore always emitted and can overwrite a separately managed copy. Those users should set crds.install: never. This is documented at the value.

Testing

helm template on this commit:

Values SM/PM CRDs scraperRole per-node
chart defaults (otelContainerInsights.enabled: false) 0 0 0
otelContainerInsights.enabled: true (scraping still off by default) 0 0 0
otelContainerInsights.enabled: true, prometheusScrape.enabled: true 2 2 2
main, otelContainerInsights.enabled: true 0 - -

New tests/prometheus_crds_matrix.sh: 36 passed, 0 failed.


PR Checklist

  • Commits are squashed into a logical, reviewable set (one commit for a single change) - one commit.
  • Commits and PR description comply with the contribution guidelines - no internal references in the commit message or this description.
  • make passes locally - on this commit: check_secrets, helm-lint, helm-flag-matrix (8/8), helm-yaml-injection (17/17) pass, and tests/prometheus_crds_matrix.sh passes 36/36.
  • All GitHub Actions checks on the PR are passing - not yet run on this PR; fork PR workflows need a maintainer to approve them. On the fork, the same commit passes Build (make all) and all 36 Minikube scenarios: run. The three EKS jobs failed at Configure AWS Credentials because the fork has no AWS role secret, so the EKS scenarios have not run.
  • Integration test evidence - 36/36 Minikube scenarios pass. EKS scenarios still need to run here once approved.
  • New or updated integration test coverage - test(otel/pernode): per-node, CRD-management and scraper-routing E2E suites aws/amazon-cloudwatch-agent-test#773: TestServiceMonitorPodMonitorCRDsBundled, TestPerNodeAllocation, TestScraperRoleWiring, TestAnnotationRoutingPartition and others.
  • New functionality has unit tests; behaviour changes have a reproducing test - tests/prometheus_crds_matrix.sh (36 render cases) covers the switch and its off default, CRD install modes and the validation message, monitor-type toggles, RBAC rendering, unit normalization on both prometheusCR pipelines, and the rejection of invalid combinations.
  • Config translation changes include updated golden files - N/A: chart-only, no translator changes.
  • Breaking or customer-visible changes are called out in the PR description - see "Off by default until compatible images ship". No change for existing users: SM/PM scraping and CRD bundling render only when prometheusScrape.enabled is set to true, which requires the operator and TA images from feat(otel-ci): add Ray metrics solution #414/feat(otel-ci): add Ray Serve request traces via the agent OTLP endpoint #415.

{{- define "amazon-cloudwatch-observability.prometheusCRDsEnabled" -}}
{{- $install := (dig "prometheusScrape" "crds" "install" "auto" .Values.otelContainerInsights) -}}
{{- /* Back-compat: honor the legacy top-level prometheusCRDs.install if set (deprecated). */ -}}
{{- if hasKey .Values "prometheusCRDs" -}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prometheusCRDs.install and otelContainerInsights.serviceMonitor/podMonitor (lines 409/417) are handled as "deprecated legacy" keys, but none of them exist on main, so there's nothing to stay compatible with. They look like leftovers from earlier revisions. The fail on line 31 also names prometheusCRDs.install: setting prometheusScrape.crds.install=bogus gives "prometheusCRDs.install must be one of...", which names a key that isn't documented in values.yaml. Suggest removing the legacy paths and pointing the error at otelContainerInsights.prometheusScrape.crds.install.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftovers from earlier revisions. Removed in 7c5e084, and the error now names otelContainerInsights.prometheusScrape.crds.install. Covered in prometheus_crds_matrix.sh.

# normalized and bounded the same way. Richer OTel enrichment (k8sattributes
# pod/node, workload, etc.) is intentionally deferred to the Phase 3 enrichment work.
processors:
- filter/cw_k8s_ci_v0_scrape_metadata

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pipeline leaves out transform/cw_k8s_ci_v0_set_unit, while the cluster-scraper's prometheuscr pipeline and every other Prometheus-scraped node pipeline include it. So the same monitor gets different units depending on whether it's annotated for the cluster-scraper. For example, *_seconds gets unit s when routed and no unit when scraped per-node. Intended?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not intended. Added in 7c5e084, with a render test that checks both prometheusCR pipelines.

*/ -}}
{{- if eq (include "amazon-cloudwatch-observability.prometheusCRDsEnabled" .) "true" }}
{{- $crdName := "servicemonitors.monitoring.coreos.com" }}
{{- $existing := lookup "apiextensions.k8s.io/v1" "CustomResourceDefinition" "" $crdName }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values.yaml note covers Argo/Flux, but how does this behave for the EKS add-on? If the add-on renders the chart without cluster access, lookup is always empty, so the bundled v0.92.0 CRDs would always be emitted. On clusters that already run kube-prometheus-stack, I'd expect either an add-on conflict on install or, with OVERWRITE, their CRDs replaced by ours. Is crds.install defaulting to auto safe for the add-on?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think auto is safe there yet. With scraping now off by default the add-on renders nothing new, so I'll confirm how the add-on renders before enabling it, and use never for that path if lookup is always empty. Do you know the right contact?

@AshuSrv

AshuSrv commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Since aws/amazon-cloudwatch-agent-operator#414 and aws/amazon-cloudwatch-agent-operator#415 aren't merged or released yet and agent.prometheus.targetAllocator.image is still 1.0.0, I'd prefer defaulting prometheusScrape.enabled to false in this PR and flipping it in the release that bumps the operator and TA images. That way this can merge independently, without leaving main in a state where enabling otelContainerInsights crashloops the TA. Happy to hear your thoughts on this.

@Aakash-Dantre
Aakash-Dantre force-pushed the smpm/chart-smpm-scraping branch from 8129142 to 7c5e084 Compare October 2, 2026 13:38
@Aakash-Dantre

Copy link
Copy Markdown
Collaborator Author

@AshuSrv Agreed, done in 7c5e084: prometheusScrape.enabled defaults to false, so this can merge independently. It flips to true with the operator and TA image bump.

Routes a ServiceMonitor/PodMonitor to the central cluster-scraper agent via
the cloudwatch.aws.amazon.com/scraper: cluster-scraper annotation on the monitor CR. The
cluster-scraper gets its own Target Allocator and prometheusCR with
scraperRole: cluster-scraper and consistent-hashing allocation; the per-node
agent keeps the default (empty) role and per-node allocation.

The Target Allocator ClusterRole/ClusterRoleBinding render once (all Target
Allocators share the target-allocator-service-acct service account), so a
second Target-Allocator-bearing agent no longer produces a duplicate-named
object. The bundled CRD's scraperRole field carries the
enum: [cluster-scraper] constraint generated by the operator.

Companion: aws/amazon-cloudwatch-agent-operator#399.

otelContainerInsights.prometheusScrape.enabled defaults to false until operator
and Target Allocator images with prometheusCR discovery, per-node allocation and
scraper_role are released; enabling it requires pinning those images together.
The per-node prometheusCR pipeline applies the same unit normalization as the
cluster-scraper one, so a monitor's units do not depend on which agent scrapes it.
@Aakash-Dantre

Copy link
Copy Markdown
Collaborator Author

Replaced by #406: same commit, opened from a branch in this repository so the EKS integration jobs can run. They need repository secrets, which fork PRs do not get. All earlier review comments here are answered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants