docker: the image has bash and busybox, so a terminal in the container opens (スライム on Discord: 这2天的docker版更新后无法进入terminal模式,导致配置不了devin … exec: "/bin/bash": stat /bin/bash: no such file or directory)

The image is distroless, which has no shell at all, so a NAS panel's
terminal (Synology, 1Panel, Portainer open /bin/bash or /bin/sh) and
`docker exec -it magpie bash` failed, and a sign-in that needs a terminal
(magpie accounts add devin) couldn't be made there. The image now copies
in Debian 12's bash with the libtinfo it links (distroless cc is Debian 12,
so its glibc runs it) and busybox's commands, and puts magpie on PATH
(/usr/local/bin/magpie). The image still runs as nonroot and starts
/magpie serve as before; it grows from about 37 MB of extras to 66.6 MB.

Built locally (docker 29.4, arm64): bash 5.2.15 and sh run as uid 65532,
`magpie version` and `magpie healthcheck` work from bash, the gateway
answers 200 on /v1/models, /config keeps its folders. The Docker workflow's
smoke test now runs bash and sh in the container. README says so.
This commit is contained in:
yetone committed 2026-10-05 03:23:18 +08:00
1 parent c377754c8f
commit 7bfe3137bd
3 files changed
+27 -1

No files matched your search

+4
View File
@@ -51,6 +51,10 @@ jobs:
done
test "$READY" = 1
# a NAS panel's terminal opens bash or sh, with magpie on PATH
docker exec smoke /bin/bash -c 'magpie healthcheck && ls /config >/dev/null'
docker exec smoke /bin/sh -c 'echo sh works'
CODE=$(curl -s -o /tmp/body.json -w '%{http_code}' \
-H 'Authorization: Bearer magpie' -H 'Content-Type: application/json' \
-d '{"model":"ci-unknown-model","messages":[{"role":"user","content":"hi"}]}' \
+20
View File
@@ -12,12 +12,32 @@ RUN CGO_ENABLED=0 go build -tags nogui -trimpath \
-ldflags "-s -w -X main.version=${VERSION}" -o /out/magpie . \
&& mkdir -p /config/home /config/cache /config/data /config/state
# A shell for the container's terminal: NAS panels (Synology, 1Panel,
# Portainer) open /bin/bash or /bin/sh, and distroless has neither, so a
# terminal there failed with "stat /bin/bash: no such file or directory".
# Debian 12's bash (with the libtinfo it links), which runs on the glibc of
# distroless's own Debian 12, and busybox for ls, cat and the like.
FROM debian:12-slim AS shell
RUN mkdir -p /out/bin /out/lib \
&& cp /bin/bash /out/bin/bash \
&& cp -L "$(ldd /bin/bash | awk '/libtinfo/ {print $3}')" /out/lib/
FROM busybox:1.37-uclibc AS busybox
# cc, not static: plugins run on Bun, which magpie downloads on first use
# and which needs glibc (static has no libc at all, and Bun's musl build
# would need musl). cc is static plus glibc, libgcc and libstdc++.
FROM gcr.io/distroless/cc-debian12:nonroot
COPY --from=build /out/magpie /magpie
COPY --from=busybox /bin/busybox /bin/busybox
COPY --from=shell /out/bin/bash /bin/bash
COPY --from=shell /out/lib/ /usr/lib/
# busybox's commands, and magpie on PATH, so `magpie accounts add …` works
# in that terminal
USER root
RUN ["/bin/busybox", "sh", "-c", "/bin/busybox --install -s /bin && mkdir -p /usr/local/bin && ln -s /magpie /usr/local/bin/magpie"]
USER nonroot
COPY --from=build --chown=65532:65532 /config /config
# Everything magpie and the sign-ins it manages write goes into the volume:
+3 -1
View File
@@ -788,7 +788,9 @@ Termux uses the Android terminal build: the installer puts it in
### Docker
`docker build` makes a server image: the terminal-only binary on
distroless (`cc`, for the glibc the plugins' Bun needs), run as nonroot,
distroless (`cc`, for the glibc the plugins' Bun needs) with bash and
busybox for a terminal in the container (`docker exec -it magpie bash`, or a
NAS panel's terminal; `magpie` is on its PATH), run as nonroot,
with everything it keeps in a volume at `/config`: magpie's own files
(`/config/magpie`), the sign-ins kept where their agent keeps them (HOME is
`/config/home`, so `~/.codex`, `~/.claude`… are in it) and the cache with the