d5630da674
Remote executors (local Docker, remote Docker, Sprites) bind-mount the linux/amd64 agentctl into the container. The release pipeline only shipped a host-arch agentctl, so users who installed via the bundled binaries (npm/Homebrew/etc.) hit the same "agentctl linux binary not found" error the first time they tried a Docker executor — even on Linux, since the resolver expects the -linux-amd64 suffix. Changes: - .github/workflows/release.yml: cross-compile agentctl-linux-amd64 in the build-bundles matrix step (CGO off so it works from every host). Bundle ships kandev + host agentctl + agentctl-linux-amd64 in dist/kandev/bin/. The AgentctlResolver finds it next to the kandev binary automatically. - Dockerfile: same idea for the container image — produce both variants in the Go builder stage and copy the linux-amd64 helper into /app/apps/backend/bin/ so the resolver picks it up inside the image. A previous commit added the same dependency to \`make build\` for local dev installs; this commit closes the gap for end users.
128 lines
4.9 KiB
Docker
128 lines
4.9 KiB
Docker
# Kandev Server Dockerfile
|
|
# Multi-stage build: Go backend + Next.js frontend + CLI launcher
|
|
#
|
|
# Build:
|
|
# docker build -t kandev:latest .
|
|
#
|
|
# Run:
|
|
# docker run -p 38429:38429 -v kandev-data:/data kandev:latest
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 1: Go builder — compile kandev + agentctl binaries
|
|
# ---------------------------------------------------------------------------
|
|
FROM golang:1.26-bookworm AS go-builder
|
|
|
|
WORKDIR /build
|
|
|
|
# Cache Go module downloads
|
|
COPY apps/backend/go.mod apps/backend/go.sum ./
|
|
RUN go mod download
|
|
|
|
# Copy backend source and build
|
|
COPY apps/backend/ ./
|
|
|
|
RUN go build -ldflags "-s -w" -o /out/kandev ./cmd/kandev && \
|
|
go build -ldflags "-s -w" -o /out/agentctl ./cmd/agentctl && \
|
|
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -o /out/agentctl-linux-amd64 ./cmd/agentctl
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 2: Web + CLI builder — build Next.js standalone + CLI
|
|
# ---------------------------------------------------------------------------
|
|
FROM node:24-slim AS web-builder
|
|
|
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
|
|
|
WORKDIR /build/apps
|
|
|
|
# Copy workspace config and all package.json files for dependency caching
|
|
COPY apps/package.json apps/pnpm-workspace.yaml apps/pnpm-lock.yaml ./
|
|
COPY apps/web/package.json ./web/package.json
|
|
COPY apps/cli/package.json ./cli/package.json
|
|
COPY apps/packages/ui/package.json ./packages/ui/package.json
|
|
COPY apps/packages/theme/package.json ./packages/theme/package.json
|
|
COPY apps/packages/types/package.json ./packages/types/package.json
|
|
|
|
RUN pnpm install --frozen-lockfile
|
|
|
|
# Copy full source for build
|
|
COPY apps/ ./
|
|
|
|
# Build shared packages, web app, and CLI
|
|
RUN pnpm --filter @kandev/web build && \
|
|
pnpm --filter kandev build
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Stage 3: Runtime — minimal image with both services
|
|
# ---------------------------------------------------------------------------
|
|
FROM node:24-bookworm-slim AS runtime
|
|
|
|
# Install only essential runtime dependencies, then clean up
|
|
RUN apt-get update && \
|
|
apt-get install -y --no-install-recommends \
|
|
git \
|
|
ca-certificates \
|
|
gosu \
|
|
tini \
|
|
python3 \
|
|
python3-venv \
|
|
pipx && \
|
|
rm -rf /var/lib/apt/lists/* && \
|
|
PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install apprise
|
|
|
|
# Replace the node base image's default user so we own uid 1000
|
|
RUN userdel -r node && groupadd -r kandev && useradd -r -g kandev -u 1000 -m kandev
|
|
|
|
# Create app directory structure matching what the CLI expects:
|
|
# /app/apps/backend/bin/kandev
|
|
# /app/apps/web/.next/standalone/web/server.js
|
|
RUN mkdir -p /app/apps/backend/bin /app/apps/web/.next /data/worktrees
|
|
|
|
# Copy Go binaries. The -linux-amd64 variant of agentctl is bind-mounted into
|
|
# Docker-executor sandboxes by the lifecycle manager; ship it next to kandev
|
|
# so the AgentctlResolver finds it without manual configuration.
|
|
COPY --from=go-builder /out/kandev /app/apps/backend/bin/kandev
|
|
COPY --from=go-builder /out/agentctl-linux-amd64 /app/apps/backend/bin/agentctl-linux-amd64
|
|
COPY --from=go-builder /out/agentctl /usr/local/bin/agentctl
|
|
|
|
# Copy Next.js standalone output
|
|
COPY --from=web-builder /build/apps/web/.next/standalone/ /app/apps/web/.next/standalone/
|
|
|
|
# Copy static assets and public directory into standalone output
|
|
COPY --from=web-builder /build/apps/web/.next/static/ /app/apps/web/.next/standalone/web/.next/static/
|
|
COPY --from=web-builder /build/apps/web/public/ /app/apps/web/.next/standalone/web/public/
|
|
|
|
# Install CLI: copy built output + package.json, install prod deps, link binary
|
|
COPY --from=web-builder /build/apps/cli/dist/ /usr/local/lib/kandev-cli/dist/
|
|
COPY --from=web-builder /build/apps/cli/bin/ /usr/local/lib/kandev-cli/bin/
|
|
COPY --from=web-builder /build/apps/cli/package.json /usr/local/lib/kandev-cli/
|
|
RUN cd /usr/local/lib/kandev-cli && npm install --omit=dev && \
|
|
chmod +x bin/cli.js && \
|
|
ln -s /usr/local/lib/kandev-cli/bin/cli.js /usr/local/bin/kandev
|
|
|
|
# Kandev home directory (DB, worktrees, sessions, repos)
|
|
VOLUME ["/data"]
|
|
|
|
# Environment defaults for containerized operation
|
|
ENV KANDEV_NO_BROWSER=1 \
|
|
KANDEV_HOME_DIR=/data \
|
|
KANDEV_DOCKER_ENABLED=false \
|
|
HOSTNAME=0.0.0.0 \
|
|
NODE_ENV=production
|
|
|
|
# Copy entrypoint script
|
|
COPY docker-entrypoint.sh /usr/local/bin/
|
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
|
|
|
# Set build-time ownership of /app and /data
|
|
RUN chown -R kandev:kandev /app /data
|
|
|
|
WORKDIR /app
|
|
|
|
# Only the backend port is exposed — it reverse-proxies the Next.js frontend
|
|
# (which listens on 37429 internally), so users hit a single port.
|
|
EXPOSE 38429
|
|
|
|
# tini as PID 1 for signal handling; entrypoint handles privilege drop
|
|
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
|
|
CMD ["kandev", "start", "--backend-port", "38429", "--web-port", "37429", "--verbose"]
|