forked from kdlbs/kandev
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
141 lines (125 loc) · 6.01 KB
/
Copy pathDockerfile
File metadata and controls
141 lines (125 loc) · 6.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# Kandev Server Dockerfile
#
# Single-stage build that consumes prebuilt artifacts. The release workflow
# (.github/workflows/release.yml) extracts the per-arch release bundle
# (`kandev-linux-{x64,arm64}.tar.gz`) into the build context, then this file
# just COPYs the native binaries into the runtime layout.
#
# Building this file outside CI (manual `docker build .`) will fail because
# the `bundle/` directory isn't present in the build context. To build
# locally, extract a release tarball into ./ctx/bundle/ alongside
# ./ctx/docker-entrypoint.sh and run:
# docker build -f Dockerfile ./ctx
#
# Run:
# docker run -p 38429:38429 -v kandev-data:/data ghcr.io/kdlbs/kandev:latest
FROM debian:bookworm-slim AS apt-keys
RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates curl gnupg && \
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
| gpg --dearmor -o /nodesource.gpg && \
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc \
| gpg --dearmor -o /microsoft.gpg && \
rm -rf /var/lib/apt/lists/*
FROM debian:bookworm-slim
ARG NODE_MAJOR=24
COPY --from=apt-keys /nodesource.gpg /usr/share/keyrings/nodesource.gpg
COPY --from=apt-keys /microsoft.gpg /usr/share/keyrings/microsoft.gpg
# Install runtime dependencies. gh is included because the GitHub integration
# (PR review, webhooks) shells out to it for auth fallback when GITHUB_TOKEN
# is not set. Node/npm support agent CLI installs and the universal image's
# pnpm layer. Azure CLI + azure-devops extension support agentctl Azure Repos PR
# creation (az repos pr create). apprise is installed via pipx for notification
# fan-out.
RUN apt-get update && \
apt-get install -y --no-install-recommends \
apt-transport-https \
ca-certificates \
curl \
git \
gh \
gosu \
tini \
python3 \
python3-venv \
pipx && \
echo "deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \
> /etc/apt/sources.list.d/nodesource.list && \
arch="$(dpkg --print-architecture)" && \
printf "%s\n" \
"Types: deb" \
"URIs: https://packages.microsoft.com/repos/azure-cli/" \
"Suites: bookworm" \
"Components: main" \
"Architectures: $arch" \
"Signed-by: /usr/share/keyrings/microsoft.gpg" \
> /etc/apt/sources.list.d/azure-cli.sources && \
apt-get update && \
apt-get install -y --no-install-recommends nodejs azure-cli && \
rm -f \
/etc/apt/sources.list.d/nodesource.list \
/etc/apt/sources.list.d/azure-cli.sources \
/usr/share/keyrings/nodesource.gpg \
/usr/share/keyrings/microsoft.gpg && \
rm -rf /var/lib/apt/lists/* && \
PIPX_HOME=/opt/pipx PIPX_BIN_DIR=/usr/local/bin pipx install apprise
# Create the runtime user with uid 1000.
# Home is placed under /data so agent CLI auth state (gh, claude, codex, auggie,
# copilot, amp, ...) lives on the PV and survives pod restarts and image upgrades.
RUN groupadd -r kandev && useradd -r -g kandev -u 1000 -d /data/home -M kandev
# Install azure-devops extension under the runtime user's Azure config dir on /data.
RUN mkdir -p /data/home/.azure && \
AZURE_CONFIG_DIR=/data/home/.azure az extension add --name azure-devops && \
chown -R kandev:kandev /data/home/.azure
# Create app directory structure matching what `kandev start` expects:
# /app/apps/backend/bin/kandev
RUN mkdir -p /app/apps/backend/bin /data/worktrees
# Build context layout (prepared by the release workflow from the extracted
# bundle tarball):
# bundle/bin/kandev - native Go backend (per-arch)
# bundle/bin/agentctl - native agentctl (per-arch)
# bundle/bin/agentctl-linux-amd64 - linux/amd64 agentctl helper
# bundle/bin/agentctl-darwin-arm64 - darwin/arm64 agentctl helper
# bundle/bin/agentctl-darwin-amd64 - darwin/amd64 agentctl helper
#
# The bundle's platform-specific agentctl helpers are uploaded into remote
# SSH hosts and bind-mounted into Docker-executor sandboxes by the lifecycle
# manager; ship them next to kandev so the AgentctlResolver finds them without
# manual configuration.
COPY bundle/bin/kandev /app/apps/backend/bin/kandev
COPY bundle/bin/agentctl-linux-amd64 /app/apps/backend/bin/agentctl-linux-amd64
COPY bundle/bin/agentctl-darwin-arm64 /app/apps/backend/bin/agentctl-darwin-arm64
COPY bundle/bin/agentctl-darwin-amd64 /app/apps/backend/bin/agentctl-darwin-amd64
COPY bundle/bin/agentctl /usr/local/bin/agentctl
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
# Re-apply executable bits stripped by tar/COPY edge cases, then link the native
# launcher onto PATH.
RUN chmod +x \
/app/apps/backend/bin/kandev \
/app/apps/backend/bin/agentctl-linux-amd64 \
/app/apps/backend/bin/agentctl-darwin-arm64 \
/app/apps/backend/bin/agentctl-darwin-amd64 \
/usr/local/bin/agentctl \
/usr/local/bin/docker-entrypoint.sh && \
ln -s /app/apps/backend/bin/kandev /usr/local/bin/kandev && \
chown -R kandev:kandev /app /data
# Kandev home directory (DB, worktrees, sessions, repos)
VOLUME ["/data"]
# Environment defaults for containerized operation.
# NPM_CONFIG_PREFIX points npm global installs at the PV so user-installed
# agent CLIs (claude-code, codex, auggie, ...) survive pod restarts.
ENV KANDEV_NO_BROWSER=1 \
KANDEV_HOME_DIR=/data \
KANDEV_DOCKER_ENABLED=false \
HOME=/data/home \
NPM_CONFIG_PREFIX=/data/.npm-global \
PATH=/data/.npm-global/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
HOSTNAME=0.0.0.0 \
NODE_ENV=production
WORKDIR /app
# Only the backend port is exposed; the Go backend serves API, WebSocket, and
# embedded SPA assets on the same listener.
EXPOSE 38429
# tini as PID 1 for signal handling; entrypoint handles privilege drop
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
CMD ["kandev", "start", "--backend-port", "38429", "--verbose"]