- Home
- Dev Container
- Local Development
Local Development
This page is for developers who want to clone the repository, build the image locally, or customize the Dockerfile. If you just want to use the pre-built container, see Getting Started.
Clone the Repository
Section titled “Clone the Repository”git clone https://github.com/f5xc-salesdemos/devcontainer.gitcd devcontainerProject Structure
Section titled “Project Structure”.├── Dockerfile # Multi-stage image build├── docker-compose.yml # Base compose — pulls pre-built image├── docker-compose.build.yml # Build override — use explicitly with -f├── .devcontainer/ # VS Code Dev Container config│ └── devcontainer.json├── entrypoint.sh # Container startup script├── .env.example # Example environment variables├── docs/ # Documentation site (Starlight)├── claude-config/ # Claude Code configuration files├── opencode-config/ # OpenCode provider templates (OAuth + LiteLLM)└── codex-config/ # Codex configurationBuild File
Section titled “Build File”The docker-compose.build.yml file adds local build support. It is not auto-merged — you must pass it explicitly with -f flags. This means docker compose up -d (or podman-compose up -d) always pulls the pre-built image from GHCR, whether you cloned the repo or not.
You can verify that a plain docker compose up uses only the pre-built image (no build: context):
docker compose configCompare with the explicit build configuration:
docker compose -f docker-compose.yml -f docker-compose.build.yml configYou can verify that a plain podman-compose up uses only the pre-built image (no build: context):
podman-compose configCompare with the explicit build configuration:
podman-compose -f docker-compose.yml -f docker-compose.build.yml configBuilding Locally
Section titled “Building Locally”docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --buildpodman-compose -f docker-compose.yml -f docker-compose.build.yml up -d --buildThis merges the build file with the base compose file, builds the image from the local Dockerfile, and starts the container. The --build flag forces a rebuild even if a cached image exists.
Two-Stage Build Architecture
Section titled “Two-Stage Build Architecture”The Dockerfile uses a two-stage build optimized for Docker layer caching:
Stage 1: deps (stable foundations, ~4.5 GB)
Section titled “Stage 1: deps (stable foundations, ~4.5 GB)”These layers only rebuild when a version ARG is bumped or APT packages change. On typical tool-only changes, BuildKit skips this entire stage.
| Section | Contents |
|---|---|
| 1. APT repos | NodeSource, deadsnakes, HashiCorp, GitHub, Docker, Microsoft, Google Cloud, Dart SDK |
| 2. APT packages | System tools, Node.js, Python, Java, Terraform, GitHub CLI, Docker engine, Azure CLI, PowerShell, locales |
| 2b. Security APT packages | Network analysis, web scanners, password tools, reverse engineering, forensics (~80 packages) |
| 3. Python bootstrap | Symlinks + pip via get-pip.py |
| 4. Go | Official tarball (latest stable, resolved at build time) |
| 5. Rust | rustup (system-wide, latest stable) |
| 6. Maven + Gradle | Binary downloads to /opt |
| 7. VNC stack | Xvfb, x11vnc, noVNC, fluxbox — remote display via browser |
| 8. Nerd Fonts | JetBrainsMono, Hack, FiraCode (latest releases) |
Stage 2: final (volatile tools + user setup, ~1.5 GB)
Section titled “Stage 2: final (volatile tools + user setup, ~1.5 GB)”These layers change more frequently (npm/pip updates, config changes) but rebuild quickly because the heavy deps stage is cached.
| Section | Contents |
|---|---|
| 9. AWS CLI v2 | Official installer |
| 10. Binary tools | kubectl, helm, tflint, terraform-docs, act, actionlint, yt-dlp, uv, opencode |
| 10b. Additional binaries | VS Code CLI, oc, yq, terragrunt, ibmcloud, fzf, hadolint, codex |
| 10c. Super-linter binaries | shfmt, gitleaks, editorconfig-checker, clj-kondo, dotenv-linter, golangci-lint, goreleaser, kubeconform, protolint, scalafmt, ktlint |
| 10d. Java JAR tools | checkstyle, google-java-format (wrapper scripts) |
| 10e. PHP linters | phpcs, phpstan, psalm (PHAR downloads) |
| 10f. PowerShell modules | PSScriptAnalyzer, arm-ttk |
| 10g. Security binaries | nuclei, subfinder, httpx, ffuf, gobuster, feroxbuster, dalfox, amass, trufflehog, grype, syft, bettercap (amd64) |
| 10h. OWASP ZAP | Java-based web application scanner |
| 10i. Ghidra | Reverse engineering framework |
| 10j. Metasploit | Exploitation framework (amd64 only) |
| 11. npm global tools | claude-code, prettier, markdownlint-cli2, devcontainers-cli, playwright, pi-coding-agent |
| 12. pip tools | pre-commit, ansible, black, pylint, yamllint, playwright |
| 12c. Ruby linters | rubocop + extensions |
| 12e. Perl linter modules | Perl::Critic extensions |
| 12f. Lua linter | luacheck |
| 12g. R linter | lintr |
| 12h. Security Ruby gems | wpscan, evil-winrm |
| 12i. Git-cloned security tools | testssl.sh, exploitdb (searchsploit), SecLists, docker-bench-security, recon-ng, spiderfoot |
| 13. Playwright browsers | Chromium + system deps via playwright install --with-deps |
| 13b. Chrome DevTools MCP | Chrome symlink + MCP pre-cache + headless patch |
| 14. Homebrew | Linuxbrew (AI assistant deps + formatters) |
| 14b. Aider | uv tool install with Python 3.12 (browser, help, playwright extras) |
| 15. ZSH plugins | oh-my-zsh custom plugins |
| 16. Shell bootstrap | npm-global, tfenv, compinit |
| 17. Claude Code + OpenCode + Codex config | Tool awareness memory, managed policy, self-test script, OpenCode provider templates, Codex config |
| 18. Entrypoint | Container startup script (absolute last COPY) |
Adding Tools
Section titled “Adding Tools”Edit the Dockerfile and add your tool to the appropriate section. Rebuild after adding:
docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --buildpodman-compose -f docker-compose.yml -f docker-compose.build.yml up -d --buildOr in VS Code: Dev Containers → Rebuild Container.
APT packages
Section titled “APT packages”Add to the section 2 apt-get install block:
RUN apt-get update && apt-get install -y --no-install-recommends \ your-package-here \ && apt-get clean \ && rm -rf /var/lib/apt/lists/*npm tools
Section titled “npm tools”Add to the section 11 npm install -g block:
RUN npm install -g \ your-npm-toolpip tools
Section titled “pip tools”Add to the section 12 pip install block:
RUN pip install --no-cache-dir --break-system-packages \ your-python-toolBinary downloads
Section titled “Binary downloads”Add to section 10 or create a new RUN layer with architecture detection:
RUN ARCH=$(dpkg --print-architecture) \ && curl -fsSL "https://example.com/tool-linux-${ARCH}.tar.gz" \ | tar -xz -C /usr/local/bin toolBuild Cache
Section titled “Build Cache”CI uses registry-based caching — build layers are stored in GHCR (ghcr.io/f5xc-salesdemos/devcontainer:cache-*) instead of the GitHub Actions cache. This avoids the 10 GB GHA cache limit that caused frequent full rebuilds for this ~6 GB multi-architecture image.
The two-stage architecture works with the registry cache so that:
- Tool version bumps (npm, pip, binary tools) — rebuild only the
finalstage (~5 min) - Config file changes (
claude-config/,entrypoint.sh) — rebuild only the last few layers (~1 min) - Foundation changes (APT packages, Go/Rust/Java versions) — full rebuild of both stages (~30 min)