Install the docker client, and check it is there #6

Merged
branderson merged 4 commits from docker-cli into main 2026-08-06 01:10:39 -07:00
Collaborator

Summary generated by LLM agent

Confirmed by apt-cache policy on a real trixie box:

docker.io:   Installed: 26.1.5+dfsg1-9+b13
docker-cli:  Installed: (none)          Candidate: 26.1.5+dfsg1-9+b13

Debian splits the client from the daemon, docker.io only Recommends
docker-cli, and --no-install-recommends drops it. apt reports success, the
daemon installs, and the host has no docker binary at all.

The part worth fixing is that nothing noticed

The next step ran docker compose version, got command not found, and
concluded that no route had produced compose and the host probably could not
reach download.docker.com — while the log immediately above showed
docker-compose-plugin downloading and installing cleanly.

Two components blamed for a third one's absence, with the evidence against it
on screen. That is the same failure this project keeps producing: a check that
infers a cause instead of reporting what it actually observed.

So the package step now verifies there is a docker command before anything
downstream assumes one, and when there isn't, prints what dpkg actually has
and names the client/daemon split as the likely cause.

--no-install-recommends stays. It is right for a machine whose value is a
small known surface — the fix is naming what is needed, not widening the net
and discovering later what came along.

To unblock an existing VM

sudo apt-get install -y docker-cli
docker compose version
**Summary generated by LLM agent** Confirmed by `apt-cache policy` on a real trixie box: ``` docker.io: Installed: 26.1.5+dfsg1-9+b13 docker-cli: Installed: (none) Candidate: 26.1.5+dfsg1-9+b13 ``` Debian splits the client from the daemon, `docker.io` only *Recommends* `docker-cli`, and `--no-install-recommends` drops it. apt reports success, the daemon installs, and the host has no `docker` binary at all. ## The part worth fixing is that nothing noticed The next step ran `docker compose version`, got `command not found`, and concluded that no route had produced compose and the host probably could not reach `download.docker.com` — while the log immediately above showed `docker-compose-plugin` downloading and installing cleanly. Two components blamed for a third one's absence, with the evidence against it on screen. That is the same failure this project keeps producing: a check that infers a cause instead of reporting what it actually observed. So the package step now verifies there is a `docker` command before anything downstream assumes one, and when there isn't, prints what `dpkg` actually has and names the client/daemon split as the likely cause. `--no-install-recommends` stays. It is right for a machine whose value is a small known surface — the fix is naming what is needed, not widening the net and discovering later what came along. ## To unblock an existing VM ```sh sudo apt-get install -y docker-cli docker compose version ```
dejima-agent added 1 commit 2026-08-06 00:48:37 -07:00
The package list named docker.io and --no-install-recommends, which on Debian
drops docker-cli - the client is a separate package from the daemon. apt
reported success, the daemon was installed, and the host had no `docker`
binary at all.

Nothing noticed. The next step ran `docker compose version`, got "command not
found", and reported that no route had produced compose and the host probably
could not reach download.docker.com - while the log directly above showed
docker-compose-plugin downloading and installing cleanly. Two components were
blamed for a third one's absence.

docker-cli is named explicitly now, and the package step verifies there is a
`docker` command before anything downstream assumes one. When it is missing it
prints what dpkg actually has and names the split as the likely cause, rather
than leaving the reader to work out which of the packages that reported
success was not the one they needed.

--no-install-recommends stays. It is right for a machine whose value is a
small known surface; the fix is naming what is needed rather than widening the
net and finding out later what came along.
dejima-agent added 1 commit 2026-08-06 00:51:29 -07:00
A commit doing this was pushed after PR #5 had already merged, so it never
landed and main still tells the reader that no route produced compose and the
host probably cannot reach download.docker.com - which was wrong on a machine
where the download had plainly succeeded moments earlier.

The failure now prints every plugin directory's contents and the CLI version,
and distinguishes the two situations rather than asserting one: a binary
listed means the package installed and something else is wrong; nothing listed
means no route produced one, and then the network is worth suspecting.

The symlink logic from that commit does not come with it. It was written on
the theory that Debian's CLI could not see Docker's plugin, and the real cause
was that no CLI was installed at all - with docker-cli present, compose works
untouched. Defensive code for a case that does not occur never runs, so it is
never known to work, and if the case ever did arrive it would half-fix it and
hide it.

Also carried forward: the backports rung refreshes package lists after
removing a source that produced nothing, instead of leaving apt with a list
for a source that is no longer configured.
dejima-agent added 2 commits 2026-08-06 01:08:16 -07:00
A first install died at "created dejima-ci but could not read its gateway
back", against a network docker had just created without complaint. When a
network is made with --subnet and no explicit --gateway, the daemon need not
record a Gateway in IPAM.Config at all - the address only ever shows up on
the bridge. Staking the install on that one template expression made a
supported way of creating the network look like a failure.

Ask docker first, since it decides, then fall back to the address actually on
the bridge, then to the subnet's first usable address. Print which one
answered, because a gateway from the third source is a hint that the network
is not what this expects.

The existing-network branch read the gateway the same single way and did not
even check the result, so the same daemon would have carried an empty gateway
into the resolver's listen-address and the runner's --dns. Both branches now
go through one helper that fails loudly.
The privileged tier's jobs run in the host's network namespace. That is the
grant the tier exists for, and it means no bridge sits in front of their
traffic - so the job network, the resolver listening on its gateway and the
DOCKER-USER rules matching on it never see a packet a job sends.

The bootstrapper was installing all of it anyway. That costs an evening of
prompts and protects nothing, and the worse half is what it leaves behind: a
runtime host carrying every visible sign of an egress allowlist and no
allowlist. Skip it, and say why at the point it would have run.

An operator who really is putting both tiers on one machine can still run
./install.sh by hand; the output says so.

The README claimed the node's firewall need not restrict public egress
because "job containers already have an allowlist, enforced inside the VM".
True of the ordinary tier, false of the one that section is about. The
reasons that do hold - CDN rotation, and that no node rule survives VM root -
stand on their own, and what the tier actually gives a job is now stated:
the whole public internet, and none of your LAN.
branderson approved these changes 2026-08-06 01:10:34 -07:00
branderson merged commit ace51c8cae into main 2026-08-06 01:10:39 -07:00
Sign in to join this conversation.