Files
michaelschiemer/deployment/stacks/registry/README.md

611 lines
11 KiB
Markdown

# Docker Registry Stack - Private Container Registry
## Overview
Private Docker Registry mit BasicAuth für sichere Container Image Storage.
**Features**:
- Private Docker Registry v2.8
- BasicAuth Authentifizierung
- SSL via Traefik
- Automatic garbage collection
- Image deletion support
- Persistent storage
## Services
- **registry.michaelschiemer.de** - Docker Registry (BasicAuth protected)
## Prerequisites
1. **Traefik Stack Running**
```bash
cd ../traefik
docker compose up -d
```
2. **DNS Configuration**
Point `registry.michaelschiemer.de` to your server IP (94.16.110.151)
3. **htpasswd Utility**
```bash
# Install if not available
sudo apt-get install apache2-utils
```
## Configuration
### 1. Create Environment File
```bash
cp .env.example .env
```
### 2. Generate Registry HTTP Secret
```bash
openssl rand -hex 32
```
Update `.env`:
```env
REGISTRY_HTTP_SECRET=<generated-secret>
```
### 3. Create Registry Users
```bash
# Create htpasswd file with first user
htpasswd -Bc auth/htpasswd admin
# Add additional users
htpasswd -B auth/htpasswd developer
# Verify users
cat auth/htpasswd
```
**Important**: Use `-B` (bcrypt) for best security. `-c` creates new file (only for first user).
## Deployment
### Initial Setup
```bash
# Ensure Traefik is running
docker network inspect traefik-public
# Create auth directory and users
mkdir -p auth
htpasswd -Bc auth/htpasswd admin
# Start registry
docker compose up -d
# Check logs
docker compose logs -f
# Verify health
docker compose ps
```
### Verify Deployment
```bash
# Test registry endpoint
curl https://registry.michaelschiemer.de/v2/
# Expected: Authentication required (401)
# Test with credentials
curl -u admin:yourpassword https://registry.michaelschiemer.de/v2/_catalog
# Expected: {"repositories":[]}
```
## Usage
### Docker Login
```bash
# Login to registry
docker login registry.michaelschiemer.de
# Enter username and password when prompted
```
### Push Images
```bash
# Tag local image for registry
docker tag myapp:latest registry.michaelschiemer.de/myapp:latest
# Push to registry
docker push registry.michaelschiemer.de/myapp:latest
```
### Pull Images
```bash
# Pull from registry
docker pull registry.michaelschiemer.de/myapp:latest
```
### List Images
```bash
# List all repositories
curl -u admin:password https://registry.michaelschiemer.de/v2/_catalog
# List tags for repository
curl -u admin:password https://registry.michaelschiemer.de/v2/myapp/tags/list
```
### Delete Images
```bash
# Get image digest
curl -I -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-u admin:password \
https://registry.michaelschiemer.de/v2/myapp/manifests/latest
# Delete by digest
curl -X DELETE -u admin:password \
https://registry.michaelschiemer.de/v2/myapp/manifests/sha256:...
# Run garbage collection
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
```
## Integration with Other Stacks
### Gitea Actions (Stack 2)
Push built images from Gitea Actions:
```yaml
# .gitea/workflows/build.yml
name: Build and Push
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Login to Registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | \
docker login registry.michaelschiemer.de \
-u "${{ secrets.REGISTRY_USER }}" \
--password-stdin
- name: Build and Push
run: |
docker build -t registry.michaelschiemer.de/myapp:${{ github.sha }} .
docker push registry.michaelschiemer.de/myapp:${{ github.sha }}
```
### Application Stack (Stack 4)
Pull images in application deployment:
```yaml
# In application docker-compose.yml
services:
app:
image: registry.michaelschiemer.de/myapp:latest
# ... rest of configuration
```
**Note**: Ensure Docker daemon has registry credentials configured.
## User Management
### Add User
```bash
# Add new user
htpasswd -B auth/htpasswd newuser
# Restart registry to apply
docker compose restart
```
### Remove User
```bash
# Edit htpasswd file and remove user line
nano auth/htpasswd
# Restart registry
docker compose restart
```
### Change Password
```bash
# Update password (removes old entry)
htpasswd -B auth/htpasswd username
# Restart registry
docker compose restart
```
## Backup & Recovery
### Manual Backup
```bash
#!/bin/bash
# backup-registry.sh
BACKUP_DIR="/backups/registry"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# Backup registry data
docker run --rm \
-v registry-data:/data \
-v $BACKUP_DIR:/backup \
alpine tar czf /backup/registry-data-$DATE.tar.gz -C /data .
# Backup auth configuration
tar czf $BACKUP_DIR/registry-auth-$DATE.tar.gz auth/
echo "Backup completed: $BACKUP_DIR/*-$DATE.tar.gz"
```
### Restore from Backup
```bash
# Stop registry
docker compose down
# Restore registry data
docker run --rm \
-v registry-data:/data \
-v /backups/registry:/backup \
alpine tar xzf /backup/registry-data-YYYYMMDD_HHMMSS.tar.gz -C /data
# Restore auth
tar xzf /backups/registry/registry-auth-YYYYMMDD_HHMMSS.tar.gz
# Start registry
docker compose up -d
```
### Automated Backups
Add to crontab:
```bash
# Daily backup at 3 AM
0 3 * * * /path/to/backup-registry.sh
# Keep only last 14 days
0 4 * * * find /backups/registry -type f -mtime +14 -delete
```
## Monitoring
### Health Checks
```bash
# Check registry health
docker compose ps
# Registry health endpoint
curl -f https://registry.michaelschiemer.de/v2/
# Check storage usage
docker exec registry du -sh /var/lib/registry
```
### Logs
```bash
# View logs
docker compose logs -f
# Check for errors
docker compose logs registry | grep -i error
# Monitor access logs
docker compose logs -f registry | grep "GET /v2"
```
### Storage Statistics
```bash
# Check volume size
docker volume inspect registry-data
# Check disk usage
docker system df -v | grep registry
# List images in registry
curl -u admin:password https://registry.michaelschiemer.de/v2/_catalog | jq
```
## Garbage Collection
### Manual Garbage Collection
```bash
# Run garbage collection
docker exec registry bin/registry garbage-collect \
/etc/docker/registry/config.yml
# With dry-run
docker exec registry bin/registry garbage-collect \
--dry-run \
/etc/docker/registry/config.yml
```
### Scheduled Garbage Collection
Add to crontab (on production server):
```bash
# Weekly garbage collection (Sunday 2 AM)
0 2 * * 0 docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
```
**Note**: Automatic upload purging is enabled (168h old uploads cleaned every 24h).
## Troubleshooting
### Authentication Failed
```bash
# Check htpasswd file exists
ls -la auth/htpasswd
# Verify htpasswd format (should be bcrypt)
cat auth/htpasswd
# Format: username:$2y$...
# Test authentication
curl -u username:password https://registry.michaelschiemer.de/v2/
# Check registry logs
docker compose logs registry | grep auth
```
### Cannot Push Images
```bash
# Verify Docker login
cat ~/.docker/config.json | grep registry.michaelschiemer.de
# Re-login
docker logout registry.michaelschiemer.de
docker login registry.michaelschiemer.de
# Check storage space
df -h /var/lib/docker
# Check registry logs
docker compose logs -f registry
```
### SSL Certificate Issues
```bash
# Verify Traefik certificate
docker exec traefik cat /acme.json | grep registry.michaelschiemer.de
# Force certificate renewal (via Traefik)
# Remove acme.json and restart Traefik
# Test SSL
openssl s_client -connect registry.michaelschiemer.de:443 -servername registry.michaelschiemer.de < /dev/null
```
### Registry Not Accessible
```bash
# Check service is running
docker compose ps
# Check Traefik routing
docker exec traefik cat /etc/traefik/traefik.yml
# Check network
docker network inspect traefik-public | grep registry
# Test from server
curl -k https://localhost:5000/v2/
```
### Storage Issues
```bash
# Check volume mount
docker exec registry df -h /var/lib/registry
# Check for corrupted layers
docker exec registry find /var/lib/registry -type f -name "data" | wc -l
# Run garbage collection
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.yml
# Check for orphaned data
docker volume prune
```
## Security
### Security Best Practices
1. **Strong Passwords**: Use bcrypt (htpasswd -B) with strong passwords
2. **SSL Only**: Always use HTTPS (enforced via Traefik)
3. **User Management**: Regularly review and rotate credentials
4. **Access Logging**: Monitor access logs for suspicious activity
5. **Firewall**: Only expose port 443 (handled by Traefik)
6. **Backup Encryption**: Encrypt backups containing sensitive data
7. **Minimal Permissions**: Limit registry access to necessary users
### Update Stack
```bash
# Pull latest images
docker compose pull
# Recreate containers
docker compose up -d
# Verify
docker compose ps
```
### Security Headers
Security headers are applied via Traefik's `default-chain@file` middleware:
- HSTS
- Content-Type Nosniff
- XSS Protection
- Frame Deny
## Docker Daemon Configuration
### Configure Docker to Trust Registry
On machines that will push/pull from registry:
```bash
# Edit daemon.json
sudo nano /etc/docker/daemon.json
```
Add:
```json
{
"insecure-registries": [],
"registry-mirrors": [],
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
```
**Note**: No need to add registry to `insecure-registries` since we use SSL.
```bash
# Restart Docker
sudo systemctl restart docker
# Verify
docker info | grep Registry
```
### Configure Credentials
```bash
# Login once per machine
docker login registry.michaelschiemer.de
# Credentials stored in ~/.docker/config.json
```
## Performance Tuning
### Registry Configuration
For high-traffic registries, edit `docker-compose.yml`:
```yaml
environment:
# Increase concurrent operations
- REGISTRY_STORAGE_MAXCONCURRENCY=50
# Cache settings
- REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR=inmemory
# Rate limiting
- REGISTRY_HTTP_RATELIMIT_REQUESTS_PER_SECOND=100
```
### Storage Optimization
```bash
# Enable compression for layers (reduces storage)
# Already enabled in v2.8
# Monitor storage growth
du -sh /var/lib/docker/volumes/registry-data/
# Schedule regular garbage collection
# See "Scheduled Garbage Collection" section
```
## Migration from Docker Hub
### Pull and Re-push Images
```bash
#!/bin/bash
# migrate-images.sh
IMAGES=(
"nginx:latest"
"node:18-alpine"
"postgres:14"
)
for image in "${IMAGES[@]}"; do
echo "Migrating $image..."
# Pull from Docker Hub
docker pull $image
# Tag for private registry
docker tag $image registry.michaelschiemer.de/$image
# Push to private registry
docker push registry.michaelschiemer.de/$image
echo "✅ Migrated $image"
done
```
## API Reference
### Registry API v2
```bash
# List catalog
GET /v2/_catalog
# List tags
GET /v2/<name>/tags/list
# Get manifest
GET /v2/<name>/manifests/<reference>
# Delete manifest
DELETE /v2/<name>/manifests/<digest>
# Check blob exists
HEAD /v2/<name>/blobs/<digest>
```
**Authentication**: All endpoints require BasicAuth.
**Documentation**: https://docs.docker.com/registry/spec/api/
## Additional Resources
- **Docker Registry Documentation**: https://docs.docker.com/registry/
- **Registry Configuration**: https://docs.docker.com/registry/configuration/
- **Storage Drivers**: https://docs.docker.com/registry/storage-drivers/
- **Token Authentication**: https://docs.docker.com/registry/spec/auth/token/