Skip to content

fix: listen on the node IP only for node-exporter on Azure Linux 3 - #9961

Open
chmill-zz wants to merge 2 commits into
mainfrom
exporterNodeIP
Open

chmill-zz wants to merge 2 commits into
mainfrom
exporterNodeIP

Conversation

@chmill-zz

@chmill-zz chmill-zz commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

Makes node-exporter listen only on the node IP on Azure Linux 3, as it already does on Ubuntu.

node-exporter-startup.sh chose the listen address with hostname -I | awk '{print $1}'. On Azure Linux 3, hostname comes from net-tools, which does not support -I, so NODE_IP was empty and the exporter started with --web.listen-address=:19100. That means it listened on every address. The AKS VM extension's copy of the script has the same bug, so extension-managed Azure Linux 3 nodes are affected too.

Listening on every address exposes the unauthenticated endpoint (TLS is off by default) beyond the node IP that scrapers use:

  • the node's IPv6 address on dual-stack clusters;
  • secondary NIC addresses, which can be in other subnets or VNets;
  • loopback and any bridge addresses.

Change

  • getNodeExporterListenIP returns the IPv4 address kubelet registers as the Node InternalIP: the IPv4 entry of --node-ip in /etc/default/kubelet. CSE sets that flag from IMDS, and it may list IPv4 and IPv6 in either order. Only KUBELET_FLAGS tokens are read, so a node label containing --node-ip= cannot match, and unspecified or loopback addresses (0.0.0.0, 127.*) are never used.
  • If --node-ip is absent (it is set only for Kubernetes ≥ 1.29, and only when IMDS succeeds), the function falls back to the primary NIC's source address for the WireServer route (ip -4 route get 168.63.129.16). That is the address cloud-node-manager assigns as InternalIP.
  • If neither is available, startup exits non-zero instead of listening on every address. systemd restarts the service (Restart=on-failure, RestartSec=10).
  • This replaces both the hostname -I path and the Flatcar eth0 path. Ubuntu's selected address is unchanged.

Consumers checked

  • Managed Prometheus (ama-metrics): scrapes NODE_IP:19100, where NODE_IP is status.hostIP, the node's IPv4 InternalIP.
  • AKS control-plane Prometheus: uses the API server node proxy (/api/v1/nodes/<node>:19100/proxy/metrics), which connects to the node InternalIP.
  • NPD node-exporter health check (check_node_exporter.sh): reads the actual listen address and probes it. It already handles both wildcard and specific addresses.
  • AgentBaker E2E: scrapes PrivateIP:19100.

Tests

  • ShellSpec:
    • --node-ip IPv4;
    • dual-stack --node-ip in either order;
    • IPv6-only --node-ip, a missing flag, or a missing file → route fallback;
    • nothing found → failure;
    • startup listens on the node IP, or exits without starting the exporter when no address is found.
  • E2E: ValidateNodeExporter now asserts that the only :19100 listener is <node IP>:19100. VHDs built before this change (used by standalone PR E2E) skip the check, because the startup script is VHD-delivered.

Validation

Dual-stack Azure CNI overlay cluster on the current production images, AKSAzureLinux-V3gen2-202610.23.0 and AKSUbuntu-2404gen2containerd-202610.23.0:

Azure Linux 3 before Azure Linux 3 with this change Ubuntu 24.04 (before and after)
--web.listen-address :19100 10.224.0.4:19100 10.224.0.5:19100
Host listeners *:19100 10.224.0.4:19100 10.224.0.5:19100
Answers on 127.0.0.1 / ::1 yes / yes no / no no / no
Answers on node IPv6 yes no no
Pod → node IPv4 :19100 yes yes yes
Pod → node IPv6 :19100 yes no no
API server node proxy ok ok ok
Managed Prometheus node target (http://<node IP>:19100/metrics) — up up
NPD check_node_exporter.sh — healthy healthy
  • After an Azure Linux 3 reboot, the exporter started once (no restarts) on 10.224.0.4:19100. The route fallback also returned 10.224.0.4 on the node.
  • Local: ShellSpec (node-exporter-startup_spec.sh plus spec/vhdbuilder, 618 examples), shellcheck, e2e go vet.
  • PR-gate pipeline on this branch (build 188667014, first commit): all VHDs built and all 122 E2E scenarios passed. The new listener check ran on 92 scenarios (19 Azure Linux 3, including Kata, and 72 Ubuntu). Every one reported exactly <node IP>:19100, including the SecondaryNIC and SecondaryNIC_DualStack scenarios. The review fixes only change --node-ip parsing and are covered by ShellSpec and a re-check on the dual-stack Azure Linux 3 node.

Follow-up

The AKS VM extension's node-exporter-startup.sh has the same hostname -I logic for extension-managed nodes (nodes without skip_vhd_node_exporter) and needs the matching fix.

Which issue(s) this PR fixes:

N/A

The startup script selected the listen address with `hostname -I`, which
the net-tools hostname on Azure Linux 3 does not support. NODE_IP was empty,
so node-exporter listened on every address, including loopback, the node's
IPv6 address on dual-stack clusters and any secondary NIC.

Use the IPv4 address from kubelet's --node-ip (the Node InternalIP that
scrapers use), falling back to the primary NIC's source address. Fail
instead of listening on all interfaces when neither is available, and
assert the listener in E2E.
Copilot AI balanced review requested due to automatic review settings October 30, 2026 21:59
@chmill-zz
chmill-zz requested review from a team as code owners October 30, 2026 21:59
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Windows Unit Test Results

  3 files   18 suites   1m 6s ⏱️
