A modular, extensible container build system designed to be shared across projects as a git submodule. Build everything from minimal agent containers to full-featured development environments using a single, configurable Dockerfile.
- Features
- Quick Start
- VS Code Dev Container
- Available Features
- Example Use Cases
- Version Management
- Testing
- Best Practices
- Contributing
- Emergency Procedures
- 🔧 Modular Architecture: Enable only the tools you need via build arguments
- 🚀 Efficient Caching: BuildKit cache mounts for faster rebuilds
- 🔒 Security Hardened: Non-root users, input validation, checksum verification, secure temp files, rate limiting
- 🌍 Multi-Purpose: Development, CI/CD, production, and agent containers
- 📦 28 Feature Modules: Python, Node.js, Rust, Go, Ruby, Java, R, and 100+ tools
- ☁️ Cloud Ready: AWS, GCP, Kubernetes, Terraform integrations
- 🐧 Debian Compatible: Supports Debian 11 (Bullseye), 12 (Bookworm), and 13 (Trixie)
- Add as a git submodule:
git submodule add https://github.com/joshjhall/containers.git containers
git submodule update --init --recursive- Build your container using the Dockerfile from the submodule:
# Build from project root (recommended)
docker build -t myproject:dev \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myproject \
--build-arg INCLUDE_NODE_DEV=true \
--build-arg INCLUDE_DEV_TOOLS=true \
.
# For testing containers standalone (without a parent project)
cd containers
docker build -t test:dev \
--build-arg PROJECT_PATH=. \
--build-arg PROJECT_NAME=test \
--build-arg INCLUDE_NODE_DEV=true \
.- Add the submodule:
git submodule add https://github.com/joshjhall/containers.git containers- Create build scripts or update your CI/CD to use the shared Dockerfile:
# scripts/build-dev.sh
docker build -t myproject:dev \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myproject \
--build-arg INCLUDE_PYTHON_DEV=true \
--build-arg INCLUDE_POSTGRES_CLIENT=true \
.
# scripts/build-prod.sh
docker build -t myproject:prod \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myproject \
--build-arg INCLUDE_PYTHON=true \
.This system integrates seamlessly with VS Code Dev Containers. Simply reference
the shared Dockerfile in your .devcontainer/docker-compose.yml:
services:
devcontainer:
build:
context: ..
dockerfile: containers/Dockerfile
args:
BASE_IMAGE: mcr.microsoft.com/devcontainers/base:trixie
PROJECT_NAME: myproject
INCLUDE_PYTHON_DEV: 'true'
INCLUDE_NODE_DEV: 'true'
volumes:
- ..:/workspace/myprojectFor complete examples with databases, 1Password integration, and advanced configurations, see the examples/devcontainer/ directory
All features are enabled via INCLUDE_<FEATURE>=true build arguments.
| Feature | Build Arg | What's Included |
|---|---|---|
| Python | INCLUDE_PYTHON=true |
Python 3.14+ from source, pip, pipx |
| Python Dev | INCLUDE_PYTHON_DEV=true |
+ Poetry, black, ruff, mypy, pytest, jupyter |
| Node.js | INCLUDE_NODE=true |
Node 22 LTS, npm, yarn, pnpm |
| Node Dev | INCLUDE_NODE_DEV=true |
+ TypeScript, ESLint, Jest, Vite, webpack |
| Rust | INCLUDE_RUST=true |
Latest stable, cargo |
| Rust Dev | INCLUDE_RUST_DEV=true |
+ clippy, rustfmt, cargo-watch, bacon |
| Go | INCLUDE_GOLANG=true |
Latest with module support |
| Go Dev | INCLUDE_GOLANG_DEV=true |
+ delve, gopls, staticcheck |
| Ruby | INCLUDE_RUBY=true |
Ruby 3.3+, bundler |
| Ruby Dev | INCLUDE_RUBY_DEV=true |
+ rubocop, solargraph |
| Java | INCLUDE_JAVA=true |
OpenJDK 21 |
| Java Dev | INCLUDE_JAVA_DEV=true |
+ Maven, Gradle |
| R | INCLUDE_R=true |
R environment |
| R Dev | INCLUDE_R_DEV=true |
+ tidyverse, devtools |
| Feature | Build Arg | What's Included |
|---|---|---|
| Docker | INCLUDE_DOCKER=true |
Docker CLI, compose, lazydocker |
| Kubernetes | INCLUDE_KUBERNETES=true |
kubectl, helm, k9s |
| Terraform | INCLUDE_TERRAFORM=true |
terraform, terragrunt, tfdocs |
| AWS | INCLUDE_AWS=true |
AWS CLI v2 |
| GCloud | INCLUDE_GCLOUD=true |
Google Cloud SDK |
| Cloudflare | INCLUDE_CLOUDFLARE=true |
Cloudflare CLI tools |
| Feature | Build Arg |
|---|---|
| PostgreSQL | INCLUDE_POSTGRES_CLIENT=true |
| Redis | INCLUDE_REDIS_CLIENT=true |
| SQLite | INCLUDE_SQLITE_CLIENT=true |
| Feature | Build Arg | What's Included |
|---|---|---|
| Dev Tools | INCLUDE_DEV_TOOLS=true |
git, gh CLI, lazygit, fzf, ripgrep, bat, eza/exa, delta |
| 1Password | INCLUDE_OP=true |
1Password CLI |
| Ollama | INCLUDE_OLLAMA=true |
Local LLM support |
# Development: Full TypeScript toolchain + debugging tools
docker build -t myapi:dev \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myapi \
--build-arg INCLUDE_NODE_DEV=true \
--build-arg INCLUDE_POSTGRES_CLIENT=true \
--build-arg INCLUDE_DEV_TOOLS=true \
.
# Production: Just Node.js runtime
docker build -t myapi:prod \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myapi \
--build-arg INCLUDE_NODE=true \
--build-arg BASE_IMAGE=node:22-slim \
.# Development: Full Python stack + Jupyter
docker build -t myml:dev \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myml \
--build-arg INCLUDE_PYTHON_DEV=true \
--build-arg PYTHON_VERSION=3.11.2 \
.
# Training: Python + cloud tools
docker build -t myml:train \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myml \
--build-arg INCLUDE_PYTHON=true \
--build-arg INCLUDE_AWS=true \
--build-arg INCLUDE_KUBERNETES=true \
.# Development: Everything you might need
docker build -t myservice:dev \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myservice \
--build-arg INCLUDE_GOLANG_DEV=true \
--build-arg INCLUDE_RUST_DEV=true \
--build-arg INCLUDE_DOCKER=true \
--build-arg INCLUDE_KUBERNETES=true \
.
# CI/CD: Just build tools
docker build -t myservice:ci \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myservice \
--build-arg INCLUDE_GOLANG=true \
--build-arg INCLUDE_RUST=true \
.To update to the latest version:
cd containers
git pull origin main
cd ..
git add containers
git commit -m "Update container build system"The container system includes a version checker to identify when newer versions of pinned tools are available:
# Check all pinned versions
./containers/bin/check-versions.sh
# Output in JSON format (for CI integration)
./containers/bin/check-versions.sh json
# With GitHub token (to avoid rate limits)
GITHUB_TOKEN=ghp_your_token ./containers/bin/check-versions.sh
# Or add to .env file
cp containers/.env.example containers/.env
# Edit .env and add your GITHUB_TOKEN
./containers/bin/check-versions.shThe script will check:
- Language versions (Python, Node.js, Go, Rust, Ruby, Java, R)
- Tool versions (Poetry, Terraform, kubectl, GitHub CLI, etc.)
- Report which tools have updates available
The GitHub Actions workflow automatically checks for updates weekly:
- Runs every Sunday at 2am UTC (configured via cron schedule)
- Creates a pull request with version updates when available
- Auto-merges after CI tests pass (if configured)
The workflow creates PRs with updated versions that can be reviewed before merging.
When updates are available, edit the appropriate files:
- Language versions: Update
ARG *_VERSIONinDockerfile - Tool versions: Update version variables in
lib/features/*.sh
The build system supports two version specification strategies depending on whether you're installing a language runtime or a utility tool:
Supported Languages: Python, Node.js, Rust, Ruby, Go, Java
Partial versions are supported and automatically resolve to the latest patch version:
# All of these work:
PYTHON_VERSION="3.12" # → Resolves to 3.12.12 (latest patch)
PYTHON_VERSION="3.12.7" # → Uses exact version
PYTHON_VERSION="3" # → Resolves to 3.13.1 (latest stable)
NODE_VERSION="20" # → Resolves to 20.19.5 (latest LTS patch)
RUST_VERSION="1.84" # → Resolves to 1.84.1 (latest patch)Why use partial versions?
- ✅ Automatic security updates - Get latest patches without manual version bumps
- ✅ Pinned checksums - Latest patches use git-tracked checksums (Tier 2 verification)
- ✅ Simpler configuration - Specify major.minor, get best patch automatically
- ✅ Weekly auto-updates - CI automatically updates pinned checksums for latest patches
When to use exact versions:
- Strict reproducibility requirements
- Testing specific version behavior
- Known issues with latest patch
Examples: npm, gh (GitHub CLI), kubectl, helm, terraform, etc.
Exact versions are required:
# Tools require exact versions:
GH_VERSION="2.60.1" # ✓ Correct
GH_VERSION="2.60" # ✗ Error - partial not supported
KUBECTL_VERSION="1.31.4" # ✓ Correct
KUBECTL_VERSION="1.31" # ✗ Error - partial not supportedWhy exact versions only?
- Reduces maintenance burden (dozens of tools vs. 6 languages)
- Tools change less frequently than language patches
- Most users pin exact tool versions anyway
All downloads are verified using a 4-tier progressive security system that tries the most secure method first and falls back gracefully:
Cryptographic proof using publisher's public key.
- Available for: Python, Node.js, Go (framework ready, full implementation in progress)
- Security: ✅ Highest - proves authenticity via cryptographic signature
- Process: Downloads
.ascsignature file and verifies against publisher's GPG key
🔐 TIER 1: Attempting GPG signature verification
Fetching signature from python.org...
✅ TIER 1 VERIFICATION PASSED
Security: Cryptographically verified by publisher
Git-tracked checksums from lib/checksums.json.
- Available for: Languages (latest patches), common tool versions
- Security: ✅ High - git-tracked, auditable, reviewed
- Updates: Weekly via auto-patch workflow
📌 TIER 2: Checking pinned checksums database
✓ Found pinned checksum in git-tracked database
✅ TIER 2 VERIFICATION PASSED
Security: Git-tracked checksum, auditable and reviewed
Trigger Tier 2: Use partial versions for languages:
PYTHON_VERSION="3.12" # Uses Tier 2 for latest 3.12.x patchDownload checksum from official publisher (e.g., python.org, nodejs.org).
- Available for: Most languages when version not in checksums.json
- Security:
⚠️ Medium - MITM vulnerable but better than calculating - Process: Fetches checksum from publisher's server, compares to download
🌐 TIER 3: Fetching published checksum from official source
Checking python.org FTP directory...
✓ Retrieved checksum from official publisher
✅ TIER 3 VERIFICATION PASSED
Security: Downloaded from official source (MITM risk remains)
Trigger Tier 3: Specify exact version not in checksums.json:
PYTHON_VERSION="3.12.7" # If 3.12.7 not in checksums.json, uses Tier 3Calculate checksum of downloaded file (TOFU - Trust On First Use).
- Available for: All downloads (fallback only)
- Security:
⚠️ Low - no external verification, MITM vulnerable - Warning: Prominent warning box displayed during build
⚠️ TIER 4: Using calculated checksum (FALLBACK)
╔════════════════════════════════════════════════════════════╗
║ SECURITY WARNING ║
╠════════════════════════════════════════════════════════════╣
║ No trusted checksum available for verification. ║
║ ║
║ Using TOFU (Trust On First Use) - calculating checksum ║
║ from downloaded file without external verification. ║
║ ║
║ Risk: Vulnerable to man-in-the-middle attacks. ║
╚════════════════════════════════════════════════════════════╝
This happens when:
- Using tool version not in checksums.json
- Using older language version without published checksums
- Publisher doesn't provide checksums
For every download, the system:
- Attempts Tier 1 (GPG) if available for that tool
- Falls back to Tier 2 (pinned checksums) if GPG unavailable
- Falls back to Tier 3 (published checksums) if not pinned
- Falls back to Tier 4 (calculated) as last resort
- Logs detailed explanation of which tier succeeded and why
Result: You get the best available security for every download with full transparency about verification method.
The project includes comprehensive test coverage with 657 total tests across unit and integration test suites.
Unit tests validate individual components and scripts (497 tests, 99% pass rate):
# Run all unit tests (no Docker required)
./tests/run_unit_tests.sh
# Run specific test suite
./tests/unit/features/python.sh
./tests/unit/base/logging.shUnit Test Coverage:
- ✅ 497 unit tests covering all features and utilities
- ✅ 99% pass rate (496 passed, 1 legitimate skip)
- ✅ Tests bash scripts directly without Docker
- ✅ Fast execution (~30 seconds)
Integration tests verify that feature combinations build and work together (160 tests across 6 variants):
# Run all integration tests
./tests/run_integration_tests.sh
# Run specific integration test
./tests/run_integration_tests.sh python_devIntegration Test Coverage:
- ✅ python-dev: Python + dev tools + databases + Docker
- ✅ node-dev: Node.js + dev tools + databases + Docker
- ✅ cloud-ops: Kubernetes + Terraform + AWS + GCloud
- ✅ polyglot: Python + Node.js multi-language
- ✅ rust-golang: Systems programming polyglot
- ✅ minimal: Base container with no features
To verify installed features in a running container:
# Inside the container - check all installed tool versions
check-installed-versions.sh
# Check build logs for any issues
check-build-logs.shThis build system includes comprehensive security hardening:
- Checksum Verification: All downloaded binaries verified with SHA256/SHA512 checksums
- Atomic Operations: Directory creation uses atomic
install -dto prevent TOCTOU attacks - Secure Temporary Files: Restrictive permissions (700) on all temporary directories
- Input Validation: Function inputs sanitized against command injection
- Completion Script Safety: Shell completions validated before sourcing
- Configuration Validation: Optional runtime validation of environment variables, format checking, and secret detection (see examples/validation/)
- Rate Limiting: Exponential backoff for external API calls with configurable retry logic
- GitHub API Token Support: Automatic detection and use of
GITHUB_TOKENfor higher rate limits - Non-Root Execution: All containers run as non-root user by default
- Minimal Attack Surface: Only install features you actually need
# Passwordless sudo (disabled by default for security)
# Enable for local development convenience:
--build-arg ENABLE_PASSWORDLESS_SUDO=true # Development only
# Keep disabled for production (default):
--build-arg ENABLE_PASSWORDLESS_SUDO=false # Production (default)
# Configure retry behavior
-e RETRY_MAX_ATTEMPTS=5
-e RETRY_INITIAL_DELAY=2
-e RETRY_MAX_DELAY=30For detailed security information, see SECURITY.md.
When using the INCLUDE_DOCKER=true feature, you may need to mount the Docker
socket to manage containers from within your dev environment.
Use Case: Local development where your main container needs to manage dependency containers (databases, Redis, message queues, etc.)
Configuration:
# docker-compose.yml or .devcontainer/docker-compose.yml
services:
devcontainer:
build:
context: ..
dockerfile: containers/Dockerfile
args:
INCLUDE_DOCKER: 'true'
INCLUDE_PYTHON_DEV: 'true'
# Enable passwordless sudo so entrypoint can fix Docker socket permissions
ENABLE_PASSWORDLESS_SUDO: 'true'
volumes:
- /var/run/docker.sock:/var/run/docker.sock # ⚠️ Development only
- ..:/workspace/myproject
command: ['sleep', 'infinity']For VS Code Dev Containers, also set in devcontainer.json:
{
// Allow container's ENTRYPOINT to run (fixes Docker socket permissions)
"overrideCommand": false
}How it works:
- The container entrypoint automatically detects the Docker socket
- Creates a
dockergroup and sets socket permissions to660 - Adds the container user to the
dockergroup - Uses passwordless sudo for privilege operations (non-root containers)
- Works on Linux, macOS, WSL2, and Docker Desktop
Why this is useful:
- Start/stop database containers for testing
- Run integration tests that need real services
- Manage multi-container development stacks
- Use docker-compose from within dev container
Security Impact:
⚠️ Grants root-equivalent access to the host system- Container can start privileged containers
- Container can mount any host directory
- Container can read/modify all other containers
- Only use in local development environments
❌ DO NOT mount the Docker socket in production containers:
# ❌ INSECURE - Never do this in production
services:
app:
image: myapp:prod
volumes:
- /var/run/docker.sock:/var/run/docker.sock # ❌ Dangerous!Alternatives for Production:
- Docker-in-Docker (DinD): Run Docker daemon inside container (for CI/CD)
- Docker API: Use restricted Docker API with limited permissions
- Kubernetes: Use Kubernetes API instead of Docker
- External orchestration: Let CI/CD system manage containers
Create separate container variants:
# Development: Include Docker CLI + mount socket
docker-compose -f docker-compose.dev.yml up
# Production: No Docker, no socket mounting
docker build -t myapp:prod \
--build-arg INCLUDE_DOCKER=false \
-f containers/Dockerfile \
.Default: Passwordless sudo is DISABLED by default (as of v4.8.7) for security.
Use Case: Local development where you need to:
- Install additional system packages during runtime
- Fix file permissions quickly
- Debug system-level issues
- Run commands that require root without password prompts
# docker-compose.yml for development
services:
devcontainer:
build:
context: ..
dockerfile: containers/Dockerfile
args:
INCLUDE_PYTHON_DEV: 'true'
# Enable for local dev convenience
ENABLE_PASSWORDLESS_SUDO: 'true' # ⚠️ Development onlyWhy this is useful for development:
- Quickly install packages:
sudo apt install <package>(no password) - Fix permission issues:
sudo chown developer:developer file - Test system configurations without password interruptions
- Streamline development workflow on your local machine
Security Impact:
⚠️ Any compromised process can gain root access- No password barrier for privilege escalation
- Acceptable risk for local development on your personal machine
- NOT acceptable for production or shared environments
✅ RECOMMENDED: Keep passwordless sudo disabled in production (default):
# Explicitly set for production (or omit - false is default)
--build-arg ENABLE_PASSWORDLESS_SUDO=falseAlternatives for Production:
- Pre-install everything at build time: Use RUN commands in Dockerfile
- Init containers: Use Kubernetes init containers for setup
- Proper IAM/RBAC: Use cloud provider IAM instead of sudo
- Configuration management: Use proper deployment tools
Production Security Best Practices:
- ❌ Never enable passwordless sudo in production
- ✅ Install all required packages during build
- ✅ Use least-privilege principles
- ✅ User can still sudo with password if absolutely necessary
-
Only enable passwordless sudo in trusted environments
- ✅ Local development on your personal machine
- ✅ Isolated development containers
- ❌ Production deployments
- ❌ Shared development environments
- ❌ CI/CD systems (should build at build time)
-
Only mount socket in trusted environments
- ✅ Local development on your machine
- ✅ Isolated development containers
- ❌ Production deployments
- ❌ Multi-tenant environments
- ❌ Containers running untrusted code
-
Use least-privilege alternatives when possible
- Consider rootless Docker
- Use Docker contexts with limited access
- Explore Docker socket proxies with ACLs
-
Monitor socket access
- Audit what containers access the socket
- Log Docker API calls in sensitive environments
For more security guidance, see SECURITY.md.
By default, passwordless sudo is disabled for security. For development environments that need Docker socket access or frequent system modifications, you can enable it explicitly.
# Enable passwordless sudo for development
docker build -t myapp:dev \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myapp \
--build-arg INCLUDE_PYTHON_DEV=true \
--build-arg ENABLE_PASSWORDLESS_SUDO=true \
.Why this is useful for development:
- Quickly install system packages during development
- Test installation scripts without password prompts
- Standard development container behavior
Security Impact:
⚠️ Non-root user can execute any command as root without password- Container escape could grant full host access (if combined with other vulnerabilities)
- Suitable for trusted development environments only
# Production: Passwordless sudo disabled by default
docker build -t myapp:prod \
-f containers/Dockerfile \
--build-arg PROJECT_NAME=myapp \
--build-arg INCLUDE_PYTHON=true \
.Benefits:
- ✅ Follows least privilege principle
- ✅ Limits damage from container escape vulnerabilities
- ✅ User remains in sudo group but requires password
When to disable passwordless sudo:
- ❌ Production deployments
- ❌ Multi-tenant environments
- ❌ CI/CD runner containers (if they don't need sudo)
- ❌ Containers processing untrusted input
When passwordless sudo is acceptable:
- ✅ Local development on your machine
- ✅ Isolated development containers
- ✅ VS Code Dev Containers
- ✅ CI/CD containers that need to install dependencies (with caution)
-
Use separate builds for dev and prod
# scripts/build-dev.sh docker build --build-arg ENABLE_PASSWORDLESS_SUDO=true ... # scripts/build-prod.sh docker build --build-arg ENABLE_PASSWORDLESS_SUDO=false ...
-
Review sudo requirements
- If your application never needs sudo, disable it
- If only specific commands need sudo, configure sudoers accordingly
- Consider removing sudo entirely for runtime-only containers
-
Layer your security
- Disable passwordless sudo
- Use read-only filesystems where possible
- Drop unnecessary capabilities
- Use security profiles (AppArmor, SELinux)
Containers using sleep infinity or long-running processes can accumulate
zombie processes when child processes (e.g., from pre-commit hooks, git
operations) are orphaned. This happens because the main process (PID 1) doesn't
implement wait() to reap child processes.
This container system includes tini as an init system wrapper, which:
- Properly reaps zombie processes
- Forwards signals to child processes
- Ensures clean container shutdown
The Dockerfile uses tini in the ENTRYPOINT:
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint"]For extra protection (especially when command: overrides the entrypoint), add
init: true to your docker-compose services:
services:
devcontainer:
build:
context: ..
dockerfile: containers/Dockerfile
# Ensures proper zombie reaping even if command overrides entrypoint
init: true
command: ['sleep', 'infinity']If you suspect zombie accumulation:
# Count zombie processes
ps aux | grep -c 'Z'
# List zombie processes with parent info
ps -eo pid,ppid,stat,cmd | grep ' Z'- ✅ Always recommended for development containers
- ✅ Containers running
sleep infinity - ✅ Containers spawning many child processes (pre-commit, test runners)
- ✅ Long-running containers (days/weeks uptime)
Build arguments are permanently stored in Docker images and visible in multiple locations:
- Docker build logs - Plain text output during build
- Image history -
docker history <image>reveals all build args - Container inspection -
docker inspect <container>exposes build-time values - Image layer metadata - Embedded in the image filesystem
❌ DON'T DO THIS:
# These secrets will be permanently embedded in the image!
docker build --build-arg API_KEY=secret123 ...
docker build --build-arg DATABASE_PASSWORD=pass123 ...
docker build --build-arg AWS_SECRET_ACCESS_KEY=... ...✅ DO THIS INSTEAD:
-
Runtime Environment Variables (recommended for development):
docker run -e API_KEY=secret123 my-image:latest # Or with .env file docker run --env-file .env my-image:latest -
Docker Secrets (recommended for Docker Swarm/Compose):
# Create secret echo "secret123" | docker secret create api_key - # Use in service docker service create --secret api_key my-image:latest
-
Mounted Config Files (recommended for sensitive files):
# Mount secrets directory read-only docker run -v ./secrets:/secrets:ro my-image:latest -
Secret Management Tools (recommended for production):
# 1Password CLI (included via INCLUDE_OP=true) docker run -e OP_SERVICE_ACCOUNT_TOKEN=... my-image:latest # AWS Secrets Manager, Vault, etc. docker run -e AWS_REGION=us-east-1 my-image:latest
For more information, see /workspace/containers/SECURITY.md.
-
Choose the right base image:
debian:trixie-slim(Debian 13): Default, latest features (default)debian:bookworm-slim(Debian 12): Stable release, good compatibilitydebian:bullseye-slim(Debian 11): Older stable releaseubuntu:24.04: More packages available, larger sizemcr.microsoft.com/devcontainers/base:trixie: VS Code optimized
-
Optimize build times:
- Only include features you actually need
- Use BuildKit cache mounts (already configured)
- Layer expensive operations early in the Dockerfile
-
Security considerations:
- Always use non-root users in production
- Remove passwordless sudo in production builds
(
ENABLE_PASSWORDLESS_SUDO=false) - Never pass secrets as build arguments - they're stored permanently in the image
- Mount secrets at runtime, don't bake them in
- Regularly update the submodule for security patches
- See detailed security guidance below
-
Version pinning:
- Pin the submodule to specific commits for stability
- Use version build arguments for reproducible builds
- Document version requirements in your project
-
Build context:
- The build context should be your project root (where you run
docker build .) - The Dockerfile path is
-f containers/Dockerfile - Your project files are available for COPY commands during build
- Use
.dockerignoreto exclude sensitive files from build context
- The build context should be your project root (where you run
Contributions are welcome! For detailed guidelines, see CONTRIBUTING.md.
-
Fork the repository
-
Run the development environment setup:
./bin/setup-dev-environment.sh
This will:
- Enable git hooks for shellcheck and credential leak prevention
- Verify your development environment
- Check for recommended tools
-
Create a feature branch
-
Add tests for new features
-
Submit a pull request
See CONTRIBUTING.md for:
- Feature script guidelines and templates
- Error handling best practices
- Testing requirements
- Code style guidelines
- Pull request process
See .githooks/README.md for configuration options.
If a release introduces critical issues, see docs/emergency-rollback.md for:
- Quick rollback commands
- Auto-patch revert procedures
- Emergency hotfix workflows
- Post-incident procedures
# Revert problematic version
git revert --no-commit <bad_commit>
git commit -m "emergency: Rollback vX.Y.Z"
# Delete bad release and create patch
gh release delete vX.Y.Z --yes --cleanup-tag
./bin/release.sh --full-auto patch- Stable releases (
v4.6.0): Manual, thoroughly tested - Auto-patch releases: Automated dependency updates, may revert more frequently
Recommendation: Pin production to specific stable versions.
MIT License - see LICENSE file for details