Skip to content

Commit 1860452

Browse files
chapterjasonclaude
andcommitted
Add cross-owner shared volume auto-mounted into every devcontainer
Introduces docker_volume.shared (fixed name, no per-owner suffix) mounted at /mnt/shared on every workspace container with sticky-bit 1777 so any user can drop files but only the owner can delete them. A shim in front of @devcontainers/cli injects --mount for /mnt/shared on every up/build, so projects pick up the drop box with zero devcontainer.json edits. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b37e766 commit 1860452

3 files changed

Lines changed: 49 additions & 1 deletion

File tree

Dockerfile.workspace

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,22 @@ RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \
5757

5858
# Pre-install @devcontainers/cli globally so the Coder module doesn't need
5959
# to (which fails for non-root users installing to /usr/lib/node_modules).
60-
RUN npm install -g @devcontainers/cli
60+
RUN npm install -g @devcontainers/cli && \
61+
mv /usr/bin/devcontainer /usr/bin/devcontainer.real
62+
63+
# Shim the devcontainer CLI to auto-inject deployment-wide mounts on every
64+
# `up` / `build`, so individual projects don't have to declare them in their
65+
# devcontainer.json. Currently injects /mnt/shared (see docker_volume.shared
66+
# in main.tf) — a cross-owner drop box mounted on every workspace container.
67+
RUN cat > /usr/bin/devcontainer <<'EOF' && chmod +x /usr/bin/devcontainer
68+
#!/bin/bash
69+
set -eu
70+
extra=()
71+
if [[ "${1:-}" == "up" || "${1:-}" == "build" ]]; then
72+
extra+=(--mount "type=bind,source=/mnt/shared,target=/mnt/shared")
73+
fi
74+
exec /usr/bin/devcontainer.real "$@" "${extra[@]}"
75+
EOF
6176

6277
# Pre-populate system known_hosts for common git forges so SSH clones don't
6378
# race the agent's ssh-keyscan startup step.

docs/persistence.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ Compared to a whole-home mount: narrower blast radius, no first-run skeleton
1111
seeding, no drift between the image's `/etc/skel` and the live `$HOME`, no
1212
cross-tool leakage between workspaces.
1313

14+
> **Not persistence, but related — `/mnt/shared`.** A single deployment-wide
15+
> docker volume (`docker_volume.shared` in `main.tf`) is mounted at
16+
> `/mnt/shared` on every workspace and auto-injected into every devcontainer
17+
> by the `devcontainer` CLI shim in `Dockerfile.workspace`. No
18+
> `devcontainer.json` edits needed. Sticky-bit 1777 (like `/tmp`) — anyone
19+
> can drop files, only the owner can delete them. Use it as a cross-user
20+
> drop box, not for per-user state.
21+
1422
## The three moving parts
1523

1624
1. **The volume + bind mount.** In `.devcontainer/devcontainer.json`:

main.tf

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ resource "coder_agent" "main" {
113113
# mounted the volume but keeps this idempotent if the mount path moves.
114114
sudo mkdir -p /mnt/home-persist
115115
sudo chown "$DEVCONTAINER_USER_UID:$DEVCONTAINER_USER_GID" /mnt/home-persist
116+
117+
# /mnt/shared is the deployment-wide shared volume (see docker_volume.shared).
118+
# Single docker volume attached to every workspace, every owner — a drop box
119+
# for moving files between users. Sticky-bit 1777 (like /tmp) so anyone can
120+
# write but only the file's owner can delete it.
121+
sudo mkdir -p /mnt/shared
122+
sudo chmod 1777 /mnt/shared
116123
EOT
117124
shutdown_script = ""
118125
dir = data.coder_parameter.directory.value
@@ -392,6 +399,17 @@ resource "docker_volume" "home_persist" {
392399
}
393400
}
394401

402+
# Deployment-wide shared volume. A single docker volume — fixed name, no per-owner
403+
# or per-workspace suffix — attached to every workspace container. Acts as a drop
404+
# box for moving files between users. Mounted at /mnt/shared with sticky-bit 1777
405+
# (see startup_script) so anyone can write but only the file's owner can delete it.
406+
resource "docker_volume" "shared" {
407+
name = "coder-shared"
408+
lifecycle {
409+
ignore_changes = all
410+
}
411+
}
412+
395413
resource "docker_volume" "home_volume" {
396414
name = "coder-${data.coder_workspace.me.id}-home"
397415
# Protect the volume from being deleted due to changes in attributes.
@@ -477,6 +495,13 @@ resource "docker_container" "workspace" {
477495
read_only = false
478496
}
479497

498+
# Deployment-wide shared drop box. Same volume on every workspace, every owner.
499+
volumes {
500+
container_path = "/mnt/shared"
501+
volume_name = docker_volume.shared.name
502+
read_only = false
503+
}
504+
480505
# Add labels in Docker to keep track of orphan resources.
481506
labels {
482507
label = "coder.owner"

0 commit comments

Comments
 (0)