mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-29 16:12:06 -04:00
Docker compose: mount docker.sock + install Docker CLI so Cookbook can reach sibling containers
Cookbook now needs to docker-exec into ollama-rocm (and any other sibling container holding a model server) from inside its own container, so: - Dockerfile installs the Docker CLI from the static binary tarball (the Debian docker.io package ships dockerd but not the client on slim) - docker-compose.yml bind-mounts /var/run/docker.sock and adds group_add for the host docker group (default GID 963) - entrypoint.sh detects the socket GID, creates a local group with that GID, and runs usermod -aG before gosu-dropping to the app user so the supplementary group propagates through (gosu strips by default)
This commit is contained in:
+17
@@ -20,6 +20,23 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
gosu \
|
gosu \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Docker CLI (client only — daemon stays on the host via the
|
||||||
|
# /var/run/docker.sock mount). The Debian `docker.io` package ships
|
||||||
|
# dockerd but not the client binary on slim, so grab the static client
|
||||||
|
# tarball from download.docker.com instead.
|
||||||
|
ARG DOCKER_CLI_VERSION=27.5.1
|
||||||
|
RUN ARCH="$(dpkg --print-architecture)" \
|
||||||
|
&& case "$ARCH" in \
|
||||||
|
amd64) DARCH=x86_64 ;; \
|
||||||
|
arm64) DARCH=aarch64 ;; \
|
||||||
|
*) echo "unsupported arch $ARCH"; exit 1 ;; \
|
||||||
|
esac \
|
||||||
|
&& curl -fsSL "https://download.docker.com/linux/static/stable/${DARCH}/docker-${DOCKER_CLI_VERSION}.tgz" \
|
||||||
|
-o /tmp/docker.tgz \
|
||||||
|
&& tar -xzf /tmp/docker.tgz -C /tmp \
|
||||||
|
&& install -m 0755 /tmp/docker/docker /usr/local/bin/docker \
|
||||||
|
&& rm -rf /tmp/docker /tmp/docker.tgz
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install Python deps first (layer cache). Optional extras (PyMuPDF AGPL, etc.)
|
# Install Python deps first (layer cache). Optional extras (PyMuPDF AGPL, etc.)
|
||||||
|
|||||||
@@ -16,6 +16,16 @@ services:
|
|||||||
# land under /app/.local for the odysseus user. Persist them so a
|
# land under /app/.local for the odysseus user. Persist them so a
|
||||||
# container recreate does not silently remove installed serve engines.
|
# container recreate does not silently remove installed serve engines.
|
||||||
- ${APP_DATA_DIR:-./data}/local:/app/.local:z
|
- ${APP_DATA_DIR:-./data}/local:/app/.local:z
|
||||||
|
# Docker socket — lets Cookbook launch commands like
|
||||||
|
# `docker exec ollama-rocm ollama show <tag>` reach the host's
|
||||||
|
# Docker daemon (and sibling containers like ollama-rocm /
|
||||||
|
# ollama-test). The in-container user needs to be in the
|
||||||
|
# socket's owning group — see `group_add` below; the GID
|
||||||
|
# there must match the host's `docker` group (defaults to 963
|
||||||
|
# on Debian, 999 on Ubuntu — override via env if yours differs).
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
group_add:
|
||||||
|
- "${DOCKER_GID:-963}"
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
# Lets the container reach local services on the Docker host, including
|
# Lets the container reach local services on the Docker host, including
|
||||||
# Ollama at http://host.docker.internal:11434.
|
# Ollama at http://host.docker.internal:11434.
|
||||||
|
|||||||
+31
-2
@@ -24,6 +24,31 @@ if ! getent passwd "$PUID" >/dev/null 2>&1; then
|
|||||||
useradd -u "$PUID" -g "$PGID" -M -s /bin/sh -d /app odysseus
|
useradd -u "$PUID" -g "$PGID" -M -s /bin/sh -d /app odysseus
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Docker-socket group plumbing. When /var/run/docker.sock is bind-
|
||||||
|
# mounted (cookbook uses `docker exec` to reach sibling containers
|
||||||
|
# like ollama-rocm), the socket is owned by root:docker on the host.
|
||||||
|
# We need the in-container odysseus user to be in the matching group
|
||||||
|
# so `gosu PUID:PGID` doesn't strip it. compose's `group_add` only
|
||||||
|
# applies to the initial root process — gosu drop resets supplementary
|
||||||
|
# groups — so detect the socket's GID here and add the user via the
|
||||||
|
# username form `gosu odysseus` below.
|
||||||
|
DOCKER_SOCK="${DOCKER_SOCK:-/var/run/docker.sock}"
|
||||||
|
if [ -S "$DOCKER_SOCK" ]; then
|
||||||
|
SOCK_GID="$(stat -c '%g' "$DOCKER_SOCK" 2>/dev/null || echo '')"
|
||||||
|
if [ -n "$SOCK_GID" ] && [ "$SOCK_GID" != "0" ]; then
|
||||||
|
# Create the group locally if missing, then add odysseus to it.
|
||||||
|
if ! getent group "$SOCK_GID" >/dev/null 2>&1; then
|
||||||
|
groupadd -g "$SOCK_GID" docker_host || true
|
||||||
|
fi
|
||||||
|
SOCK_GROUP="$(getent group "$SOCK_GID" | cut -d: -f1)"
|
||||||
|
if [ -n "$SOCK_GROUP" ]; then
|
||||||
|
ODY_USER="$(getent passwd "$PUID" | cut -d: -f1)"
|
||||||
|
[ -z "$ODY_USER" ] && ODY_USER=odysseus
|
||||||
|
usermod -aG "$SOCK_GROUP" "$ODY_USER" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Repair ownership on every writable path the app touches at runtime.
|
# Repair ownership on every writable path the app touches at runtime.
|
||||||
#
|
#
|
||||||
# Bind-mounted dirs (/app/data, /app/logs) are the obvious ones, but
|
# Bind-mounted dirs (/app/data, /app/logs) are the obvious ones, but
|
||||||
@@ -83,9 +108,13 @@ export PATH="/app/.local/bin:$PATH"
|
|||||||
# Run first-time setup as the app user so data/ files get the right ownership.
|
# Run first-time setup as the app user so data/ files get the right ownership.
|
||||||
# setup.py is idempotent — skips auth.json / .env if they already exist.
|
# setup.py is idempotent — skips auth.json / .env if they already exist.
|
||||||
# || true so a setup failure never prevents the container from starting.
|
# || true so a setup failure never prevents the container from starting.
|
||||||
gosu "$PUID:$PGID" python /app/setup.py || true
|
# Use the username form (no :GID) so supplementary groups from /etc/group
|
||||||
|
# (including the docker-socket group set above) flow through to the child.
|
||||||
|
ODY_USER="$(getent passwd "$PUID" | cut -d: -f1)"
|
||||||
|
[ -z "$ODY_USER" ] && ODY_USER="$PUID:$PGID"
|
||||||
|
gosu "$ODY_USER" python /app/setup.py || true
|
||||||
|
|
||||||
# Drop root and run the actual app. `gosu` is preferred over `su` /
|
# Drop root and run the actual app. `gosu` is preferred over `su` /
|
||||||
# `sudo` because it cleans up the process tree (no extra shell layer)
|
# `sudo` because it cleans up the process tree (no extra shell layer)
|
||||||
# so signals (SIGTERM from `docker stop`) reach uvicorn directly.
|
# so signals (SIGTERM from `docker stop`) reach uvicorn directly.
|
||||||
exec gosu "$PUID:$PGID" "$@"
|
exec gosu "$ODY_USER" "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user