Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions charts/runtime-agent/templates/NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ runtime-agent is installed in namespace {{ .Release.Namespace }}, profile {{ .Va
The agent collects into its local spool and ships nothing: backend transport is
not built yet. Read charts/runtime-agent/values.yaml for what you can change,
and docs/security.md for what the agent can reach.

Every pod answers health probes on port {{ include "runtime-agent.healthPort" . }} at /livez and /readyz, in every
profile (ADR 0069). Readiness means the caches are synced, so the rollout below
returns when the agent is actually collecting rather than when it has started:

kubectl -n {{ .Release.Namespace }} rollout status deployment/{{ include "runtime-agent.controllerName" . }}
{{- if include "runtime-agent.nodeEnabled" . }}

CHECK ONE THING: the NetworkPolicy needs a CNI that enforces it.
Expand All @@ -23,6 +29,11 @@ by any pod in the cluster. What it does not change: what a caller may say. Every
request is authenticated by audience, signature against your cluster's JWKS, a
pinned ServiceAccount subject, and the node named in the caller's own token, and
none of those depend on your CNI (ADR 0040).

The policy has a second rule, on port {{ include "runtime-agent.healthPort" . }}, with no source restriction: the
probes come from your kubelet at the node's address, which no pod selector can
name. What it admits is two read-only paths that answer about the agent and name
nothing in your cluster (ADR 0069).
{{- end }}
{{- if or (eq .Values.profile "inventory") (eq .Values.profile "ebpf") }}

Expand Down
10 changes: 10 additions & 0 deletions charts/runtime-agent/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ runtime-agent-controller-{{ .Release.Namespace }}
system:serviceaccount:{{ .Release.Namespace }}:{{ include "runtime-agent.nodeName" . }}
{{- end -}}

{{/*
The port both roles answer probes on, and the one number the chart states about
it: the container port, the probes and the policy hole all read this (ADR 0069).
It is not a value — no other port the chart opens is one — and it is deliberately
not 8080: that port exists only where a DaemonSet does, and it carries the node
reports. The metrics endpoint of a later slice joins this listener as a path, so
the hole in the network policy stays one.
*/}}
{{- define "runtime-agent.healthPort" -}}9090{{- end -}}

{{/* The in-cluster base URL of the controller's receiver. */}}
{{- define "runtime-agent.controllerEndpoint" -}}
http://{{ include "runtime-agent.controllerName" . }}.{{ .Release.Namespace }}.svc:8080
Expand Down
4 changes: 4 additions & 0 deletions charts/runtime-agent/templates/controller-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ data:
{{- if .Values.spool.maxAgeHours }}
maxAgeHours: {{ .Values.spool.maxAgeHours }}
{{- end }}
health:
# The port the probes ask on. Rendered in every profile: the two questions
# a kubelet asks are not a feature of one (ADR 0069).
listenAddress: ":{{ include "runtime-agent.healthPort" . }}"
nodeIntake:
{{- if include "runtime-agent.nodeEnabled" . }}
enabled: true
Expand Down
35 changes: 33 additions & 2 deletions charts/runtime-agent/templates/controller-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,42 @@ spec:
args:
- -config
- /etc/runtime-agent/config.yaml
{{- if include "runtime-agent.nodeEnabled" . }}
ports:
# Answered in every profile, on a port of its own: probes must not
# depend on a receiver that half the profiles do not install
# (ADR 0069).
- name: health
containerPort: {{ include "runtime-agent.healthPort" . }}
{{- if include "runtime-agent.nodeEnabled" . }}
- name: node-intake
containerPort: 8080
{{- end }}
{{- end }}
# The startup budget is deliberately above the five minutes a gating
# cache may fail before the agent stops itself (ADR 0035): a refused
# LIST should produce the agent's own diagnostic exit, not an
# anonymous probe restart.
startupProbe:
httpGet:
path: /readyz
port: {{ include "runtime-agent.healthPort" . }}
periodSeconds: 5
failureThreshold: 120
# Liveness asks the process about itself and nothing else: an API
# server outage must not restart the agent (ADR 0069 §2).
livenessProbe:
httpGet:
path: /livez
port: {{ include "runtime-agent.healthPort" . }}
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
httpGet:
path: /readyz
port: {{ include "runtime-agent.healthPort" . }}
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
{{- if ((.Values.controller.resources).limits).memory }}
env:
# The limit the Go runtime does not read for itself; the agent runs
Expand Down
15 changes: 11 additions & 4 deletions charts/runtime-agent/templates/controller-networkpolicy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,9 @@ spec:
policyTypes:
- Ingress
ingress:
# One rule, and no second: naming a single source is what makes everything
# else denied. An empty `ingress:` would deny all, and an absent one would
# allow all — this is the middle case and it is the one that has to be
# written exactly.
# Two rules, and no third. An empty `ingress:` would deny all and an absent
# one would allow all; this is the middle case, and each rule has to be
# written exactly. The receiver names its source and nothing else reaches it.
- from:
- podSelector:
matchLabels:
Expand All @@ -63,4 +62,12 @@ spec:
# number that has to stay in step with the Deployment.
- protocol: TCP
port: 8080
# The health port, from anywhere, because the caller is the kubelet and it
# arrives from the node's own address — not a pod, not a source any selector
# in this template can name portably (ADR 0069 §5). What the rule opens is
# two read-only paths that answer yes or no about this process and name
# nothing in the cluster.
- ports:
- protocol: TCP
port: {{ include "runtime-agent.healthPort" . }}
{{- end }}
35 changes: 35 additions & 0 deletions charts/runtime-agent/templates/node-daemonset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ spec:
# Without this it fails closed and scans nothing.
- -scope-endpoint
- {{ printf "%s/v1/node-scope" $endpoint | quote }}
# Where this pod answers the kubelet's two questions. A flag and not
# the node's config file: that file exists only in the profile that
# profiles, and probes are needed in both (ADR 0069, ADR 0025).
- -health-address
- {{ printf ":%s" (include "runtime-agent.healthPort" .) | quote }}
{{- if $ebpf }}
# The master switch for the eBPF CPU profiler (ADR 0011). On a
# kernel below 5.8 or without BTF the profiler refuses gracefully
Expand All @@ -137,6 +142,36 @@ spec:
- -profile-endpoint
- {{ printf "%s/v1/node-profile" $endpoint | quote }}
{{- end }}
ports:
- name: health
containerPort: {{ include "runtime-agent.healthPort" . }}
# Readiness is the first completed pass, so a DaemonSet rollout waits
# for a node that has actually scanned. The budget covers a first pass
# whose scope query and report both wait out their 30s timeouts against
# a controller that is not up yet (ADR 0069).
startupProbe:
httpGet:
path: /readyz
port: {{ include "runtime-agent.healthPort" . }}
periodSeconds: 5
failureThreshold: 36
# The scan loop's own stamp. Not the controller's reachability: a
# controller outage would otherwise restart the agent on every node at
# once (ADR 0069 §2).
livenessProbe:
httpGet:
path: /livez
port: {{ include "runtime-agent.healthPort" . }}
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
readinessProbe:
httpGet:
path: /readyz
port: {{ include "runtime-agent.healthPort" . }}
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
env:
# The node name for the report; the controller keys facts by pod UID
# and container ID, so this is for observability, not attribution.
Expand Down
Loading