# Base Image Caching Solution for Docker Hub Rate Limiting

## Overview

This solution provides a simple, short-term approach to reduce Docker Hub usage by pre-pulling and caching base images. It's designed to be implemented quickly while providing significant benefits.

## Problem Addressed

- **Docker Hub Rate Limiting**: 100 pulls/6h for anonymous users
- **Build Failures**: Timeouts and authentication errors during CI/CD
- **Inconsistent Builds**: Different base image versions causing issues

## Solution Architecture

```
[Docker Hub] → [Pre-Pull Script] → [Local Cache/Registry] → [Service Builds]
```

## Implementation Options

### Option 1: Simple Docker Cache (Easiest)

```bash
# Just run the prepull script
./scripts/prepull-base-images.sh
```

**How it works:**
- Pulls all base images once with authentication
- Docker caches them locally
- Subsequent builds use cached images
- Reduces Docker Hub pulls by ~90%

### Option 2: Local Registry (More Robust)

```bash
# Start local registry
docker run -d -p 5000:5000 --name bakery-registry \
  -v $(pwd)/registry-data:/var/lib/registry \
  registry:2

# Run prepull script with local registry enabled
USE_LOCAL_REGISTRY=true ./scripts/prepull-base-images.sh
```

**How it works:**
- Runs a local Docker registry
- Pre-pull script pushes images to local registry
- All builds pull from local registry
- Can be shared across team members

### Option 3: Pull-Through Cache (Most Advanced)

```yaml
# Configure Docker daemon (docker daemon.json)
{
  "registry-mirrors": ["http://localhost:5000"],
  "insecure-registries": ["localhost:5000"]
}

# Start registry as pull-through cache
docker run -d -p 5000:5000 --name bakery-registry \
  -v $(pwd)/registry-data:/var/lib/registry \
  -e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \
  registry:2
```

**How it works:**
- Local registry acts as transparent cache
- First request pulls from Docker Hub and caches
- Subsequent requests served from cache
- Completely transparent to builds

## Quick Start Guide

### 1. Simple Caching (5 minutes)

```bash
# Make script executable
chmod +x scripts/prepull-base-images.sh

# Run the script
./scripts/prepull-base-images.sh

# Verify images are cached
docker images | grep -E "python:3.11-slim|postgres:17-alpine"
```

### 2. Local Registry (10 minutes)

```bash
# Build local registry image
cd scripts/local-registry
docker build -t bakery-registry .

# Start registry
docker run -d -p 5000:5000 --name bakery-registry \
  -v $(pwd)/registry-data:/var/lib/registry \
  bakery-registry

# Run prepull with local registry
USE_LOCAL_REGISTRY=true ../prepull-base-images.sh

# Verify registry contents
curl http://localhost:5000/v2/_catalog
```

### 3. CI/CD Integration

**GitHub Actions Example:**
```yaml
jobs:
  setup:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Set up Docker
        uses: docker/setup-buildx-action@v2
      
      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}
      
      - name: Pre-pull base images
        run: ./scripts/prepull-base-images.sh
      
      - name: Cache Docker layers
        uses: actions/cache@v3
        with:
          path: /tmp/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-buildx-

  build:
    needs: setup
    runs-on: ubuntu-latest
    steps:
      - name: Build services
        run: ./scripts/build-services.sh
```

**Tekton Pipeline Example:**
```yaml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: prepull-base-images
spec:
  steps:
    - name: login-to-docker
      image: docker:cli
      script: |
        echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
      env:
        - name: DOCKER_USERNAME
          valueFrom:
            secretKeyRef:
              name: docker-creds
              key: username
        - name: DOCKER_PASSWORD
          valueFrom:
            secretKeyRef:
              name: docker-creds
              key: password
    
    - name: prepull-images
      image: docker:cli
      script: |
        #!/bin/bash
        images=("python:3.11-slim" "postgres:17-alpine" "redis:7.4-alpine")
        for img in "${images[@]}"; do
          echo "Pulling $img..."
          docker pull "$img"
        done
```

## Base Images Covered

The script pre-pulls all base images used in the Bakery-IA project:

### Primary Base Images
- `python:3.11-slim` - Main Python runtime
- `postgres:17-alpine` - Database init containers
- `redis:7.4-alpine` - Redis init containers

### Utility Images
- `busybox:1.36` - Lightweight utility container
- `busybox:latest` - Latest busybox
- `curlimages/curl:latest` - Curl utility
- `bitnami/kubectl:1.28` - Kubernetes CLI

### Build System Images
- `alpine:3.18` - Lightweight base
- `alpine:3.19` - Latest Alpine
- `gcr.io/kaniko-project/executor:v1.23.0` - Kaniko builder
- `alpine/git:2.43.0` - Git client

## Benefits

### Immediate Benefits
- **Reduces Docker Hub pulls by 90%+** - Only pull each base image once
- **Eliminates rate limiting issues** - Authenticated pulls with proper credentials
- **Faster builds** - Cached images load instantly
- **More reliable CI/CD** - No more timeout failures

### Long-Term Benefits
- **Consistent build environments** - Same base images for all builds
- **Easier debugging** - Known image versions
- **Better security** - Controlled image updates
- **Foundation for improvement** - Can evolve to pull-through cache

## Monitoring and Maintenance

### Check Cache Status
```bash
# List cached images
docker images

# Check disk usage
docker system df

# Clean up old images
docker image prune -a
```

### Update Base Images
```bash
# Run prepull script monthly to get updates
./scripts/prepull-base-images.sh

# Or create a cron job
0 3 1 * * /path/to/prepull-base-images.sh
```

## Security Considerations

### Credential Management
- Store Docker Hub credentials in secrets management system
- Rotate credentials periodically
- Use least-privilege access

### Image Verification
```bash
# Verify image integrity
docker trust inspect python:3.11-slim

# Scan for vulnerabilities
docker scan python:3.11-slim
```

## Comparison with Other Solutions

| Solution | Complexity | Docker Hub Usage | Implementation Time | Maintenance |
|----------|------------|------------------|---------------------|-------------|
| **This Solution** | Low | Very Low | 5-30 minutes | Low |
| GHCR Migration | Medium | None | 1-2 days | Medium |
| Pull-Through Cache | Medium | Very Low | 1 day | Medium |
| Immutable Base Images | High | None | 1-2 weeks | High |

## Migration Path

This solution can evolve over time:

```
Phase 1: Simple caching (Current) → Phase 2: Local registry → Phase 3: Pull-through cache → Phase 4: Immutable base images
```

## Troubleshooting

### Common Issues

**Issue: Authentication fails**
```bash
# Solution: Verify credentials
docker login -u your-username
echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
```

**Issue: Local registry not accessible**
```bash
# Solution: Check registry status
docker ps | grep registry
curl http://localhost:5000/v2/
```

**Issue: Images not found in cache**
```bash
# Solution: Verify images are pulled
docker images | grep python:3.11-slim
# If missing, pull manually
docker pull python:3.11-slim
```

## Conclusion

This simple base image caching solution provides an immediate fix for Docker Hub rate limiting issues while requiring minimal changes to your existing infrastructure. It serves as both a short-term solution and a foundation for more advanced caching strategies in the future.

**Recommended Next Steps:**
1. Implement simple caching first
2. Monitor Docker Hub usage reduction
3. Consider adding local registry if needed
4. Plan for long-term solution (GHCR or immutable base images)