返回 CodeWhale
DOCKER.md
根目录 / docs / DOCKER.md
1 # Docker
2
3 > 阅读简体中文版:[zh_hans/DOCKER.md](zh_hans/DOCKER.md)。
4
5 Codewhale publishes a multi-arch Linux image to GitHub Container Registry
6 for each release.
7
8 ```bash
9 docker pull ghcr.io/codewhale-hq/codewhale:latest
10 ```
11
12 ## Quick start
13
14 Run the published image with a Docker-managed data volume:
15
16 ```bash
17 docker volume create codewhale-home
18
19 docker run --rm -it \
20 -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
21 -v codewhale-home:/home/codewhale/.codewhale \
22 -v "$PWD:/workspace" \
23 -w /workspace \
24 ghcr.io/codewhale-hq/codewhale:latest
25 ```
26
27 Use a pinned release tag for reproducible installs:
28
29 ```bash
30 docker run --rm -it \
31 -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
32 -v codewhale-home:/home/codewhale/.codewhale \
33 -v "$PWD:/workspace" \
34 -w /workspace \
35 ghcr.io/codewhale-hq/codewhale:vX.Y.Z
36 ```
37
38 Replace `vX.Y.Z` with a tag from
39 [GitHub Releases](https://github.com/codewhale-hq/CodeWhale/releases).
40
41 ## Default image contract
42
43 `ghcr.io/codewhale-hq/codewhale:latest` and the semver tags are conservative runtime
44 images:
45
46 - the container runs as the non-root `codewhale` user with UID/GID `1000:1000`
47 - the image does not grant passwordless `sudo`
48 - the image is meant to run Codewhale against mounted workspaces, not to mutate
49 the base operating system at runtime
50 - user state belongs in a volume mounted at `/home/codewhale/.codewhale`
51
52 That default is intentional. Keep using it for the smallest trust boundary. If a
53 project needs `apt-get`, compiler toolchains, Node/Python package managers,
54 custom CA certificates, or other host-like setup inside Docker, build an
55 explicit toolbox image instead of changing the default image contract.
56
57 ## Opt-in toolbox/custom image
58
59 The repository includes an example
60 [`docs/examples/Dockerfile.toolbox`](examples/Dockerfile.toolbox) that extends
61 the official image with passwordless `sudo` and common development packages.
62 Build it with a pinned Codewhale tag when you want repeatable project
63 environments:
64
65 ```bash
66 docker build -f docs/examples/Dockerfile.toolbox \
67 --build-arg CODEWHALE_IMAGE=ghcr.io/codewhale-hq/codewhale:vX.Y.Z \
68 --build-arg TOOLBOX_PACKAGES="git openssh-client curl build-essential pkg-config python3 python3-pip nodejs npm" \
69 -t codewhale-toolbox:my-project .
70 ```
71
72 Use `latest` only for throwaway testing. For shared projects, keep the
73 `CODEWHALE_IMAGE` value pinned and review package additions like any other
74 development-environment change.
75
76 Run the toolbox image with the same workspace and state mounts:
77
78 ```bash
79 docker volume create codewhale-my-project-home
80
81 docker run --rm -it \
82 -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
83 -v codewhale-my-project-home:/home/codewhale/.codewhale \
84 -v "$PWD:/workspace" \
85 -w /workspace \
86 codewhale-toolbox:my-project
87 ```
88
89 Inside this opt-in image, Codewhale can use commands such as
90 `sudo apt-get update` and `sudo apt-get install -y <package>`. For repeatable
91 containers, prefer baking those packages into the toolbox Dockerfile instead of
92 letting a long-lived container drift.
93
94 Do not bake API keys, SSH private keys, or other secrets into custom images.
95 Pass API keys at runtime and mount any SSH material deliberately, preferably
96 read-only and only for projects that need it.
97
98 ### Compose toolbox template
99
100 If you prefer a repeatable `docker compose` entry point, use
101 [`docs/examples/compose.toolbox.yml`](examples/compose.toolbox.yml). It builds
102 the toolbox image from [`docs/examples/Dockerfile.toolbox`](examples/Dockerfile.toolbox)
103 and keeps the project state volume explicit:
104
105 ```bash
106 CODEWHALE_IMAGE=ghcr.io/codewhale-hq/codewhale:vX.Y.Z \
107 CODEWHALE_TOOLBOX_IMAGE=codewhale-toolbox:my-project \
108 CODEWHALE_HOME_VOLUME=codewhale-my-project-home \
109 CODEWHALE_WORKSPACE="$PWD" \
110 docker compose -f docs/examples/compose.toolbox.yml run --rm codewhale
111 ```
112
113 Use a different `CODEWHALE_TOOLBOX_IMAGE` and `CODEWHALE_HOME_VOLUME` for each
114 project that needs an independent toolchain or independent `.codewhale` state.
115 The Compose file also shows opt-in, read-only mounts for SSH material and local
116 CA certificates; keep those commented out unless the project needs them.
117
118 ## Multiple independent projects
119
120 Use one named state volume per project so sessions, config, skills, memory, and
121 the offline queue do not bleed across workspaces:
122
123 ```bash
124 project="$(basename "$PWD")"
125 image="codewhale-toolbox:${project}"
126 docker volume create "codewhale-${project}-home"
127
128 docker run --rm -it \
129 --name "codewhale-${project}" \
130 -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
131 -v "codewhale-${project}-home:/home/codewhale/.codewhale" \
132 -v "$PWD:/workspace" \
133 -w /workspace \
134 "$image"
135 ```
136
137 For projects with different toolchains, build different toolbox tags, for
138 example `codewhale-toolbox:frontend` and `codewhale-toolbox:backend`. The
139 separate launcher idea discussed in issue #2217 can build on this contract, but
140 it is intentionally outside the core Docker image.
141
142 ## Project bootstrap scripts
143
144 Codewhale does not automatically execute `.codewhale/setup.sh` or legacy
145 `.deepseek/setup.sh`. If you keep one of those files as a local project recipe,
146 run it explicitly. For shared team setup, prefer a committed project script or
147 the toolbox Dockerfile so the environment can be reviewed and rebuilt.
148
149 For example, to run a committed bootstrap script before starting Codewhale:
150
151 ```bash
152 docker run --rm -it \
153 -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
154 -v codewhale-my-project-home:/home/codewhale/.codewhale \
155 -v "$PWD:/workspace" \
156 -w /workspace \
157 --entrypoint bash \
158 codewhale-toolbox:my-project \
159 -lc './scripts/bootstrap-dev.sh && exec codewhale'
160 ```
161
162 Use the toolbox image for bootstrap scripts that need `sudo`. The default image
163 will not elevate privileges.
164
165 ## Custom CA certificates and proxies
166
167 For corporate proxies, dev-sidecar, or self-signed internal services, prefer
168 baking trusted CA certificates into a custom toolbox image:
169
170 ```dockerfile
171 USER root
172 COPY docker/certs/*.crt /usr/local/share/ca-certificates/
173 RUN update-ca-certificates
174 USER codewhale
175 ```
176
177 All files copied into `/usr/local/share/ca-certificates/` must use the `.crt`
178 extension. Keep private CA material out of public images.
179
180 For a local-only run, mount certificates read-only and update the trust store at
181 container start:
182
183 ```bash
184 docker run --rm -it \
185 -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
186 -v codewhale-my-project-home:/home/codewhale/.codewhale \
187 -v "$PWD:/workspace" \
188 -v "$PWD/docker/certs:/usr/local/share/ca-certificates/local:ro" \
189 -w /workspace \
190 --entrypoint bash \
191 codewhale-toolbox:my-project \
192 -lc 'sudo update-ca-certificates && exec codewhale'
193 ```
194
195 This CA workflow requires the opt-in toolbox image because the default image
196 does not include passwordless `sudo`.
197
198 ## Local build
199
200 Build the image locally from a checkout:
201
202 ```bash
203 docker build -t codewhale .
204 ```
205
206 Then run it with the same Docker-managed data volume:
207
208 ```bash
209 docker run --rm -it \
210 -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
211 -v codewhale-home:/home/codewhale/.codewhale \
212 -v "$PWD:/workspace" \
213 -w /workspace \
214 codewhale
215 ```
216
217 Docker Hub publishing is not configured; GHCR is the supported prebuilt image
218 registry.
219
220 ## Environment variables
221
222 | Variable | Required | Description |
223 |-----------------------|----------|--------------------------------------------------|
224 | `DEEPSEEK_API_KEY` | yes | DeepSeek API key |
225 | `DEEPSEEK_BASE_URL` | no | Custom API base URL (e.g. `https://api.deepseek.com`) |
226 | `DEEPSEEK_NO_COLOR` | no | Set to `1` to disable terminal colour output |
227
228 ## Volumes
229
230 Mount `/home/codewhale/.codewhale` to persist sessions, config, skills, memory,
231 and the offline queue across container restarts. The image also keeps
232 `/home/codewhale/.deepseek` available for legacy compatibility. A
233 Docker-managed named volume is the safest default because Docker creates it with
234 ownership the container can write:
235
236 ```bash
237 -v codewhale-home:/home/codewhale/.codewhale
238 ```
239
240 Without this mount the container starts fresh each time.
241
242 If you bind-mount an existing host directory instead, the image runs as the
243 non-root `codewhale` user with UID/GID `1000:1000`. The mounted directory must be
244 writable by that user, or startup can fail while creating runtime directories
245 under `.codewhale/tasks`. On Linux hosts, either use the named volume above or
246 prepare the bind mount explicitly:
247
248 ```bash
249 mkdir -p ~/.codewhale
250 sudo chown -R 1000:1000 ~/.codewhale
251
252 docker run --rm -it \
253 -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
254 -v ~/.codewhale:/home/codewhale/.codewhale \
255 ghcr.io/codewhale-hq/codewhale:latest
256 ```
257
258 That `chown` changes ownership of the host `~/.codewhale` directory. Skip it if
259 you do not want the container UID to own your local config, and use a named
260 volume instead.
261
262 ## Non-interactive / pipeline usage
263
264 When stdin is not a TTY, `codewhale` drops to the dispatcher's one-shot mode
265 (`codewhale -c "…"`). Pipe a prompt on stdin:
266
267 ```bash
268 echo "Explain the Cargo.toml in structured English." | \
269 docker run --rm -i -e DEEPSEEK_API_KEY ghcr.io/codewhale-hq/codewhale:latest
270 ```
271
272 ## Building locally
273
274 ```bash
275 # Single platform (your host architecture)
276 docker build -t codewhale .
277
278 # Multi-platform (requires a builder with emulation)
279 docker buildx create --use
280 docker buildx build --platform linux/amd64,linux/arm64 -t codewhale .
281 ```
282
283 ## Devcontainer
284
285 The repository includes a [`.devcontainer/devcontainer.json`](../.devcontainer/devcontainer.json)
286 configuration for VS Code / GitHub Codespaces. It builds a dedicated development
287 image with the Rust toolchain, Git, `pkg-config`, and the DBus development headers
288 required by the workspace. The first open runs `cargo build --locked` and installs
289 rust-analyzer and the other editor extensions.
290
291 The source checkout remains mounted from the host. Codewhale state and Cargo build
292 artifacts use Docker named volumes instead, so the configuration works when VS Code
293 cannot provide a POSIX-style `HOME` variable (notably on Windows), and builds do not
294 write thousands of small files through a Windows bind mount. Rebuild the container
295 after changing the Dev Container configuration.
296
297 ## Release status
298
299 Docker image publishing is part of the release gate. The image is published to
300 GHCR for `linux/amd64` and `linux/arm64` with semver tags plus `latest`.
301
301 lines MARKDOWN