feat(vm): ship node exporter + OpenTelemetry Collector on the CDE VM, inert until the bot enables it - #580
Open
venkatamutyala wants to merge 1 commit into
Open
feat(vm): ship node exporter + OpenTelemetry Collector on the CDE VM, inert until the bot enables it#580venkatamutyala wants to merge 1 commit into
venkatamutyala wants to merge 1 commit into
Conversation
… inert until the bot enables it Every VM built from this image now carries prometheus-node-exporter (Debian package, loopback only) and otelcol-contrib, which scrapes it, reads per-container stats from the Docker socket, and ships OTLP/HTTP to the GlueOps observability endpoint. The image ships it inert: otelcol-contrib.service is gated on ConditionPathExists=/etc/glueops/otel.env and takes both the endpoint and the VM's identity (OTEL_RESOURCE_ATTRIBUTES) from that file. The Slack bot writes it through cloud-init, the same way it writes cde_token and tunnel_endpoint; a VM without the file leaves the unit inactive, not failed. Nothing per-VM is baked in — the image is public, so it never could carry a secret anyway, and this keeps the endpoint a bot-side setting. vm/observability.sh is the Packer step. It downloads the pinned, checksum-verified .deb, installs the config and drop-in, and runs a smoke test in the build VM: both units active, node_* served, both receivers produced points, and the unit refuses to start without otel.env. hack/test-vm.sh and a paths-scoped workflow validate the config against the pinned collector on PRs, because the image build itself only runs post-release. Measured on a live host: ~22 MB RSS for node exporter, ~190 MB and well under 1% of a core for the collector with both receivers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013zxxz8592fPJaq2B81jsC2
Open
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Every CDE VM built from this image now carries
prometheus-node-exporter(Debian package, bound to127.0.0.1:9100) andotelcol-contrib(pinned, checksum-verified.deb), which scrapes it, reads per-container stats from the Docker socket (docker_stats), and ships everything as OTLP/HTTP to the GlueOps observability endpoint.The image ships it inert.
otelcol-contrib.serviceis gated onConditionPathExists=/etc/glueops/otel.envand takes both the endpoint and the VM's identity (OTEL_RESOURCE_ATTRIBUTES) from that file. Nothing per-VM is baked in — the image is public (qcow2 on S3 + GitHub releases), so it could never carry a secret, and this keeps the endpoint a bot-side setting. A VM without the file (anything created before the bot writes one, or a hand-made VM) leaves the unit inactive, not failed.Companion PR in
slackbot-developer-workspaceswrites/etc/glueops/otel.envthrough cloud-init, the same way it already writescde_tokenandtunnel_endpoint. Either PR can land first; neither can break an existing VM. The file's contract is in the new README section.Files
vm/observability.shdeveloper-setup.sh). Installs both, addsotelcol-contribto thedockergroup, then smoke-tests in the build VM: both units active,node_*served, both receivers produced points (via the collector's own:8888metrics), and the unit refuses to start withoutotel.env. Exporter is pointed at a closed local port during the test — nothing leaves the build VM.vm/otelcol/config.yamlprometheus+docker_stats→memory_limiter(256 MiB) →resourcedetection→resource(service.instance.id= hostname, soinstanceon node dashboards is the VM name) →otlphttpwith${env:OTEL_EXPORTER_OTLP_ENDPOINT}.vm/otelcol/glueops.confEnvironmentFile, ordering aftercloud-config.service/docker.service.vm/node-exporter/prometheus-node-exporter.defaultqemu.pkr.hclfileprovisioner uploadsvm/; new script in the provisioner list.hack/test-vm.sh,.github/workflows/vm-tests.yamlotelcol-contrib validateagainst the pinned version (CI downloads it). Exists because the image build only runs post-release.README.mdotel.envcontract.Cost (measured on a live host, both receivers, 30s interval)
node exporter ~22 MB RSS / ~0.2% of a core; collector ~190 MB RSS / ~0.2% of a core. ~2.6% of RAM on the smallest slot.
Verified
hack/test-vm.shwith the pinned 0.159.0 binary:ALL PASS(config validates; refuses to start without the endpoint var).shellcheck -S warningclean;packer validatepasses.Notes
otel-http-cde.observability.glueopshosted.com) is write-only, no auth, and not routed yet (prod Traefik default backend + wildcard cert). Until it is, VMs queue and drop, bounded bymemory_limiter.dockergroup membership forotelcol-contribis root-equivalent on the host — the one privilege this grants; same membershipdeveloper-setup.shgivesvscode.packer fmtwants to realign pre-existing lines in the HCL; left untouched.🤖 Generated with Claude Code
https://claude.ai/code/session_013zxxz8592fPJaq2B81jsC2