Docker Engine with a HEART: built in, or as a sidecar (experimental)#
To repeat the experiment step by step, read REPLICATE.md. Results: results/SUMMARY.md.
Status: experimental. Built from Moby docker-v29.9.3 (Docker Engine 29.9.3) with one new package, tested on a real daemon running real containers. Not a Docker release, and not endorsed by Docker. Licence: Apache-2.0, like Moby.
What it adds#
One new package, daemon/heart | Standard library only, so no new dependencies. It serves the HEART Basic API on 127.0.0.1:43278 (or 7685): the Card, the Pulse and alerts. |
One hook in daemon/command/daemon.go | heart.Start(ctx, hosts, cli.Config.Root), called right after the daemon tells systemd it is ready. |
| How it reads Docker | Only through the daemon's own Engine API socket (/_ping, /info, /containers/json, /events). It never touches the daemon's internals, environment variables, logs or files. |
What it notices, with no network and no AI model#
| What happens | Fault code |
|---|---|
| A container keeps restarting (3 starts in 5 minutes) | system.main-function-degraded |
| A container's health check fails | system.main-function-degraded |
| A container is killed for lack of memory | performance.memory-exhausted |
| The disk under the data root passes 90% | storage.nearly-full |
| The Engine API stops answering (3 checks) | system.main-function-lost |
Privacy#
- Anyone sees the Card, the Pulse status and the fault codes.
- With the owner key you also see container names, counts and disk figures. The key is made at first start, kept in
<data-root>/heart/owner.key(mode 600), and printed once in the daemon's log. - Loopback only: the HEART refuses any address that is not loopback, because it holds the power of the Docker socket.
HEART=offturns it off.
Files#
| File | What it is |
|---|---|
heart/heart.go, statfs_*.go, heart_test.go | The package, and its unit tests against a fake Engine |
heart/cmd/heart-docker-sidecar | The same package as its own program, beside an unchanged dockerd (way B) |
run_both.sh, summarize.py | Both ways, 3 runs each; and the summary table |
REPLICATE.md | Every step, with the exact versions, commands and our results |
apply_patch.py | Adds the package and the hook to a Moby source tree |
pod_main.sh | Clone, patch, test, build, then the end-to-end tests, then the upload to B2. Runs on a RunPod CPU pod. |
test_heart_docker.py | End-to-end tests against the real patched dockerd and Docker's own containerd and runc: real faults in real containers, and a comparison with the stock dockerd |
runpod_run.py | Starts the pod, watches B2 for the result, and always terminates the pod |
b2.py | Uploads to and downloads from B2 with the B2 native API |
results/ | Results of each run |
test_monitor_e2e.py | End to end with HEART Hub: register, figures, Ask AI (a fake Claude API) and changing CPU and memory from the site |
screenshots/ | The live run on heartcortex.ai: registering, figures, Ask AI with Claude, and changing the CPU limit (walkthrough) |
On B2 (experimentalDocker/)#
| Folder | What is in it |
|---|---|
source/ | The full modified Moby source |
bin/docker-v29.9.3/dockerd-heart | The binary, with its SHA-256 |
patch/ | The change as a patch |
scripts/ | These files |
results/<run>/ | The results of each run |
Run it yourself#
python3 apply_patch.py path/to/moby
cd path/to/moby && go build -o dockerd-heart ./cmd/dockerd
sudo python3 test_heart_docker.py --heart ./dockerd-heart --bin /path/to/docker-static --out results/