666 tests 666 ✅ 0 💤 0 ❌
689 runs  689 ✅ 0 💤 0 ❌

Results for commit 76c2f34.

♻️ This comment has been updated with latest results.

Copilot AI left a comment

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.

🟡 Changes recommended

The startup script can expose the unauthenticated exporter on all IPv4 interfaces when the node IP is unspecified, and can select an unrelated address from a node label, making metrics unavailable.

2 open issues
What changed in this PR

This PR updates AgentBaker’s VHD-delivered node-exporter startup script to bind to the node’s IPv4 address, addressing unintended all-interface listening on Azure Linux 3.

Changes:

  • Selects IPv4 from kubelet’s --node-ip, with a primary-NIC route fallback.
  • Stops startup when address discovery fails.
  • Adds ShellSpec coverage and an E2E listener check that skips older startup scripts.
File Description
spec/​parts/​linux/​cloud-init/​artifacts/​node-exporter-startup_spec.sh Tests address selection, fallback, and startup failure.
parts/​linux/​cloud-init/​artifacts/​node-exporter/​node-exporter-startup.sh Replaces hostname-based address discovery with kubelet and route lookup.
e2e/​scenario/​validators.go Checks that port 19100 listens only on the node IP.

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 30, 2026 23:13
@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Health
test 0% ❌
windows 27% ❌
staging_cse_windows Package 1 68% ➖
debug 0% ❌
provisioningscripts 2% ❌
parts_windows Package 1 73% ➖
Summary 39% (1819 / 7006) ❌

@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Health
shellspec spec 29% ❌
Summary 29% (4805 / 16501) ❌

Copilot AI left a comment

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.

🔵 Needs a closer look

The VHD-only fix leaves existing VHDs and extension-managed nodes exposed, requiring human coordination for rollout and a separate extension fix.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@github-actions

Copy link
Copy Markdown
Contributor

Code Coverage

Package Line Rate Health
github.com/Azure/agentbaker/aks-node-controller 73% ➖
github.com/Azure/agentbaker/aks-node-controller/common 100% ✔
github.com/Azure/agentbaker/aks-node-controller/helpers 68% ➖
github.com/Azure/agentbaker/aks-node-controller/parser 88% ✔
github.com/Azure/agentbaker/aks-node-controller/pkg/gpu 100% ✔
github.com/Azure/agentbaker/aks-node-controller/pkg/nodeconfigutils 89% ✔
github.com/Azure/agentbaker/aks-node-controller/utils 0% ❌
github.com/Azure/agentbaker/apiserver 24% ❌
github.com/Azure/agentbaker/cmd 0% ❌
github.com/Azure/agentbaker/cmd/starter 0% ❌
github.com/Azure/agentbaker/fuzz/api 0% ❌
github.com/Azure/agentbaker/hotfix/render-nodecustomdata 35% ❌
github.com/Azure/agentbaker/pkg/agent 78% ➖
github.com/Azure/agentbaker/pkg/agent/datamodel 77% ➖
github.com/Azure/agentbaker/pkg/agent/toggles 0% ❌
github.com/Azure/agentbaker/pkg/vhdbuilder/datamodel 87% ✔
Summary 75% (6059 / 8026) ➖

This branch has not been deployed

No deployments
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.

2 participants