@@ -77,55 +77,179 @@ See [Case Study: Docker ARM64 Build Timeout](docs/case-studies/issue-7/README.md
7777
7878## Build Pipeline
7979
80+ The CI/CD pipeline uses per-image change detection for efficiency. Only images whose
81+ scripts or Dockerfiles changed are rebuilt. Unchanged images reuse the latest published version.
82+
83+ All language images are built in parallel, and the full sandbox assembles them via
84+ multi-stage ` COPY --from ` once all are ready.
85+
8086```
81- ┌─────────────────┐
82- │ detect-changes │
83- │ (ubuntu-latest) │
84- └────────┬────────┘
87+ ┌──────────────────┐
88+ │ detect-changes │ (per-image + per-language granularity)
89+ │ (ubuntu-latest) │
90+ └────────┬─────────┘
91+ │
92+ ▼
93+ ┌──────────────────┐ ← built first (base layer)
94+ │ build-js │
95+ │ (amd64 + arm64) │ (parallel per arch)
96+ └────────┬─────────┘
97+ │
98+ ▼
99+ ┌────────────────────────┐
100+ │ build-essentials │ ← built on JS sandbox
101+ │ (amd64 + arm64) │ (parallel per arch)
102+ └────────┬───────────────┘
85103 │
86- ├─────────────────────────┐
87- │ │
88- ▼ ▼
89- ┌─────────────────┐ ┌─────────────────────┐
90- │docker-build-push│ │docker-build-push- │
91- │ (amd64) │ │ arm64 │
92- │ ubuntu-latest │ │ ubuntu-24.04-arm │
93- └────────┬────────┘ │ (NATIVE - NO EMU) │
94- │ └──────────┬──────────┘
95- │ │
96- └──────────┬──────────────┘
97- │
98- ▼
99- ┌─────────────────┐
100- │ docker-manifest │
101- │ (multi-arch) │
102- └─────────────────┘
104+ ▼
105+ ┌────────────────────────────────────────────────────┐
106+ │ build-languages (matrix: 11 languages) │ ← ALL in parallel
107+ │ python, go, rust, java, kotlin, ruby, php, perl, │
108+ │ swift, lean, rocq │
109+ │ (amd64 + arm64 per language) │
110+ └────────────────────┬───────────────────────────────┘
111+ │
112+ ▼
113+ ┌────────────────────────┐
114+ │ docker-build-push │ ← full sandbox: COPY --from all language images
115+ │ (amd64 + arm64) │ (multi-stage assembly, waits for all languages)
116+ └────────┬───────────────┘
117+ │
118+ ▼
119+ ┌──────────────────┐
120+ │ manifests │ ← multi-arch manifests for js, essentials, languages, full
121+ │ (multi-arch) │
122+ └──────────────────┘
103123```
104124
125+ Each image only rebuilds if its own scripts/Dockerfiles changed, or if a dependency
126+ (common.sh, essentials) changed. The full sandbox uses ` COPY --from ` to merge
127+ pre-built language runtimes from all language images, plus ` apt install ` for
128+ system-level packages (.NET, R, C/C++, Assembly).
129+
105130## File Structure
106131
107132```
108133sandbox/
109134├── .github/
110135│ └── workflows/
111- │ └── release.yml # CI/CD workflow
112- ├── docs/
113- │ └── case-studies/
114- │ └── issue-7/ # ARM64 timeout analysis
136+ │ └── release.yml # CI/CD workflow
137+ ├── ubuntu/
138+ │ └── 24.04/
139+ │ ├── common.sh # Shared functions for all install scripts
140+ │ ├── js/ # JavaScript/TypeScript (Node.js, Bun, Deno)
141+ │ │ ├── install.sh
142+ │ │ └── Dockerfile
143+ │ ├── python/ # Python (Pyenv)
144+ │ │ ├── install.sh
145+ │ │ └── Dockerfile
146+ │ ├── go/ # Go
147+ │ │ ├── install.sh
148+ │ │ └── Dockerfile
149+ │ ├── rust/ # Rust (rustup)
150+ │ │ ├── install.sh
151+ │ │ └── Dockerfile
152+ │ ├── java/ # Java (SDKMAN, Temurin)
153+ │ │ ├── install.sh
154+ │ │ └── Dockerfile
155+ │ ├── kotlin/ # Kotlin (SDKMAN)
156+ │ │ ├── install.sh
157+ │ │ └── Dockerfile
158+ │ ├── dotnet/ # .NET SDK 8.0
159+ │ │ ├── install.sh
160+ │ │ └── Dockerfile
161+ │ ├── r/ # R language
162+ │ │ ├── install.sh
163+ │ │ └── Dockerfile
164+ │ ├── ruby/ # Ruby (rbenv)
165+ │ │ ├── install.sh
166+ │ │ └── Dockerfile
167+ │ ├── php/ # PHP 8.3 (Homebrew)
168+ │ │ ├── install.sh
169+ │ │ └── Dockerfile
170+ │ ├── perl/ # Perl (Perlbrew)
171+ │ │ ├── install.sh
172+ │ │ └── Dockerfile
173+ │ ├── swift/ # Swift 6.x
174+ │ │ ├── install.sh
175+ │ │ └── Dockerfile
176+ │ ├── lean/ # Lean (elan)
177+ │ │ ├── install.sh
178+ │ │ └── Dockerfile
179+ │ ├── rocq/ # Rocq/Coq (Opam)
180+ │ │ ├── install.sh
181+ │ │ └── Dockerfile
182+ │ ├── cpp/ # C/C++ (CMake, Clang, LLVM)
183+ │ │ ├── install.sh
184+ │ │ └── Dockerfile
185+ │ ├── assembly/ # Assembly (NASM, FASM)
186+ │ │ ├── install.sh
187+ │ │ └── Dockerfile
188+ │ ├── essentials-sandbox/ # Minimal sandbox (git identity tools)
189+ │ │ ├── install.sh
190+ │ │ └── Dockerfile
191+ │ └── full-sandbox/ # Complete sandbox (all languages)
192+ │ ├── install.sh
193+ │ └── Dockerfile
115194├── scripts/
116- │ └── ... # Build scripts
117- ├── data/
118- │ └── ... # Data files
119- ├── experiments/
120- │ └── ... # Experimental scripts
121- ├── Dockerfile # Main container definition
122- ├── README.md # Project overview
123- ├── ARCHITECTURE.md # This file
124- ├── REQUIREMENTS.md # Project requirements
125- ├── LICENSE # MIT License
126- └── package.json # Node.js metadata
195+ │ ├── ubuntu-24-server-install.sh # Legacy full installation script
196+ │ ├── entrypoint.sh # Container entrypoint
197+ │ ├── measure-disk-space.sh # Disk space measurement
198+ │ └── ... # Other scripts
199+ ├── docs/
200+ │ └── case-studies/ # Case studies
201+ ├── data/ # Data files
202+ ├── experiments/ # Experimental scripts
203+ ├── Dockerfile # Root Dockerfile (full sandbox)
204+ ├── README.md # Project overview
205+ ├── ARCHITECTURE.md # This file
206+ ├── REQUIREMENTS.md # Project requirements
207+ └── LICENSE # MIT License
127208```
128209
210+ ## Modular Design
211+
212+ The sandbox follows a modular architecture where all language images depend on
213+ ` essentials-sandbox ` , and the full sandbox assembles them via multi-stage ` COPY --from ` :
214+
215+ ```
216+ ┌─────────────────────────────────────────────────────────────┐
217+ │ JS sandbox (konard/sandbox-js) │
218+ │ └─ Node.js, Bun, Deno, npm │
219+ └─────────────────────────┬───────────────────────────────────┘
220+ │
221+ ▼
222+ ┌─────────────────────────────────────────────────────────────┐
223+ │ Essentials sandbox (konard/sandbox-essentials) │
224+ │ └─ + git, gh, glab, identity tools, dev libraries │
225+ └──┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬────┬──┬─┘
226+ │ │ │ │ │ │ │ │ │ │
227+ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
228+ Python Go Rust Java Kotlin Ruby PHP Perl Swift Lean Rocq
229+ │ │ │ │ │ │ │ │ │ │
230+ └──────┴──────┴──────┴──────┴──────┴──────┴──────┴────┴──┘
231+ │
232+ ▼
233+ ┌─────────────────────────────────────────────────────────────┐
234+ │ Full sandbox (konard/sandbox) │
235+ │ └─ COPY --from all language images │
236+ │ └─ + apt: .NET, R, C/C++, Assembly (system packages) │
237+ └─────────────────────────────────────────────────────────────┘
238+ ```
239+
240+ Each language image is also available as a standalone Docker image
241+ (e.g., ` konard/sandbox-python ` , ` konard/sandbox-go ` , etc.), each with
242+ essentials pre-installed (JS, git, gh, glab, dev libraries).
243+
244+ ### Benefits
245+
246+ 1 . ** Configurable disk usage** : Users can choose only the languages they need
247+ 2 . ** Parallel CI/CD** : All language images are built in parallel
248+ 3 . ** Faster iteration** : Changes to one language only rebuild that image
249+ 4 . ** Efficient assembly** : Full sandbox uses ` COPY --from ` to merge pre-built files
250+ 5 . ** No dependency conflicts** : Each language builds in isolation on essentials
251+ 6 . ** Standalone scripts** : Each ` install.sh ` works directly on Ubuntu 24.04 via ` curl | bash `
252+
129253## Design Decisions
130254
131255### 1. Non-Root User
0 commit comments