port Docker, with the group-versus-rootless choice spelled out
Three options, each explained rather than named, because the difference between
them is a security posture and the default is the one that sounds harmless.
1 docker group, the default. The text says what the group actually is: anyone
in it can run `docker run -v /:/host -it alpine chroot /host` and have a root
shell. It is not "access to Docker", it is root by a longer route — the same
framing os-user-docker.ts already uses for why members never get it.
Whether that matters is conditional, and the run works it out rather than
asserting either way: on an account that already has sudo it is a shorter
path to something they can reach anyway, and it says so; on an account that
does not, it is a real escalation, and it says that instead. Caught in
testing, where the reassuring sentence was being printed for a throwaway
account with no sudo at all — the exact case where it is untrue.
2 rootless, with the thing nobody would find out stated at the prompt:
Officer's app store cannot provision containers with it. compose.ts,
preflight.ts and system-monitor all spawn `docker` with no environment of
their own, so they reach /var/run/docker.sock; DOCKER_HOST is set only for
member commands, in os-user-docker.ts. pm2 started at boot by systemd has no
session either, so exporting it in a shell rc does not reach the process
that matters. The consequence is recorded in the summary, not just spoken.
3 neither, and what that costs.
Also fixed in the port: the repository codename came from `lsb_release -cs`, which
is wrong on every derivative — Mint reports "vanessa", Pop reports its own, and
Docker publishes neither, so `apt update` fails against a repository that does not
exist. os-release carries UBUNTU_CODENAME on exactly those systems for exactly
this reason; it is preferred now, with VERSION_CODENAME as the fallback, and the
ubuntu/debian half of the URL comes from ID_LIKE rather than being hardcoded.
The shared `services` network is created only when missing, checked with
`docker network inspect` rather than by running create and discarding the error.
Verified on this host, and against a throwaway account both with and without
sudo.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# machine-setup — Docker
|
||||
# =============================================================================
|
||||
#
|
||||
# Definitions only, like the other lib/ files.
|
||||
|
||||
[[ -n "${MACHINE_SETUP_DOCKER_LOADED:-}" ]] && return 0
|
||||
MACHINE_SETUP_DOCKER_LOADED=1
|
||||
|
||||
DOCKER_NETWORK="${SETUP_DOCKER_NETWORK:-services}"
|
||||
|
||||
docker_is_installed() { command -v docker &>/dev/null; }
|
||||
|
||||
# The daemon, not just the binary. `docker --version` answers from the client
|
||||
# alone and says nothing about whether there is anything to talk to.
|
||||
docker_daemon_ok() { docker info &>/dev/null; }
|
||||
|
||||
user_in_docker_group() { id -nG "$USERNAME" 2>/dev/null | tr ' ' '\n' | grep -qx docker; }
|
||||
|
||||
docker_rootless_installed() { [[ -S "/run/user/$(id -u "$USERNAME" 2>/dev/null)/docker.sock" ]]; }
|
||||
|
||||
# The codename Docker's repository is actually published under.
|
||||
#
|
||||
# `lsb_release -cs` is what the original used, and it is wrong on every
|
||||
# derivative: Mint reports "vanessa", Pop reports its own, and Docker publishes
|
||||
# neither — so `apt update` fails on a repository that does not exist. os-release
|
||||
# carries UBUNTU_CODENAME on exactly those systems for exactly this reason, so it
|
||||
# is preferred and VERSION_CODENAME is the fallback.
|
||||
docker_repo_codename() {
|
||||
local c
|
||||
c="$(os_release UBUNTU_CODENAME || true)"
|
||||
[[ -z "$c" ]] && c="$(os_release VERSION_CODENAME || true)"
|
||||
echo "$c"
|
||||
}
|
||||
|
||||
# Which upstream to point at. A derivative is Ubuntu or Debian as far as Docker
|
||||
# is concerned, and ID_LIKE is how it says which.
|
||||
docker_repo_distro() {
|
||||
case "$OS" in
|
||||
ubuntu | debian) echo "$OS" ;;
|
||||
*)
|
||||
case " $(os_release ID_LIKE || true) " in
|
||||
*" ubuntu "*) echo ubuntu ;;
|
||||
*) echo debian ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_docker_engine() {
|
||||
local distro codename
|
||||
distro="$(docker_repo_distro)"
|
||||
codename="$(docker_repo_codename)"
|
||||
|
||||
[[ -n "$codename" ]] || {
|
||||
warn "could not work out this release's codename — cannot add the Docker repository"
|
||||
return 1
|
||||
}
|
||||
|
||||
install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL "https://download.docker.com/linux/${distro}/gpg" |
|
||||
gpg --batch --yes --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${distro} ${codename} stable" \
|
||||
>/etc/apt/sources.list.d/docker.list
|
||||
|
||||
pkg_refresh >/dev/null
|
||||
pkg_install_now docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
}
|
||||
|
||||
# A shared network so containers from different compose files can reach each
|
||||
# other by name. Harmless if it is already there.
|
||||
ensure_docker_network() {
|
||||
docker network inspect "$DOCKER_NETWORK" &>/dev/null && return 0
|
||||
docker network create "$DOCKER_NETWORK" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# ── Rootless, for the owner ──
|
||||
#
|
||||
# Works, and does not work with Officer's app store as it stands. Both are true
|
||||
# and the second is the one nobody would find out until a container failed to
|
||||
# provision, so it is stated at the prompt rather than left here.
|
||||
#
|
||||
# The app store spawns `docker` with no environment of its own —
|
||||
# app-store/compose.ts, app-store/preflight.ts, api/system-monitor — so it talks
|
||||
# to whatever socket the `officer` pm2 process's environment points at. That is
|
||||
# /var/run/docker.sock unless DOCKER_HOST says otherwise, and nothing sets
|
||||
# DOCKER_HOST for the owner: os-user-docker.ts sets it only for member commands.
|
||||
#
|
||||
# pm2 started at boot by systemd has no session either, so exporting it in a
|
||||
# shell rc does not reach the process that matters.
|
||||
install_docker_rootless() {
|
||||
local uid
|
||||
uid="$(id -u "$USERNAME")"
|
||||
|
||||
# Without lingering, the user manager stops when the last session ends and
|
||||
# takes the daemon with it. Officer's shells are not login sessions.
|
||||
loginctl enable-linger "$USERNAME" >/dev/null 2>&1
|
||||
|
||||
sudo -u "$USERNAME" \
|
||||
XDG_RUNTIME_DIR="/run/user/${uid}" \
|
||||
DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${uid}/bus" \
|
||||
PATH="/usr/bin:/usr/sbin:/bin:/sbin" \
|
||||
dockerd-rootless-setuptool.sh install >/dev/null 2>&1 || return 1
|
||||
|
||||
sudo -u "$USERNAME" \
|
||||
XDG_RUNTIME_DIR="/run/user/${uid}" \
|
||||
DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/${uid}/bus" \
|
||||
systemctl --user enable --now docker >/dev/null 2>&1
|
||||
}
|
||||
Reference in New Issue
Block a user