# metabuilder/devcontainer # # All-in-one development container: every build tool, language runtime, # package manager cache, and software 3D renderer in a single image. # # Layers (in order): # base-conan-deps → all apt packages + all Conan C++ packages # base-node-deps → all npm workspace packages (copied in) # base-pip-deps → all Python pip packages (copied in) # base-android-sdk → Android SDK 34 + Gradle (copied in) # + Rust / Cargo # + Go 1.22 # + Mesa software renderer (CPU-powered headless 3D/GL/Vulkan) # + oh-my-zsh + dev comforts # # Build: docker build -f Dockerfile.devcontainer -t metabuilder/devcontainer:latest ../../ # VS Code: "image": "metabuilder/devcontainer:latest" in devcontainer.json ARG BASE_REGISTRY=metabuilder FROM ${BASE_REGISTRY}/base-node-deps:latest AS node-deps FROM ${BASE_REGISTRY}/base-pip-deps:latest AS pip-deps FROM ${BASE_REGISTRY}/base-android-sdk:latest AS android-sdk FROM ${BASE_REGISTRY}/base-conan-deps:latest # ── Node.js (from base-node-deps) ───────────────────────────────────────────── # Copy pre-installed node_modules + node binary from base-node-deps image COPY --from=node-deps /usr/local/bin/node /usr/local/bin/node COPY --from=node-deps /usr/local/bin/npm /usr/local/bin/npm COPY --from=node-deps /usr/local/bin/npx /usr/local/bin/npx COPY --from=node-deps /usr/local/lib/node_modules /usr/local/lib/node_modules COPY --from=node-deps /app/node_modules /workspace/node_modules # ── Python packages (from base-pip-deps) ────────────────────────────────────── # Copy entire site-packages + all pip-installed binaries in one go. # Avoids hard-coding individual binary paths (gunicorn, celery, etc.). COPY --from=pip-deps /usr/local/lib/python3.14 /usr/local/lib/python3.14 COPY --from=pip-deps /usr/local/bin/ /usr/local/bin/ # ── Android SDK + Gradle (from base-android-sdk) ────────────────────────────── COPY --from=android-sdk /opt/android-sdk /opt/android-sdk COPY --from=android-sdk /opt/gradle /opt/gradle COPY --from=android-sdk /root/.gradle /root/.gradle ENV ANDROID_HOME=/opt/android-sdk \ ANDROID_SDK_ROOT=/opt/android-sdk \ GRADLE_HOME=/opt/gradle/gradle-8.12 # ── Rust + Cargo ────────────────────────────────────────────────────────────── ENV CARGO_HOME=/opt/cargo \ RUSTUP_HOME=/opt/rustup \ PATH=/opt/cargo/bin:$PATH RUN for i in 1 2 3 4 5; do \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ | sh -s -- -y --no-modify-path \ --default-toolchain stable \ --component rust-analyzer,clippy,rustfmt \ && break \ || (echo "rustup failed (attempt $i/5), retrying in $((i*10))s..." && sleep $((i*10))); \ done # ── Go 1.22 ─────────────────────────────────────────────────────────────────── ENV GOROOT=/opt/go \ GOPATH=/opt/gopath \ PATH=/opt/go/bin:/opt/gopath/bin:$PATH RUN GO_VERSION=1.22.6 && \ ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \ for i in 1 2 3 4 5; do \ wget -q "https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz" -O /tmp/go.tar.gz && \ tar -C /opt -xzf /tmp/go.tar.gz && \ rm /tmp/go.tar.gz \ && break \ || (echo "Go download failed (attempt $i/5), retrying in $((i*10))s..." \ && rm -f /tmp/go.tar.gz && sleep $((i*10))); \ done # ── Mesa software 3D renderer (CPU-powered, no GPU required) ────────────────── # Enables OpenGL, Vulkan (llvmpipe), EGL in headless Docker environments. # Set LIBGL_ALWAYS_SOFTWARE=1 to force software rendering at runtime. RUN for i in 1 2 3 4 5; do \ apt-get update && apt-get install -y --no-install-recommends \ libgl1 \ libglx-mesa0 \ libgl1-mesa-dri \ mesa-utils \ mesa-vulkan-drivers \ vulkan-tools \ libegl1 \ libegl-mesa0 \ libgles2 \ xvfb \ x11-utils \ && break \ || (echo "apt-get (mesa) failed (attempt $i/5), retrying in $((i*10))s..." && sleep $((i*10))); \ done && rm -rf /var/lib/apt/lists/* # Runtime env: always use software renderer in containers ENV LIBGL_ALWAYS_SOFTWARE=1 \ MESA_LOADER_DRIVER_OVERRIDE=softpipe \ GALLIUM_DRIVER=softpipe \ VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.x86_64.json # ── zsh + oh-my-zsh + shell comforts ────────────────────────────────────────── # Install zsh first (required by oh-my-zsh and the SHELL directive below). RUN apt-get update && apt-get install -y --no-install-recommends zsh \ && rm -rf /var/lib/apt/lists/* RUN for i in 1 2 3 4 5; do \ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" \ "" --unattended \ && break \ || (echo "oh-my-zsh failed (attempt $i/5), retrying in $((i*10))s..." && sleep $((i*10))); \ done COPY --from=android-sdk /usr/lib/jvm /usr/lib/jvm ENV JAVA_HOME=/usr/lib/jvm/default-java # ── PATH consolidation ──────────────────────────────────────────────────────── ENV PATH=/opt/gradle/gradle-8.12/bin:/opt/android-sdk/cmdline-tools/latest/bin:/opt/android-sdk/platform-tools:/opt/cargo/bin:/opt/go/bin:/opt/gopath/bin:/usr/local/bin:$PATH WORKDIR /workspace SHELL ["/bin/zsh", "-c"] LABEL org.metabuilder.image="devcontainer" \ org.metabuilder.description="All-in-one dev container: C++/Conan, Node/npm, Python/pip, Android/Gradle, Rust, Go, Mesa software 3D"