Use Cases¶
This document covers common scenarios for using Occy Strap with practical examples.
Airgapped Environments¶
Transfer container images to systems without internet access.
Download Images for Transfer¶
# Download multiple images to tarballs
occystrap process registry://docker.io/library/python:3.11 tar://python.tar
occystrap process registry://docker.io/library/nginx:latest tar://nginx.tar
occystrap process registry://docker.io/library/postgres:15 tar://postgres.tar
Load Images on Airgapped System¶
# On the airgapped system with Docker
docker load -i python.tar
docker load -i nginx.tar
docker load -i postgres.tar
Reproducible Builds¶
Create images with consistent hashes regardless of build time.
Normalize Timestamps¶
# Download with timestamp normalization (Unix epoch)
occystrap process registry://docker.io/library/busybox:latest \
tar://busybox.tar -f normalize-timestamps
# Verify hash is consistent
sha256sum busybox.tar
# Running again produces the same hash
Use Specific Timestamp¶
# Normalize to a specific date (Jan 1, 2024)
occystrap process registry://docker.io/library/python:3.11 \
tar://python.tar -f "normalize-timestamps:ts=1704067200"
Container Forensics¶
Inspect and analyze container image contents.
Search for Configuration Files¶
# Find all .conf files
occystrap search registry://docker.io/library/nginx:latest "*.conf"
# Find all Python files with regex
occystrap search --regex docker://myapp:v1 ".*\.py$"
# Machine-readable output for scripting
occystrap search --script-friendly tar://image.tar "*.sh" > shell_files.txt
Extract and Inspect Layers¶
# Extract with expanded layers for inspection
occystrap process registry://docker.io/library/python:3.11 \
"dir://python-inspect?expand=true"
# Browse the extracted filesystem
ls -la python-inspect/
find python-inspect -name "*.conf"
Search While Processing¶
# Search for config files while creating tarball
occystrap process registry://docker.io/library/nginx:latest \
tar://nginx.tar -f "search:pattern=etc/**/*.conf"
Private Registry Operations¶
Work with authenticated registries.
Download from Private Registry¶
# Using command-line options
occystrap --username myuser --password mytoken \
process registry://registry.gitlab.com/mygroup/myimage:latest \
tar://myimage.tar
# Using environment variables (more secure)
export OCCYSTRAP_USERNAME=myuser
export OCCYSTRAP_PASSWORD=mytoken
occystrap process registry://registry.gitlab.com/mygroup/myimage:latest \
tar://myimage.tar
Mirror Images Between Registries¶
# Copy from Docker Hub to private registry
occystrap --username destuser --password desttoken \
process registry://docker.io/library/nginx:latest \
registry://myregistry.example.com/mirror/nginx:latest
# Copy from local Docker to registry
occystrap --username myuser --password mytoken \
process docker://myapp:v1 \
registry://ghcr.io/myorg/myapp:v1
# Copy from local Docker to registry (faster for multi-layer images)
occystrap --username myuser --password mytoken \
process dockerpush://myapp:v1 \
registry://ghcr.io/myorg/myapp:v1
Multi-Architecture Images¶
Work with images for different CPU architectures.
Download ARM64 Image¶
# Using global options
occystrap --os linux --architecture arm64 --variant v8 \
process registry://docker.io/library/busybox:latest \
tar://busybox-arm64.tar
# Using URI query parameters
occystrap process \
"registry://docker.io/library/busybox:latest?os=linux&arch=arm64&variant=v8" \
tar://busybox-arm64.tar
Download Multiple Architectures¶
# AMD64
occystrap process registry://docker.io/library/python:3.11 \
tar://python-amd64.tar
# ARM64
occystrap --architecture arm64 --variant v8 \
process registry://docker.io/library/python:3.11 \
tar://python-arm64.tar
Storage Optimization¶
Reduce disk usage when working with multiple images.
Shared Layer Storage¶
# Download multiple images with layer deduplication
occystrap process registry://docker.io/library/python:3.11 \
"dir://shared-images?unique_names=true"
occystrap process registry://docker.io/library/python:3.10 \
"dir://shared-images?unique_names=true"
occystrap process registry://docker.io/library/python:3.9 \
"dir://shared-images?unique_names=true"
# Shared base layers are stored only once
ls -la shared-images/
cat shared-images/catalog.json
Clean Up Images¶
# Exclude unnecessary files to reduce size
occystrap process registry://docker.io/library/python:3.11 \
tar://python-clean.tar \
-f "exclude:pattern=**/__pycache__/**,**/*.pyc,**/.git/**"
Efficient Registry Pushes with Deduplication¶
When pushing images that share base layers, Occy Strap skips uploading
blobs that already exist in the target registry. Combining this with
normalize-timestamps maximizes the chance of layer deduplication:
# Push multiple Python versions -- shared base layers upload once
for version in 3.9 3.10 3.11; do
occystrap process \
"registry://docker.io/library/python:$version" \
"registry://myregistry.example.com/python:$version" \
-f normalize-timestamps
done
Compression is deterministic (gzip suppresses header timestamps, zstd is inherently deterministic), so identical layers always produce the same compressed digest. The second and third pushes will skip uploading any layers shared with earlier pushes.
OCI Runtime Integration¶
Create runtime bundles for runc.
Generate OCI Bundle¶
# Create OCI bundle from registry image
occystrap process registry://docker.io/library/hello-world:latest \
oci://hello-bundle
# Run with runc
cd hello-bundle
sudo runc run hello-world
From Local Docker Image¶
# Export and convert to OCI bundle
occystrap process docker://myapp:v1 oci://myapp-bundle
# Run the bundle
cd myapp-bundle
sudo runc run myapp
Podman Integration¶
Work with Podman instead of Docker.
Enable Podman Socket¶
# Start rootless Podman socket
systemctl --user start podman.socket
# Or rootful
sudo systemctl start podman.socket
Fetch from Podman¶
# Rootless Podman
occystrap process \
"docker://myimage:v1?socket=/run/user/$(id -u)/podman/podman.sock" \
tar://myimage.tar
# Rootful Podman
occystrap process \
"docker://myimage:v1?socket=/run/podman/podman.sock" \
tar://myimage.tar
Load into Podman¶
# Load tarball into Podman
occystrap process tar://myimage.tar \
"docker://myimage:v1?socket=/run/user/$(id -u)/podman/podman.sock"
CI/CD Pipelines¶
Integrate Occy Strap into build pipelines.
Cache Images for CI¶
#!/bin/bash
# ci-image-cache.sh - Download images for CI environment
CACHE_DIR="/var/cache/ci-images"
mkdir -p "$CACHE_DIR"
# Download with normalized timestamps for consistent caching
for image in python:3.11 node:18 postgres:15; do
name=$(echo "$image" | tr ':' '-')
if [ ! -f "$CACHE_DIR/$name.tar" ]; then
occystrap process "registry://docker.io/library/$image" \
"tar://$CACHE_DIR/$name.tar" -f normalize-timestamps
fi
done
Fast Local-to-Registry Push with Layer Cache¶
#!/bin/bash
# ci-push.sh - Push locally-built images to registry with layer cache
# Uses dockerpush:// for fast transfer from local Docker and
# --layer-cache to skip re-processing shared base layers.
CACHE="/tmp/occystrap-cache.json"
for image in app-web app-api app-worker; do
occystrap --layer-cache "$CACHE" \
process "dockerpush://$image:latest" \
"registry://myregistry.example.com/$image:latest" \
-f normalize-timestamps
done
# Second and third images skip uploading shared base layers
Verify Image Contents¶
#!/bin/bash
# verify-image.sh - Check image doesn't contain sensitive files
IMAGE="$1"
SENSITIVE_PATTERNS="*.pem *.key id_rsa* .env* secrets*"
for pattern in $SENSITIVE_PATTERNS; do
matches=$(occystrap search --script-friendly \
"registry://$IMAGE" "$pattern" 2>/dev/null)
if [ -n "$matches" ]; then
echo "WARNING: Found sensitive files matching '$pattern':"
echo "$matches"
exit 1
fi
done
echo "Image passed security check"
Validate Image Integrity in CI¶
#!/bin/bash
# validate-image.sh - Validate image after processing
# Process image with filters
occystrap process docker://myapp:v1 tar://output.tar \
-f normalize-timestamps \
-f "exclude:pattern=**/__pycache__/**"
# Fast metadata check (no layer download)
occystrap check --fast tar://output.tar
# Full integrity check (verifies diff_ids, tar validity)
occystrap -O json check tar://output.tar | jq .errors
# Exit code is non-zero if errors found
Inspect Image Metadata¶
# Quick overview of a registry image
occystrap info registry://docker.io/library/python:3.11
# JSON output for scripting
occystrap -O json info docker://myapp:v1 | jq '.layer_count, .architecture'
Batch Image Builds with Filtering Proxy¶
When building many container images (e.g., OpenStack Kolla), the proxy command lets build and push overlap, and deduplicates shared base layers across images.
Start Proxy Before Build¶
# Start the proxy in the background
occystrap proxy --listen 127.0.0.1:5050 \
--downstream ghcr.io/myorg \
--layer-cache /tmp/layer-cache.json \
-f normalize-timestamps &
# Configure the build tool to push to the proxy
kolla-build --registry 127.0.0.1:5050 --push ...
# Or push individual images as they're built
docker tag nova-api:latest localhost:5050/kolla/nova-api:latest
docker push localhost:5050/kolla/nova-api:latest
docker tag keystone:latest localhost:5050/kolla/keystone:latest
docker push localhost:5050/kolla/keystone:latest
Why Use the Proxy Instead of dockerpush://¶
The dockerpush:// input processes one image per invocation. For a
build producing many images (Kolla builds ~100), each invocation
starts a fresh embedded registry and cannot share state across images.
The proxy:
- Runs once, receives all images as they are built
- Maintains a single
LayerCacheacross all images, so the first image pays the full cost and subsequent images skip shared base layers entirely - Overlaps build and push (images push as soon as they are built, rather than waiting for the entire build to complete)
TLS behavior difference: The dockerpush:// input starts an
embedded HTTPS server with a self-signed certificate. Docker skips
certificate verification for 127.0.0.0/8, so it works without any
daemon.json changes. The proxy, on the other hand, listens on plain
HTTP. Docker normally allows insecure access to localhost, but when
containerd-snapshotter: true is enabled in daemon.json this
exception is not honored and insecure-registries in daemon.json
is not propagated to containerd's push path. You must configure
containerd's host-based registry config directly. See the
proxy command reference for details.
Push Multiple Images with Layer Dedup¶
#!/bin/bash
# Start proxy with layer cache
occystrap proxy -l 127.0.0.1:5050 \
-d myregistry.example.com \
--layer-cache /tmp/cache.json \
-f normalize-timestamps &
PROXY_PID=$!
# Push images -- shared base layers are uploaded only once
for img in app-web app-api app-worker; do
docker tag "$img:latest" "localhost:5050/$img:latest"
docker push "localhost:5050/$img:latest"
done
# Stop proxy
kill $PROXY_PID
Debugging¶
Troubleshoot issues with verbose output. By default, occystrap only
logs milestones (start/end, summary statistics). Use --verbose to
see per-layer detail from occystrap, or --debug to also include
library output (requests, urllib3, etc.).
Enable Debug Logging¶
# Debug logging for occystrap modules only
occystrap --verbose process registry://docker.io/library/busybox:latest \
tar://busybox.tar
# Debug logging for all modules (includes library output)
occystrap --debug process registry://docker.io/library/busybox:latest \
tar://busybox.tar
When running in a terminal, registry downloads and uploads display interactive progress bars. In non-TTY environments (CI, pipes), periodic log messages are emitted instead.