v1.10.2: booterm runtime on bookworm-slim (glibc), su-exec → gosu
Switched the booterm runtime + proddeps stages from node:20-alpine (musl) to node:20-bookworm-slim (glibc) so host-installed glibc binaries (Claude Code, opencode, nvm node) run inside the container when invoked from the terminal pane. node-pty's native .node has to be compiled in the same libc env as the runtime, so both stages flip together; the TypeScript-only builder stage stays on alpine. su-exec is alpine-only; Debian replacement is gosu — swapped in both the runtime apt install and the tmux default-command. uid/gid 1000 collision with the bookworm `node` user handled via userdel/groupdel before groupadd/useradd. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,28 +15,45 @@ COPY apps/booterm ./apps/booterm
|
||||
RUN pnpm --filter=@boocode/booterm build
|
||||
|
||||
# ---- Prod-deps stage: hoisted, native built via npm rebuild ----
|
||||
FROM node:20-alpine AS proddeps
|
||||
# v1.10.2: switched to bookworm-slim (glibc) so node-pty's native .node is
|
||||
# compiled against the same libc as the runtime stage. A musl-built .node
|
||||
# won't dlopen in a glibc node binary, so both stages must match.
|
||||
FROM node:20-bookworm-slim AS proddeps
|
||||
ENV COREPACK_DEFAULT_TO_LATEST=0
|
||||
RUN corepack enable && corepack prepare pnpm@10.15.1 --activate
|
||||
RUN apk add --no-cache python3 make g++
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
python3 make g++ ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /prod
|
||||
COPY apps/booterm/package.json ./package.json
|
||||
RUN pnpm install --prod --config.node-linker=hoisted --config.strict-peer-dependencies=false
|
||||
# pnpm 10 ignores build scripts; force compile with npm directly.
|
||||
# node-gyp is bundled with npm in the node:20-alpine image.
|
||||
# node-gyp is bundled with npm in the node:20-bookworm-slim image.
|
||||
RUN cd node_modules/node-pty && npm run install
|
||||
# Sanity check — fail the build if the artifact still isn't there
|
||||
RUN test -f node_modules/node-pty/build/Release/pty.node && echo "pty.node OK" || (echo "pty.node MISSING" && exit 1)
|
||||
|
||||
# ---- Runtime ----
|
||||
FROM node:20-alpine AS runtime
|
||||
RUN apk add --no-cache tmux libstdc++ bash su-exec shadow
|
||||
# v1.10.1: terminal shells inside tmux drop privs to samkintop via su-exec.
|
||||
# v1.10.2: switched from node:20-alpine (musl) to node:20-bookworm-slim (glibc)
|
||||
# so glibc-linked binaries from /home/samkintop (Claude Code, opencode, the
|
||||
# host's nvm node) run inside the container when invoked from the terminal
|
||||
# pane. Side-effect: su-exec is alpine-only — Debian replacement is gosu.
|
||||
FROM node:20-bookworm-slim AS runtime
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
tmux bash gosu ca-certificates procps \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
# Mirror uid/gid 1000:1000 from the host so the bind-mounted /home/samkintop
|
||||
# (added in docker-compose) is owned by the user from the container's view.
|
||||
RUN deluser --remove-home node 2>/dev/null; delgroup node 2>/dev/null; \
|
||||
addgroup -g 1000 samkintop && \
|
||||
adduser -D -u 1000 -G samkintop -s /bin/bash samkintop
|
||||
# bookworm-slim ships a `node` user at 1000 — wipe whatever sits on uid/gid
|
||||
# 1000 first, then create samkintop fresh.
|
||||
RUN if id -u 1000 >/dev/null 2>&1; then \
|
||||
userdel -r "$(id -un 1000)" 2>/dev/null || true; \
|
||||
fi; \
|
||||
if getent group 1000 >/dev/null 2>&1; then \
|
||||
groupdel "$(getent group 1000 | cut -d: -f1)" 2>/dev/null || true; \
|
||||
fi; \
|
||||
groupadd -g 1000 samkintop && \
|
||||
useradd -m -u 1000 -g 1000 -s /bin/bash samkintop
|
||||
WORKDIR /app
|
||||
COPY --from=builder /build/apps/booterm/dist ./dist
|
||||
COPY --from=proddeps /prod/package.json ./package.json
|
||||
|
||||
Reference in New Issue
Block a user