Architecture
Overview
Section titled “Overview”Infrashift DevContainer Features follow a layered architecture: a base Containerfile provides the foundation, and each feature uses a standardized install pipeline of shell → Ansible → tool installation.
Base Image Pipeline
Section titled “Base Image Pipeline”┌─────────────────────────────────┐│ Red Hat UBI 9 (ubi:latest) │├─────────────────────────────────┤│ dnf update ││ Create vscode user (1000:1000) ││ Install UV bootstrapper │└─────────────────────────────────┘The base Containerfile (.devcontainer/Containerfile) starts from UBI9, creates the vscode user, and installs UV as the sole bootstrap dependency. UV enables Ansible execution without permanently installing ansible-core.
Feature Install Pipeline
Section titled “Feature Install Pipeline”Each feature follows the same three-stage pipeline:
install.sh → uv run ansible-playbook → activate-feature.ymlStage 1: install.sh
Section titled “Stage 1: install.sh”The install.sh script runs as root during container build. It’s a thin wrapper that:
- Validates that UV is available
- Reads feature options from environment variables (set by the Dev Container runtime)
- Invokes
uv run --with ansible-core ansible-playbookwith feature-specific extra variables
Stage 2: UV Ephemeral Environment
Section titled “Stage 2: UV Ephemeral Environment”UV creates a temporary virtual environment, installs ansible-core into it, and runs the playbook. This avoids permanently installing ansible-core in the image.
Stage 3: Ansible Playbook
Section titled “Stage 3: Ansible Playbook”The activate-feature.yml playbook contains the actual installation logic:
- Download binaries from official sources
- Verify SHA256 checksums (when provided)
- Extract and install to user-scoped directories
- Set file permissions for the vscode user
Directory Layout
Section titled “Directory Layout”src/├── <feature-id>/│ ├── devcontainer-feature.json # Feature metadata and options│ ├── install.sh # Entry point (called by runtime)│ ├── activate-feature.yml # Ansible playbook│ └── hosts.yml # Ansible inventory (localhost)test/├── <feature-id>/│ ├── test.sh # Autogenerated test script│ └── scenarios.json # Scenario test definitionsInstallation Paths
Section titled “Installation Paths”Features install software into user-scoped directories under /home/vscode/:
| Path | Purpose |
|---|---|
~/.local/bin | CLI binaries (jq, yq, grype, syft, etc.) |
~/.local/share/go | Go installation |
~/.local/share/nodejs | Node.js installation |
~/.local/share/java | OpenJDK installation |
~/.local/share/dotnet | .NET SDK installation |
~/.local/share/pnpm | pnpm home directory |
~/.local/share/gopath | Go workspace (GOPATH) |
~/.bun/bin | Bun global installs (Claude Code, OpenAI Codex) |
Dependency Graph
Section titled “Dependency Graph”bun ──→ claude-code └─→ openai-codex
nodejs ──→ npm └──→ pnpm
golang ──→ cuelang
uv-ruff ──→ python ──→ ansible-core
git ──→ git-lfsFeatures use installsAfter declarations to ensure correct installation order. The Dev Container runtime resolves the dependency graph automatically.
CI/CD Pipeline
Section titled “CI/CD Pipeline”The test pipeline (.github/workflows/test-all.yaml) runs three test stages:
- Autogenerated tests: Each feature is tested in isolation against a UBI9 base image
- Scenario tests: Features with dependencies are tested in combination
- Global integration: All features are tested together in a single container
Each test stage builds the UBI9 base image from the Containerfile, then uses devcontainers/ci to run the tests.