Stage 4 · Provision
Image Internals & Advanced Builds
Layer Size Forensics
Use docker history, dive, syft, and .dockerignore to remove hidden bloat and unused artifacts.
Finding Bloat
Image bloat accumulates silently. Package caches, test files, development dependencies, and unnecessary files end up in production images. Finding and removing bloat requires inspecting every layer to identify what is taking up space.
docker history
# Show all layers with sizes
docker history myapp:latest
# Truncated output format
docker history myapp:latest --format "{{.Size}} {{.CreatedBy}}"
# Find the largest layers
docker history myapp:latest --format "{{.Size}} {{.CreatedBy}}" | sort -hr
# Show commands that created each layer
docker history myapp:latest --no-truncdocker history shows every layer in an image, its size, and the command that created it. Large layers from RUN instructions indicate opportunities for optimization.
Using dive
# Install dive
brew install dive # macOS
# Analyze an image
dive myapp:latest
# Analyze during build
dive build -t myapp:latest .
# CI mode (fails if efficiency is below threshold)
CI=true dive myapp:latest
# Key bindings in dive:
# Tab — toggle file details
# Ctrl+A — show added files
# Ctrl+R — show removed files
# Ctrl+M — show modified filesdive shows a tree view of every file in every layer. It highlights which files were added, modified, or deleted. It also gives an efficiency score and warns about wasted space.
Hidden Files
# List all files in a layer
dive myapp:latest --layer 0
# Export and inspect layer contents
docker export $(docker create myapp:latest) | tar -tf - | wc -l
# Find large files
docker export $(docker create myapp:latest) | tar -tf - | while read f; do
docker export $(docker create myapp:latest) | tar -xf - "$f" 2>/dev/null
size=$(stat -f%z "$f" 2>/dev/null || echo 0)
echo "$size $f"
done | sort -hr | head -20
# Common hidden bloat:
# - .git directory
# - node_modules
# - __pycache__
# - *.pyc files
# - .env files
# - Test dataHidden files like .git, node_modules, and __pycache__ can add hundreds of MB to your image. Use .dockerignore to exclude them before they reach the build context.
.dockerignore Forensics
# Check build context size
du -sh .
# List what Docker sends to the daemon
docker build --no-cache -t myapp . 2>&1 | grep "Sending build context"
# Compare with .dockerignore
# The "Sending build context" line shows the compressed size
# Comprehensive .dockerignore
cat > .dockerignore << EOF
# Version control
.git
.gitignore
.github
# Dependencies
node_modules
vendor
__pycache__
*.pyc
# Build output
dist
build
target
*.o
*.so
# Development
.env
.env.*
*.log
coverage
.nyc_output
.vscode
.idea
# Documentation
*.md
LICENSE
docs/
# Docker files
Dockerfile*
docker-compose*.yml
# Testing
test/
tests/
*_test.go
*.test.js
EOFA comprehensive .dockerignore prevents unnecessary files from entering the build context. This reduces both build time and image size. Update it as your project evolves.
Automated Size Checks
name: Image Size Check
on: [pull_request]
jobs:
size-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:pr .
- name: Check image size
run: |
SIZE=$(docker image inspect myapp:pr --format '{{.Size}}')
MAX_SIZE=$((50 * 1024 * 1024)) # 50MB limit
if [ "$SIZE" -gt "$MAX_SIZE" ]; then
echo "Image too large: $SIZE bytes (max: $MAX_SIZE)"
exit 1
fi
echo "Image size: $SIZE bytes"
- name: Run dive
uses: wagoodman/dive-action@stable
with:
image: myapp:pr
highestEfficiency: 90Automate size checks in CI to catch bloat before it reaches production. The dive action fails if image efficiency is below 90%, catching unnecessary files.
docker image ls --format "table {{.Repository}} {{.Tag}} {{.Size}}" shows all images with sizes. Sort by size to find your largest images and prioritize optimization.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.