A tool to create minimal, hardened container images by observing what files your application actually uses at runtime, then building a new image with ONLY those files.
minifier-cli creates dramatically smaller and more secure container images by:
- Tracing - Monitoring which files your running container actually accesses
- Analyzing - Resolving dependencies and following symlinks to find all required files
- Repackaging - Building a new "FROM scratch" image with only the essential files
Result: 80-90% size reduction while maintaining full functionality.
Tracer:
- Spawns your container normally with Docker
- Background goroutine polls every 1 second
- Reads
/proc/*/mapsfor memory-mapped files - Reads
/proc/*/fdfor open file descriptors - Writes deduplicated file list to trace log
Analyzer:
- Parses trace log line-by-line
- Uses Go's
debug/elfpackage to analyze ELF binaries - Extracts imported shared libraries (
.sofiles) - Finds dynamic linker (PT_INTERP like
/lib64/ld-linux.so) - Recursively resolves all dependencies
- Adds critical system files (passwd, group, hosts, etc.)
Repackager:
- Extracts Docker metadata via JSON inspect
- Preserves ENV, CMD, ENTRYPOINT, EXPOSE, VOLUME, LABEL, USER, WORKDIR
- Creates temp container to copy files from original image
- Generates optimized Dockerfile
- Builds new minimal image from scratch
Problem: Third-party appliances (like Datadog Agent) come with unnecessary tools that increase attack surface.
Solution:
minifier-cli trace start --image datadog/agent:latest --name dd-prod
# Let it run for 24 hours in production-like environment
# Ctrl+C to stop
minifier-cli repackage --name dd-prod --output datadog-minimal:prodResult: 1.2GB → 150MB (87% reduction), removed shells, package managers, debug tools
Problem: Need to prove minimal attack surface for compliance audits.
Benefits:
- Documents exact file manifest for auditors
- Passes "principle of least privilege" requirements
- Easier security scanning (fewer files to check)
- Reproducible minimal builds
Problem: Ancient application with unknown dependencies.
minifier-cli trace start --image legacy-app:old --name legacy
# Run comprehensive test suite to exercise all code paths
# Ctrl+C when done
minifier-cli repackage --name legacy --output legacy-app:minimalResult: Discovered exact runtime requirements, 2.5GB → 300MB
Problem: Slow Docker pulls, high registry costs.
Benefits:
- Faster deployments (nginx: 80MB → 14MB)
- Lower storage costs across thousands of deployments
- Reduced bandwidth usage
- Faster autoscaling
Problem: Limited disk space on edge devices.
Benefits:
- Fits on resource-constrained devices (Node.js: 900MB → 120MB)
- Faster OTA updates
- More applications per device
Problem: Unsure which files to include in final stage.
Solution: Trace to discover actual dependencies, then use manifest to inform Dockerfile COPY statements.
vs. Multi-stage Docker builds:
- ✅ Automatic (no manual file selection)
- ✅ Based on runtime data (not guesswork)
- ✅ Works with ANY existing image
vs. Distroless images:
- ✅ Works with existing images (no rebuild needed)
- ✅ Preserves your exact dependencies
- ✅ No need to start from scratch
vs. Docker Slim:
- ✅ Written in Go (easier to extend)
- ✅ Simple three-step workflow
- ✅ Preserves all Docker metadata
git clone https://github.com/swantron/minifier-cli
cd minifier-cli
go build -o minifier-cli .Trace Representative Workloads:
- Run for 24-48 hours in production-like environment
- Execute comprehensive test suite during trace
- Exercise all code paths and features
- Include edge cases and error scenarios
Important Considerations:
- Entrypoint scripts need to execute
- May need multiple trace sessions for different modes
- Plugins loaded at runtime must be exercised
- Database drivers loaded by name need testing
- Configuration-dependent features must be triggered
✅ Validation:
- Thoroughly test minified image before production
- Keep original image as fallback
- Monitor for missing files in staging environment
Perfect for:
- Security hardening existing third-party images
- Compliance requirements (minimal attack surface)
- Optimizing legacy applications with unknown dependencies
- Reducing deployment costs and bandwidth
- Edge/IoT deployments with space constraints
- Discovering actual runtime dependencies
Not ideal for:
- Images you fully control and can rebuild properly
- Development environments (need debug tools)
- Images with frequently changing behavior
- Applications with complex dynamic loading
The tool uses a stateful, multi-step workflow:
minifier-cli trace start \
--image nginx:alpine \
--name my-nginxThis command:
- Launches the container with its default configuration
- Attaches file access monitor to capture accessed files
- Writes traced files to temp directory
- Runs in foreground (Ctrl+C to stop)
Note: The tracer process must stay running to capture files. Run it in a terminal you can keep open, or use a terminal multiplexer like tmux.
While the tracer is running, interact with your container to generate trace data:
# In another terminal, generate traffic
curl http://localhost:8080
curl http://localhost:8080/api/health
# Exercise all features you need
# Send production-like traffic
# Run your test suiteRun for a representative period (minutes to hours) to capture all necessary files.
Press Ctrl+C in the terminal running the tracer.
The container continues running in the background. The trace log is saved and ready for analysis.
minifier-cli repackage \
--name my-nginx \
--output nginx-minimal:latestThis command:
- Reads the trace log
- Analyzes ELF dependencies and resolves symlinks
- Extracts Docker metadata from the original image
- Copies only the necessary files
- Builds a new "FROM scratch" image
Result: A dramatically smaller image with the same functionality.
# 1. Start tracing nginx
minifier-cli trace start --image nginx:alpine --name web
# 2. In another terminal, generate traffic for 5 minutes
for i in {1..300}; do
curl -s http://localhost:80 > /dev/null
sleep 1
done
# 3. Stop tracing (Ctrl+C in tracer terminal)
# 4. Create minified image
minifier-cli repackage --name web --output nginx-minimal:prod
# 5. Compare sizes
docker images | grep nginx
# nginx:alpine 80.9MB
# nginx-minimal:prod 14MB (83% reduction!)
# 6. Test the minified image
docker run -d -p 8080:80 nginx-minimal:prod
curl http://localhost:8080 # Should work!You can also use a trace log directly:
minifier-cli repackage \
--log-file /path/to/trace.log \
--output minified-image:latest- Userspace Tracing: Polls
/proc/*/fdand/proc/*/mapsevery second to capture all file accesses from within the running container - Dependency Resolution: Resolves symlinks, ELF binary dependencies, and adds essential system files
- Image Repackaging: Copies traced files from the original image and builds a new minimal image from scratch
minifier-cli/
├── cmd/ # CLI commands (cobra)
│ ├── root.go # Root command setup
│ ├── trace.go # trace start/stop commands
│ └── repackage.go # repackage command
├── pkg/
│ ├── session/ # Session state management
│ ├── tracer/ # eBPF tracer implementation
│ ├── analyzer/ # Dependency analysis engine
│ └── repackager/ # Docker image builder
└── main.go # Entry point
- Docker installed and running
- Linux kernel with eBPF support (for tracing)
CAP_SYS_ADMINandCAP_SYS_PTRACEcapabilities
- v0.1 does not support Java/JVM applications
- Requires thorough manual testing to ensure complete coverage
- Only captures file accesses during the trace period
- v0.2: CI/Test-Suite Mode - Automated tracing with test suites
- Recipe files for common applications (e.g.,
datadog.recipe.sh) - Enhanced ELF dependency resolution
- Support for more runtime environments
MIT — see LICENSE.
Contributions are welcome. See CONTRIBUTING.md for guidelines.
Run the automated demo:
./demo.shOr run the full test suite:
./test.shSee TESTING.md for detailed testing instructions and scenarios.
go test ./...