Your all-in-one dev environment: reproducible builds, universal tooling, and cohesive DX. π οΈβ¨
UBI (Universal Base Image) is the baseline container environment for all Ego Hygiene projects. It provides a reproducible, stable, and developer-experience-optimized foundation that every devcontainer and project in the organization builds upon.
Instead of each project maintaining its own environment setup, UBI serves as the single source of truth β ensuring:
- Consistency: Every developer works in an identical environment
- Reproducibility: Builds are deterministic and versioned
- Developer Happiness: Pre-configured with sensible defaults and modern tooling
- Maintainability: Update the base once, benefit everywhere
UBI is distributed via GitHub Container Registry (GHCR) and consumed by other repositories as their base image.
-
ποΈ Fully XDG-Aligned Filesystem Adheres to the XDG Base Directory Specification for predictable configuration and data locations.
-
π
/opt/universal/*Hierarchy Standardized paths for binaries, configs, caches, logs, and more:/opt/universal/bin- Universal binaries/opt/universal/config- Configuration files (XDG_CONFIG_HOME)/opt/universal/cache- Cache directory (XDG_CACHE_HOME)/opt/universal/toolbox- Data files (XDG_DATA_HOME)/opt/universal/runtime- Runtime state (XDG_STATE_HOME)/opt/universal/logs- Centralized logs/opt/universal/apps- Application resources- And more...
-
βοΈ Predictable Runtime Environment Pre-configured environment variables for consistent behavior across:
- Locale and timezone settings
- Editor and pager preferences (VS Code, less)
- Color and terminal settings
- Python, Node.js, and Rust configurations
- Telemetry opt-outs for privacy
-
ποΈ Configurable via Build Arguments Customize behavior at build time with Docker ARGs for locale, timezone, editor preferences, and more.
-
π Reproducible Builds & Semantic Versioning Every release is tagged with a semantic version, ensuring immutable and auditable deployments.
-
ποΈ Multi-Architecture Support Native support for multiple CPU architectures:
linux/amd64(x86_64) - Intel/AMD processorslinux/arm64(ARM64) - Apple Silicon (M1/M2/M3), AWS Graviton, Raspberry Pi
Docker automatically pulls the correct architecture for your platform. To verify or explicitly specify:
docker pull --platform=linux/arm64 ghcr.io/egohygiene/ubi:latest
-
π₯ Built-in Health Checks All variants include Docker HEALTHCHECK instructions for improved observability and runtime stability:
- Validates essential tools (bash, python3, node) are operational
- Enables container orchestrators to monitor and restart unhealthy containers
- Improves CI testing accuracy with health status validation
-
π¦ Distributed via GHCR Pull from GitHub Container Registry for fast, reliable access:
ghcr.io/egohygiene/ubi -
π Optimized for Developer Experience Sensible defaults that "just work" β less configuration, more productivity.
UBI provides multiple image variants optimized for different use cases:
- Base (
ubi:latest) - Default general-purpose image - Minimal (
ubi:latest-minimal) - Lightweight with only essentials - Python (
ubi:latest-python) - Includes Python, pip, poetry, pyenv - Node (
ubi:latest-node) - Includes Node.js, npm, pnpm, yarn, nvm - Full (
ubi:latest-full) - All tools and runtimes included
π See the full variants documentation β
The simplest way to consume UBI is via a devcontainer configuration:
{
"name": "My Project",
"image": "ghcr.io/egohygiene/ubi:latest",
"features": {
// Add your devcontainer features here
}
}Or use a specialized variant:
{
"name": "My Python Project",
"image": "ghcr.io/egohygiene/ubi:latest-python",
"features": {
// Add your devcontainer features here
}
}Build your project-specific image on top of UBI:
FROM ghcr.io/egohygiene/ubi:0.1.5
# Install project-specific dependencies
RUN apt-get update && apt-get install -y \
your-package-here
# Copy your application code
COPY . /workspace
# Set up your project
RUN npm install # or pip install, cargo build, etc.Or use a specialized variant:
FROM ghcr.io/egohygiene/ubi:0.1.5-python
# Your Python project is ready to go!
COPY . /workspace
RUN poetry installdocker pull ghcr.io/egohygiene/ubi:latestdocker run -it --rm ghcr.io/egohygiene/ubi:latest bashWant to see UBI in action? Check out our example projects:
- Python CLI - Command-line tool with Click
- Node.js Express - REST API server
- Polyglot - Multi-language project (Python + Node.js + Bash)
Each example is fully documented and ready to run. They demonstrate:
- Real-world usage patterns
- XDG directory compliance
- Modern development workflows
- Multi-language support
UBI images are signed with Sigstore Cosign using keyless signing. This provides cryptographic proof that images are authentic and haven't been tampered with.
# macOS
brew install cosign
# Linux
curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
sudo chmod +x /usr/local/bin/cosign
# Or use the official container
alias cosign="docker run --rm gcr.io/projectsigstore/cosign:latest"To verify the signature of a UBI image:
# Verify the latest image
cosign verify \
--certificate-identity-regexp="https://github.com/egohygiene/ubi/" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
ghcr.io/egohygiene/ubi:latest
# Verify a specific version
cosign verify \
--certificate-identity-regexp="https://github.com/egohygiene/ubi/" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
ghcr.io/egohygiene/ubi:0.1.5
# Verify by digest (most secure)
cosign verify \
--certificate-identity-regexp="https://github.com/egohygiene/ubi/" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
ghcr.io/egohygiene/ubi@sha256:<digest>What does this verify?
- β The image was built by an official UBI GitHub Actions workflow
- β The image hasn't been modified since signing
- β The signature is backed by Sigstore's transparency log
- β The build is traceable to a specific GitHub workflow run
Note: Verification will fail if the image has been tampered with or wasn't signed by an official workflow. This is a security feature, not a bug!
UBI follows Semantic Versioning (SemVer): MAJOR.MINOR.PATCH
- MAJOR: Breaking changes to the environment or filesystem structure
- MINOR: New features, tools, or non-breaking enhancements
- PATCH: Bug fixes and minor updates
UBI uses semantic-release for fully automated versioning, CHANGELOG generation, and GitHub releases based on Conventional Commits. This means:
- Commits with
feat:trigger minor version bumps - Commits with
fix:,perf:, orrefactor:trigger patch version bumps - Commits with
BREAKING CHANGE:trigger major version bumps - Version, CHANGELOG, and GitHub releases are automatically managed
See CONTRIBUTING.md for details on the release workflow.
The current version is defined in the VERSION file at the root of this repository (for example 0.1.0):
Every release publishes multiple tags to GHCR:
ghcr.io/egohygiene/ubi:latestβ Always points to the most recent stable releaseghcr.io/egohygiene/ubi:0.1.0β Specific version for pinned deploymentsghcr.io/egohygiene/ubi:sha-<commit>β Git commit SHA for exact reproducibility
Recommendation: Use specific version tags (e.g., 0.1.0) in production and latest for development.
For detailed release notes and change history, see the CHANGELOG.md.
UBI is built on top of the official Microsoft DevContainers base image, which provides a solid foundation with common development tools.
- Base Image:
mcr.microsoft.com/devcontainers/base:2.1.2(pinned with digest for reproducibility) - Environment Configuration: Extensive ENV vars for consistent behavior
- XDG Directory Structure:
/opt/universal/*hierarchy - Build Arguments: Customizable settings at build time
- Multi-Stage Build: Organized into
base,environment, andfinalstages
The image is automatically built and published via GitHub Actions on every push to main or when the VERSION file changes. See .github/workflows/publish.yml for details.
For detailed architecture documentation, see docs/architecture.md.
To build UBI locally:
docker build -f .devcontainer/Dockerfile -t ubi:local .- Build the image locally
- Update your devcontainer to use
ubi:local - Rebuild your devcontainer and test your changes
- Once validated, update
VERSIONand push to trigger a new release
UBI's base image is pinned to a specific version with a digest for reproducibility and stability. To update it:
Visit the official sources to find the latest stable version:
-
GitHub Releases: devcontainers/images releases
-
MCR Tag List: Query available tags from the Microsoft Container Registry API:
# List all available tags (returns JSON) curl -s https://mcr.microsoft.com/v2/devcontainers/base/tags/list | jq -r '.tags[]' # Or filter for version tags only curl -s https://mcr.microsoft.com/v2/devcontainers/base/tags/list | \ jq -r '.tags[] | select(. | test("^[0-9]+\\.[0-9]+"))' | sort -V | tail -10
-
Docker Hub Alternative: Search directly with Docker:
docker search mcr.microsoft.com/devcontainers/base
# Pull the desired version
docker pull mcr.microsoft.com/devcontainers/base:<version>
# Get the digest
docker inspect mcr.microsoft.com/devcontainers/base:<version> \
--format='{{index .RepoDigests 0}}'Edit .devcontainer/Dockerfile and update the FROM line with:
- The new version tag
- The corresponding digest (from step 2)
- The
LAST UPDATEDdate in the comment block
# Build with no cache to ensure clean build
docker build -f .devcontainer/Dockerfile -t ubi:test . --no-cache
# Test the container
docker run -it --rm ubi:test bash- Update the base image version in
README.md(Architecture > Key Components) - Document the base image update in
CHANGELOG.mdby creating a new version section or note the change in your PR description for the maintainers to include in the next release - Document any breaking changes or notable updates from the upstream base image
Evaluate base image updates when:
- Security patches are released (high priority)
- New stable versions are available (evaluate breaking changes)
- Quarterly review (best practice for staying current)
- CI/CD issues arise from upstream changes (investigate and update if needed)
Note: Always review the devcontainers release notes before updating to understand what's changing.
UBI includes automated base image monitoring that runs daily to check for new releases:
- Workflow:
.github/workflows/monitor-base-image.yml - Schedule: Daily at 00:00 UTC
- Actions: Automatically creates PRs when updates are detected
- Security: Includes Trivy vulnerability scans of new base images
- Coverage: Updates all Dockerfiles (main + variants) simultaneously
When the monitoring workflow detects a new base image version:
- It automatically creates a PR with all Dockerfile updates
- Runs a Trivy security scan on the new base image
- Uploads scan results to GitHub Security and workflow artifacts
- Includes version change details and security assessment in the PR
This automation complements Dependabot and provides specialized handling for the critical base image dependency. See CONTRIBUTING.md for details.
UBI includes automated container vulnerability scanning using Trivy to ensure supply chain security and detect CVEs in the base image and dependencies.
The Trivy scanner runs automatically on:
- Pull Requests: Every PR is scanned to catch vulnerabilities before merging
- Push to main: Scans verify security after each merge
- Weekly Schedule: Every Monday at 00:00 UTC for continuous monitoring
- Manual Trigger: Can be run on-demand via GitHub Actions
- Base image layers and OS packages
- Installed system dependencies
- Known CVEs from the National Vulnerability Database (NVD)
The workflow:
- Builds the UBI image from the Dockerfile
- Scans it with Trivy for vulnerabilities
- Fails the build if critical or high-severity CVEs are found
- Uploads results to GitHub Security tab (SARIF format)
- Generates a human-readable report available as an artifact
GitHub Security Tab: View all detected vulnerabilities at:
https://github.com/egohygiene/ubi/security/code-scanning
Workflow Artifacts: Download detailed reports from the Trivy Scan workflow runs.
To scan the UBI image locally before pushing changes:
# macOS
brew install trivy
# Linux
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update && sudo apt-get install trivy
# Or use Docker
docker pull aquasec/trivy:latestdocker build -f .devcontainer/Dockerfile -t ubi:local .# Basic scan (CRITICAL and HIGH only)
trivy image --severity CRITICAL,HIGH ubi:local
# Detailed scan (all severities)
trivy image ubi:local
# Generate a report
trivy image --format table --output trivy-report.txt ubi:local
# Or using Docker
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy:latest image --severity CRITICAL,HIGH ubi:local# Scan the latest published image
trivy image ghcr.io/egohygiene/ubi:latest
# Scan a specific version
trivy image ghcr.io/egohygiene/ubi:0.1.5If the scan detects vulnerabilities:
- Review the findings: Check if they're false positives or real issues
- Update dependencies: Bump versions of affected packages if patches are available
- Update base image: Check if a newer version of the DevContainers base image has fixes
- Document exceptions: If a vulnerability can't be fixed immediately, document why and track it
- Pin base image versions with digests for reproducibility (already implemented)
- Regularly update the base image to get security patches
- Monitor the Security tab for new vulnerabilities
- Subscribe to notifications for the repository to get alerts
- Review weekly scan results to stay proactive
UBI includes automated metrics collection to track image size, build performance, and layer distribution over time. This helps identify performance regressions, optimize image size, and monitor build trends.
-
Image Size Metrics:
- Compressed and uncompressed size per architecture (amd64, arm64)
- Layer count and distribution
- Size trends over time
-
Build Metadata:
- Version, commit SHA, and timestamp
- Workflow run information
- Build duration and runner details
-
Layer Analysis:
- Per-layer size breakdown
- Command history for each layer
- Identification of largest layers for optimization
Metrics are automatically collected on every tagged release and push to main:
- Workflow Artifacts: Download from the Metrics Workflow runs
- Historical Data: View the
metrics/build-metrics.jsonlfile for trends - Detailed Reports: Check version-specific reports in the
metrics/directory
Each build generates:
- JSON Report (
metrics-report.json): Complete metrics in structured format - Markdown Report (
metrics-report.md): Human-readable summary - Layer Breakdown (
layers-amd64.json): Detailed layer analysis - Historical Log (
build-metrics.jsonl): Append-only history in JSON Lines format
# View latest metrics
tail -1 metrics/build-metrics.jsonl | jq '.'
# Compare sizes over time
jq -r '[.version, .timestamp, .amd64_size_mb] | @tsv' metrics/build-metrics.jsonl
# Find largest build
jq -s 'max_by(.amd64_size_mb | tonumber)' metrics/build-metrics.jsonl
# Track layer count trends
jq -r '[.version, .amd64_layer_count] | @tsv' metrics/build-metrics.jsonlYou can manually trigger metrics collection:
- Go to Actions β π Collect Build Metrics & Observability Data
- Click Run workflow
- Optionally enable commit_metrics to save results to the repository
See the metrics documentation for more details.
UBI includes automated performance benchmarking to track container startup times, resource usage, and overall performance characteristics across releases. This helps detect performance regressions and validate optimizations.
-
Startup Performance:
- Cold start time (no cached layers)
- Warm start time (cached layers)
- Time to first command execution
-
Resource Usage:
- CPU utilization during startup
- Memory footprint at idle
- Resource efficiency metrics
-
Image Characteristics:
- Compressed and uncompressed size
- Layer count and distribution
- Per-architecture metrics (amd64, arm64)
Benchmarks can be triggered manually or run automatically on tagged releases:
- Go to Actions β β‘ Performance Benchmarking
- Click Run workflow
- Select the branch to benchmark (default: main)
- Optionally enable commit_results to save results to the repository
Benchmark results are available in multiple formats:
- Workflow Artifacts: Download from the Benchmark Workflow runs
- Historical Data: View the
benchmarks/benchmark-results.jsonlfile for trends - Detailed Reports: Check version-specific reports in the
benchmarks/directory
Each benchmark run generates:
- JSON Report (
benchmark-{version}.json): Complete results in structured format - Markdown Report (
benchmark-{version}.md): Human-readable summary - Historical Log (
benchmark-results.jsonl): Append-only history in JSON Lines format
# View latest benchmark
tail -1 benchmarks/benchmark-results.jsonl | jq '.'
# Compare startup times over releases
jq -r '[.version, .cold_start_seconds, .warm_start_seconds] | @tsv' \
benchmarks/benchmark-results.jsonl
# Find slowest startup
jq -s 'max_by(.cold_start_seconds)' benchmarks/benchmark-results.jsonl
# Average memory usage
jq -s 'map(.memory_mb) | add/length' benchmarks/benchmark-results.jsonlThese are informal goals for UBI performance:
| Metric | Target | Rationale |
|---|---|---|
| Cold Start | < 3s | Fast developer feedback |
| Warm Start | < 1s | Instant iteration |
| Memory at Idle | < 100 MB | Efficient resource usage |
| Image Size | < 500 MB | Reasonable download time |
See the benchmarks documentation for more details.
Contributions are welcome! Here's how you can help:
- Report Issues: Found a bug or have a feature request? Open an issue
- Submit PRs: Fix bugs, improve documentation, or add features
- Share Feedback: Let us know how UBI can better serve your needs
- Keep changes minimal and focused
- Update documentation for any environment changes
- Bump the
VERSIONfile according to SemVer for breaking or feature changes - Document your changes in your PR description; the CHANGELOG.md is updated automatically during releases
- Test your changes locally before submitting
This project is licensed under the MIT License - see the LICENSE file for details.
Built with β€οΈ by the Ego Hygiene team.
Special thanks to:
- Microsoft DevContainers for the excellent base image
- The XDG Base Directory Specification community
- All contributors who help make UBI better
π Visit the full documentation site β
Comprehensive documentation is also available in the docs/ directory:
- Architecture - Design, XDG strategy, filesystem layout, and CI/CD
- Troubleshooting - Common issues and solutions
- Release Process - Version management and publishing workflow
- Security Overview - Security practices, scanning, and SBOM
See the Documentation Index for a complete overview.
- Issues: github.com/egohygiene/ubi/issues
- Discussions: github.com/egohygiene/ubi/discussions
- Documentation: egohygiene.github.io/ubi
- Organization: github.com/egohygiene
Made with π οΈ by Ego Hygiene | Powered by π Universal Base Image