Install a probe on Kubernetes

A probe inside the cluster watches its workloads through the apiserver with its own ServiceAccount — no token to create, no kubeconfig to copy — and runs URL, API, TCP and database checks from the cluster network itself. The Helm chart installs it as a single-replica StatefulSet that registers itself with your Webserver on its first start.

What the in-cluster probe runs

The image is the slim probe: no browsers.

Runs Does not run
Container hosts (this cluster, other clusters, Docker hosts), URL, API, TCP, UDP, DNS, database, WebSocket, SNMP EUM / Web UI browser journeys
Ping, once icmp.enabled=true Ping without icmp.enabled — ICMP needs the NET_RAW capability

Keep a VM or Windows probe for browser journeys.

Before you start

  • Kubernetes 1.24 or later, and Helm 3.
  • A Webserver API address the pod can reach, as <host>:<port> — a DNS name works.
  • The _sharedInternal value from the Webserver’s webserver.json. Every component must carry the same one.
  • The chart, from the probe release archive: deploy/helm/mugnsoft-probe.
  • The image mugnsoft/monitor:<version>-slim in a registry the cluster can pull from. To build it yourself, from the probe sources:
docker build -f deploy/docker/Dockerfile --build-arg VERSION=4.2.0 -t registry.example.com/mugnsoft/monitor:4.2.0-slim .
docker push registry.example.com/mugnsoft/monitor:4.2.0-slim

Choose how the Webserver reaches the probe

The Webserver always calls the probe on its API port, over HTTPS. Where the Webserver runs decides the Service type:

Webserver runs service.type The Webserver dials You set
In the same cluster ClusterIP (default) <release>-mugnsoft-probe.<namespace>.svc.cluster.local:8051 nothing
Outside, nodes reachable NodePort a node address and the node port advertise.address, service.nodePort
Outside, through a load balancer LoadBalancer the balancer’s DNS name or IP advertise.address, once the balancer exists
The address is fixed at registration. The probe tells the Webserver how to reach it the first time it registers. If the address changes later, update the component’s IP and port on the Webserver’s Components page — a reinstall does not re-register a probe that kept its volume.

Install

A Webserver inside the cluster:

helm install probe-k8s ./mugnsoft-probe \
  --namespace mugnsoft --create-namespace \
  --set probe.webserver=webserver.mugnsoft.svc.cluster.local:8050 \
  --set probe.sharedInternal='<the _sharedInternal value>' \
  --set probe.location=eu-west-1

A Webserver outside, through a load balancer restricted to the Webserver’s address:

helm install probe-k8s ./mugnsoft-probe \
  --namespace mugnsoft --create-namespace \
  --set probe.webserver=mugnsoft.example.com:8050 \
  --set probe.sharedInternal='<the _sharedInternal value>' \
  --set service.type=LoadBalancer \
  --set 'service.loadBalancerSourceRanges={203.0.113.10/32}' \
  --set advertise.address=probe-k8s.example.com

With NodePort, add --set service.type=NodePort --set service.nodePort=30851 --set advertise.address=<a node address>.

Keep your settings in a values file rather than on the command line for upgrades: helm upgrade probe-k8s ./mugnsoft-probe -n mugnsoft -f probe-values.yaml.

Approve the probe

The probe registers itself as soon as the Webserver answers, retrying from 15 seconds to every 5 minutes while it does not. Watch it happen:

kubectl -n mugnsoft logs statefulset/probe-k8s-mugnsoft-probe | grep autoRegister
autoRegister - registered probe-k8s-mugnsoft-probe with webserver.mugnsoft.svc.cluster.local:8050; approve it on the Webserver's Components page

Then enable it on the Webserver’s Components page, like any other probe. Until then it is running and healthy, but idle.

Monitor this cluster from it

Add a container host on the Webserver:

Field Value
Runtime Kubernetes
Push to Probes the probe you just approved
Endpoint leave empty
Auth mode inCluster
Namespace empty — or the release namespace with rbac.scope=namespace

The probe uses the ServiceAccount token Kubernetes mounts into the pod, which the kubelet rotates; it is re-read on every check. See Container monitoring for discovery, grading and limits.

Values

Key Default Description
probe.webserver required The Webserver API as <host>:<port>
probe.name the release’s full name Component name on the Webserver; underscores become hyphens
probe.sharedInternal "" The shared machine-account secret; must match the Webserver’s
probe.existingSecret "" A Secret with a monitor.json key, used instead of rendering one
probe.location, probe.description "", Kubernetes in-cluster probe Shown on the Webserver
probe.port 8051 The port the probe listens on
probe.autoRegister true Register on the first start of an empty volume
probe.settings {} Extra monitor.json settings, such as dataRetention
advertise.address the Service DNS name What the Webserver dials; required with NodePort and LoadBalancer
advertise.port service.nodePort, else service.port The port the Webserver dials
service.type ClusterIP ClusterIP, NodePort or LoadBalancer
service.port, service.nodePort 8051, "" Service ports
service.loadBalancerSourceRanges [] Who may reach the probe through a load balancer
service.annotations {} For cloud load balancer options, such as an internal balancer
rbac.scope cluster cluster for every namespace and the nodes, namespace for the release namespace only
persistence.enabled, persistence.size true, 2Gi The volume holding keys, certificate and databases
persistence.storageClass "" The cluster default when empty
icmp.enabled false Run as root with NET_RAW so ping monitors work
image.repository, image.tag mugnsoft/monitor, <appVersion>-slim The probe image
resources 100m CPU, 128Mi requested; 512Mi limit Container resources
extraEnv [] Additional environment variables

What the chart creates

Object Purpose
StatefulSet (1 replica) The probe. One replica is one registered component; a second would be a second identity under the same name
PersistentVolumeClaim Keys, certificate and databases, so a restarted pod keeps its identity and history
Service and a headless Service The address the Webserver dials, and the StatefulSet’s stable pod DNS
Secret monitor.json, including the shared secret
ServiceAccount, ClusterRole (or Role) and binding Read-only access: get and list on pods, events, nodes, namespaces, deployments, statefulsets, daemonsets, cronjobs, jobs and pod and node metrics

Security

  • The container runs as a non-root user (UID 10001) with a read-only root filesystem, no privilege escalation, every capability dropped and the RuntimeDefault seccomp profile. icmp.enabled is the only exception: root with NET_RAW and DAC_OVERRIDE only.
  • The ServiceAccount can read and nothing else — it cannot change the cluster.
  • rbac.scope=namespace narrows it to one namespace. Node health is then unavailable.
  • Put the probe API behind service.loadBalancerSourceRanges or a network policy when it is exposed outside the cluster.

Troubleshooting

Symptom Cause and fix
The log repeats could not register ... retrying The pod cannot reach probe.webserver: DNS name, port, or an egress network policy
the Webserver refused ...: a server is already defined with this name A component of that name already exists — a previous install, or a volume that was deleted. Delete the old component on the Webserver, or set probe.name, then restart the pod
Registered and approved, but the Webserver cannot reach it The advertised address is not reachable from the Webserver: check service.type and advertise.address, then correct the component’s IP and port on the Webserver
Ping monitors fail with operation not permitted Set icmp.enabled=true
The pod restarted and asks to register again Persistence is disabled. Enable it; an empty volume is a new identity

Limitations

  • No EUM browser journeys in the slim image.
  • One replica per release. For redundancy, install a second release under another name and push the same monitors to both probes.
  • Changing the advertised address after registration is manual, on the Webserver.
  • The probe API is served over HTTPS with a self-signed certificate.

Translations