Files
yetone 7bfe3137bd 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.
2026-10-05 03:23:18 +08:00

64 lines
2.2 KiB
Docker

FROM golang:1.26-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
ARG VERSION=dev
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:
# its own files (/config/magpie), sign-ins kept where an agent keeps them
# (~/.codex, ~/.claude…, under HOME), and the cache holding Bun and the
# model catalog. magpie makes the folders a volume from an older image
# lacks.
ENV HOME=/config/home \
XDG_CONFIG_HOME=/config \
XDG_CACHE_HOME=/config/cache \
XDG_DATA_HOME=/config/data \
XDG_STATE_HOME=/config/state \
MAGPIE_ADDR=0.0.0.0:3425
VOLUME /config
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD ["/magpie", "healthcheck"]
EXPOSE 3425 3430
ENTRYPOINT ["/magpie"]
CMD ["serve"]