diff --git a/bin/install.sh b/bin/install.sh index 6acc4a4..7a5897e 100755 --- a/bin/install.sh +++ b/bin/install.sh @@ -20,13 +20,15 @@ REPO_ROOT="$(dirname -- "$SCRIPT_DIR")" ARCH="$(fetch_arch)" # x86_64 / aarch64 DEB="$(fetch_arch_deb)" # amd64 / arm64 -# docker_rootless_available — true only if a rootless Docker daemon is up and -# reachable. kind needs a container runtime to create clusters; on Kasm we run -# Docker rootless (never system Docker), so kind is worth installing only when -# that daemon answers. SecurityOptions lists name=rootless under rootless mode. -docker_rootless_available() { +# docker_full_available — true only if a non-rootless (full) Docker daemon is +# up and reachable. kind needs full Docker: we could not get it working against +# rootless Docker on Kasm, so it is only worth installing where a rootful +# daemon answers. SecurityOptions lists name=rootless under rootless mode. +docker_full_available() { command -v docker >/dev/null 2>&1 || return 1 - docker info -f '{{println .SecurityOptions}}' 2>/dev/null | grep -q 'name=rootless' + _secopts="$(docker info -f '{{println .SecurityOptions}}' 2>/dev/null)" || return 1 + [ -n "$_secopts" ] || return 1 + ! printf '%s' "$_secopts" | grep -q 'name=rootless' } # jq — command-line JSON processor (single static binary). @@ -68,9 +70,8 @@ install_k9s() { } # kind — run local Kubernetes clusters in Docker (single static binary). Gated -# on rootless Docker at the call site since it is useless without a runtime. -# On systemd-less hosts the rootless daemon also needs cgroup delegation before -# kind can create clusters; see the docker-rootless-cgroup/ module. +# on full (non-rootless) Docker at the call site: kind could not be made to +# work against rootless Docker on Kasm, so it is skipped there. install_kind() { ver=v0.32.0 have_version kind "$ver" && { fsay "kind $ver already installed."; return 0; } @@ -150,10 +151,10 @@ install_jq install_kubectl install_helm install_k9s -if docker_rootless_available; then +if docker_full_available; then install_kind else - fsay "Skipping kind: rootless Docker not available." + fsay "Skipping kind: full (non-rootless) Docker not available." fi install_kubectx install_kubens diff --git a/bootstrap.sh b/bootstrap.sh index b6001d1..d953c1e 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -31,6 +31,8 @@ fi "$SCRIPT_DIR/zsh/install.sh" "$SCRIPT_DIR/git/install.sh" +# Runs before bin/ so the kind install gate can see the rootful daemon. +"$SCRIPT_DIR/docker/install.sh" "$SCRIPT_DIR/bin/install.sh" "$SCRIPT_DIR/ansible/install.sh" # Runs last: needs rootless Docker already up (started at boot) so it can diff --git a/docker-rootless-cgroup/install.sh b/docker-rootless-cgroup/install.sh index 0110de9..61f0ff1 100755 --- a/docker-rootless-cgroup/install.sh +++ b/docker-rootless-cgroup/install.sh @@ -1,7 +1,10 @@ #!/usr/bin/env sh # docker-rootless-cgroup/install.sh — give rootless Docker cgroup v2 controller -# delegation on a systemd-less host (e.g. Kasm), so per-container cgroups work -# and `kind` can create clusters. +# delegation on a systemd-less host (e.g. Kasm), so per-container cgroups work. +# (This was originally done to support `kind`, but kind never worked reliably +# against rootless Docker even with delegation — bin/ now only installs kind +# where full Docker is available. The delegation itself is still useful for +# per-container resource limits.) # # Why: rootless Docker only receives delegated cgroup v2 controllers when # systemd sets `Delegate=yes` on the user session. Kasm images run no systemd @@ -117,7 +120,7 @@ cat > "$tmp" <<'SH' #!/bin/sh # Managed by dotfiles (docker-rootless-cgroup). Shadows /usr/bin/dockerd-rootless.sh # on PATH. Places the rootless Docker daemon in a private, delegated cgroup v2 -# leaf so it can enable controllers (needed by `kind`), then execs the real +# leaf so it can enable controllers (per-container cgroups), then execs the real # launcher. No-op if the delegated slice is absent, so it is safe anywhere. _cg=/sys/fs/cgroup/rootless/daemon if [ -w /sys/fs/cgroup/rootless ] && [ -d "$_cg" ]; then @@ -156,9 +159,9 @@ done driver="$(docker info -f '{{.CgroupDriver}}' 2>/dev/null || true)" if [ "$driver" = "none" ] || [ -z "$driver" ]; then say "docker-rootless-cgroup: WARNING — CgroupDriver is still '${driver:-unreachable}'." - say " kind will not work yet. Inspect the new dockerd's cgroup:" + say " Per-container cgroups will not work yet. Inspect the new dockerd's cgroup:" say " cat /proc/\$(pgrep -x dockerd | head -1)/cgroup # expect .../rootless/daemon" exit 0 fi say "docker-rootless-cgroup: done. CgroupDriver=$driver — rootless Docker now has" -say " delegated cgroups; \`kind create cluster\` can run." +say " delegated cgroups; per-container resource limits work." diff --git a/docker/install.sh b/docker/install.sh new file mode 100755 index 0000000..c2bcc5f --- /dev/null +++ b/docker/install.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env sh +# docker/install.sh — install full (rootful) Docker Engine and let the +# invoking user talk to it without sudo. +# +# What it does: +# 1. Installs Docker Engine via Docker's official convenience script +# (get.docker.com — supports both RHEL- and Debian-family distros and +# sets up the upstream package repo). Skipped when `docker` is already +# installed. +# 2. Enables and starts the service (systemd hosts only). +# 3. Adds the invoking user to the `docker` group so the daemon socket is +# usable without sudo. Takes effect at next login. +# +# Deliberately no-ops when a rootless Docker daemon is detected (e.g. Kasm +# ships its own rootless setup) — installing rootful Docker there would fight +# the existing runtime. See docker-rootless-cgroup/ for the Kasm-side config. +# +# Idempotent and safe to re-run. Uses sudo. +set -eu + +say() { printf '%s\n' "$*" >&2; } + +# --- skip on rootless-Docker hosts ------------------------------------------- +if command -v docker >/dev/null 2>&1 && + docker info -f '{{println .SecurityOptions}}' 2>/dev/null | grep -q 'name=rootless'; then + say "docker: rootless Docker daemon detected; leaving it alone." + exit 0 +fi + +# --- 1. install engine ------------------------------------------------------- +if command -v docker >/dev/null 2>&1; then + say "docker: engine already installed ($(docker --version 2>/dev/null || echo 'version unknown'))." +else + say "docker: installing Docker Engine via get.docker.com..." + tmp="$(mktemp)" + if command -v curl >/dev/null 2>&1; then + curl -fsSL https://get.docker.com -o "$tmp" + elif command -v wget >/dev/null 2>&1; then + wget -qO "$tmp" https://get.docker.com + else + say "docker: need curl or wget"; exit 1 + fi + sudo sh "$tmp" + rm -f "$tmp" +fi + +# --- 2. enable + start the service (systemd only) ---------------------------- +if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then + sudo systemctl enable --now docker +else + say "docker: no systemd; not managing the service (start dockerd yourself)." +fi + +# --- 3. group membership for the invoking user ------------------------------- +user="$(id -un)" +if id -nG "$user" | tr ' ' '\n' | grep -qx docker; then + say "docker: $user already in the docker group." +else + sudo usermod -aG docker "$user" + say "docker: added $user to the docker group." + say " Log out and back in (or run 'newgrp docker') for it to take effect." +fi diff --git a/zsh/zshrc b/zsh/zshrc index 3c5ab6a..9e505ff 100644 --- a/zsh/zshrc +++ b/zsh/zshrc @@ -2,6 +2,19 @@ # overwritten on the next bootstrap run. Edit zsh/zshrc in the dotfiles repo # instead. +# If this account was added to the docker group (dotfiles/docker/install.sh) +# but this shell's session predates that, re-exec via newgrp so docker works +# without a full logout. Guarded: fires only when the group is on the account +# yet missing from the running shell's groups, so the newgrp'd shell (which +# has the group) cannot loop. +# Only for real terminals ([ -t 0 ]): newgrp replaces the shell and would +# swallow the command in scripted `zsh -i -c ...` invocations. +if [ -t 0 ] && [ -S /var/run/docker.sock ] \ + && id -nG "${USER:-$(id -un)}" 2>/dev/null | grep -qw docker \ + && ! id -Gn 2>/dev/null | grep -qw docker; then + exec newgrp docker +fi + # Userland tools installed by dotfiles/bin/install.sh live here. case ":$PATH:" in *":$HOME/.local/bin:"*) ;;