Registro de Docker Private Configuración

A private Docker registro allows your organization to store, manage, and distribute contenedor imágenes securely without relying on public registries. Esta guía completa cubre installing, configuring, and maintaining a Registro de Docker instance with authentication, TLS encryption, almacenamiento backends, and garbage collection. By hosting your own registro, you gain complete control over imagen distribution, improve deployment speed with local caching, and eliminate external dependencies for CI/CD pipelines.

Tabla de Contenidos

Comprendiendo Registro de Docker

Registro de Docker is the official Docker imagen distribution system. The registro:2 imagen proporciona a stateless, highly scalable application for managing and distributing imágenes. Comprendiendo its architecture is essential for production deployments.

Registro components:

  • Registro API server: Handles imagen push/pull operations
  • Almacenamiento driver: Persists imagen layers to filesystem, cloud almacenamiento, or object almacenamiento
  • Authentication capa: Verifies client identity
  • Garbage collection: Removes unreferenced blobs and layers
  • Notification system: Emits events on imagen operations
# Pull official registro:2 imagen
docker pull registro:2

# Verifica imagen
docker imágenes | grep registro

# Check registro version
docker run --rm registro:2 /bin/registro --version

Key concepts:

  • Blobs: Individual imagen layers and configurations
  • Manifests: JSON documents describing imagen structure
  • Repositories: Collections of related imagen tags
  • Tags: Human-readable references to specific imagen versions

Installing Registro de Docker

Despliega a registro instance with persistent almacenamiento for development and testing environments.

Basic registro setup:

# Crea data directory with proper permissions
sudo mkdir -p /opt/registro/data
sudo chown -R 1000:1000 /opt/registro/data
sudo chmod 755 /opt/registro/data

# Ejecuta registro contenedor
docker run -d \
  --name registro \
  --restart always \
  -p 5000:5000 \
  -v /opt/registro/data:/var/lib/registro \
  registro:2

# Verifica registro is running
docker ps | grep registro

# Prueba registro health
curl http://localhost:5000/v2/

Configura environment variables for registro:

# Crea environment file
cat > /opt/registro/registro.env <<EOF
REGISTRY_LOG_LEVEL=info
REGISTRY_STORAGE_DELETE_ENABLED=true
REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR=inmemory
REGISTRY_HTTP_ADDR=0.0.0.0:5000
REGISTRY_HTTP_RELATIVEURLS=true
EOF

# Ejecuta with environment file
docker run -d \
  --name registro \
  --restart always \
  -p 5000:5000 \
  --env-file /opt/registro/registro.env \
  -v /opt/registro/data:/var/lib/registro \
  registro:2

# Verifica environment applied
docker exec registro env | grep REGISTRY

Using docker-compose for registro:

# Crea docker-compose.yml
cat > /opt/registro/docker-compose.yml <<EOF
version: '3.9'

servicios:
  registro:
    imagen: registro:2
    container_name: docker-registro
    restart: always
    puertos:
      - "5000:5000"
    volúmenes:
      - /opt/registro/data:/var/lib/registro
      - /opt/registro/config.yml:/etc/docker/registro/config.yml
    environment:
      REGISTRY_LOG_LEVEL: info
      REGISTRY_STORAGE_DELETE_ENABLED: "true"

EOF

# Inicia registro
docker-compose -f /opt/registro/docker-compose.yml up -d

# Check logs
docker-compose -f /opt/registro/docker-compose.yml logs -f registro

Configuring TLS/SSL Encryption

TLS encryption is essential for production deployments to protect imagen transmission and credentials.

Generate self-signed certificates (development only):

# Crea certificate directory
sudo mkdir -p /opt/registro/certs
cd /opt/registro/certs

# Generate private key
openssl genrsa -out domain.key 2048

# Generate certificate (valid 365 days)
openssl req -new \
  -x509 \
  -key domain.key \
  -out domain.crt \
  -days 365 \
  -subj "/CN=registro.example.com"

# Verifica certificate
openssl x509 -in domain.crt -text -noout

Generate CA-signed certificates (production):

# Crea private key
openssl genrsa -out /opt/registro/certs/domain.key 2048

# Crea certificate signing request
openssl req -new \
  -key /opt/registro/certs/domain.key \
  -out /opt/registro/certs/domain.csr \
  -subj "/CN=registro.example.com" \
  -addext "subjectAltName=DNS:registro.example.com,DNS:*.registro.example.com,IP:192.168.1.100"

# Submit CSR to CA and receive domain.crt (obtained from your certificate provider)

# Verifica certificate chain
openssl verifica -CAfile ca.crt domain.crt

Configura registro with TLS:

# Set certificate permissions
sudo chmod 600 /opt/registro/certs/domain.key
sudo chmod 644 /opt/registro/certs/domain.crt

# Ejecuta registro with TLS
docker run -d \
  --name registro \
  --restart always \
  -p 443:5000 \
  -v /opt/registro/data:/var/lib/registro \
  -v /opt/registro/certs:/certs \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  registro:2

# Verifica HTTPS
curl --cacert /opt/registro/certs/domain.crt https://registro.example.com/v2/

Configura client to trust self-signed certificate:

# Copy certificate to Docker daemon config
sudo mkdir -p /etc/docker/certs.d/registro.example.com:443
sudo cp /opt/registro/certs/domain.crt \
  /etc/docker/certs.d/registro.example.com:443/ca.crt

# Reload Docker daemon
sudo systemctl reload docker

# Prueba pull/push
docker pull registro.example.com/myimage:latest

Implementing Authentication

Asegura your registro with authentication using htpasswd or other methods.

Basic htpasswd authentication:

# Crea password file
mkdir -p /opt/registro/auth
docker run --rm \
  --entrypoint htpasswd \
  registro:2 -Bbc /dev/stdout admin password123 > /opt/registro/auth/htpasswd

# Set proper permissions
sudo chmod 600 /opt/registro/auth/htpasswd

# View password file
sudo cat /opt/registro/auth/htpasswd

# Add another user
docker run --rm \
  --entrypoint htpasswd \
  -v /opt/registro/auth:/auth \
  registro:2 -Bbc /auth/htpasswd developer mypassword

Ejecuta registro with authentication:

# Detén previous registro
docker rm -f registro

# Ejecuta with auth
docker run -d \
  --name registro \
  --restart always \
  -p 5000:5000 \
  -v /opt/registro/data:/var/lib/registro \
  -v /opt/registro/auth:/auth \
  -v /opt/registro/certs:/certs \
  -e REGISTRY_AUTH=htpasswd \
  -e REGISTRY_AUTH_HTPASSWD_REALM="Registro Realm" \
  -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
  -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
  -e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
  registro:2

# Prueba authentication
docker login -u admin -p password123 registro.example.com

# Push imagen
docker tag myimage:latest registro.example.com/myimage:latest
docker push registro.example.com/myimage:latest

# View login credentials
cat ~/.docker/config.json

Token-based authentication (advanced):

# Crea auth server configuration
cat > /opt/registro/auth-config.json <<EOF
{
  "server": "https://auth.example.com/token",
  "issuer": "myissuer",
  "rootcertbundle": "/certs/ca.crt"
}
EOF

# Ejecuta registro with token auth
docker run -d \
  --name registro \
  --restart always \
  -p 5000:5000 \
  -v /opt/registro/data:/var/lib/registro \
  -v /opt/registro/certs:/certs \
  -e REGISTRY_AUTH=token \
  -e REGISTRY_AUTH_TOKEN_REALM=https://auth.example.com/token \
  -e REGISTRY_AUTH_TOKEN_SERVICE="Docker registro" \
  -e REGISTRY_AUTH_TOKEN_ISSUER=myissuer \
  -e REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/ca.crt \
  registro:2

Almacenamiento Backend Configuración

Configura different almacenamiento backends based on your infrastructure requirements.

Local filesystem almacenamiento (default):

# Already configured in basic setup
# Almacenamiento is at /var/lib/registro in contenedor

# Inspect almacenamiento
docker exec registro ls -la /var/lib/registro/docker/registro/v2/

AWS S3 almacenamiento backend:

# Crea registro config with S3 backend
cat > /opt/registro/config.yml <<EOF
version: 0.1
log:
  level: info
almacenamiento:
  s3:
    accesskey: AKIAIOSFODNN7EXAMPLE
    secretkey: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
    region: us-east-1
    bucket: my-docker-registro
    encrypt: true
    secure: true
    v4auth: true
    rootdirectory: /docker-registro
http:
  addr: :5000
  relativeurls: true
EOF

# Ejecuta registro with S3
docker run -d \
  --name registro \
  --restart always \
  -p 5000:5000 \
  -v /opt/registro/config.yml:/etc/docker/registro/config.yml \
  registro:2

# Verifica S3 connectivity
docker logs registro | grep -i s3

Azure Blob Almacenamiento backend:

# Crea registro config for Azure
cat > /opt/registro/config.yml <<EOF
version: 0.1
almacenamiento:
  azure:
    accountname: myaccount
    accountkey: ACCOUNT_KEY_HERE
    contenedor: docker-registro
    realm: core.windows.net
http:
  addr: :5000
EOF

# Ejecuta registro with Azure
docker run -d \
  --name registro \
  --restart always \
  -p 5000:5000 \
  -v /opt/registro/config.yml:/etc/docker/registro/config.yml \
  registro:2

Configura cache capa for performance:

# Crea config with Redis cache
cat > /opt/registro/config.yml <<EOF
version: 0.1
almacenamiento:
  filesystem:
    rootdirectory: /var/lib/registro
  cache:
    blobdescriptor: redis
  redis:
    addr: redis:6379
    db: 0
    dialtimeout: 10ms
    readtimeout: 10ms
    writetimeout: 10ms
    pool:
      maxidle: 16
      maxactive: 64
      idletimeout: 300s
http:
  addr: :5000
  relativeurls: true
EOF

# Actualiza docker-compose to include Redis
cat > /opt/registro/docker-compose.yml <<EOF
version: '3.9'

servicios:
  redis:
    imagen: redis:7-alpine
    container_name: registro-redis
    restart: always
    puertos:
      - "6379:6379"

  registro:
    imagen: registro:2
    container_name: docker-registro
    restart: always
    puertos:
      - "5000:5000"
    depends_on:
      - redis
    volúmenes:
      - /opt/registro/data:/var/lib/registro
      - /opt/registro/config.yml:/etc/docker/registro/config.yml
    environment:
      REGISTRY_LOG_LEVEL: info

EOF

docker-compose -f /opt/registro/docker-compose.yml up -d

Setting Up Nginx Frontend

Nginx proporciona reverse proxy functionality, load balancing, and additional security for your registro.

Instala and configure Nginx:

# Instala Nginx
sudo apt-get update
sudo apt-get install -y nginx

# Crea Nginx config for registro
sudo tee /etc/nginx/sites-available/registro > /dev/null <<EOF
upstream registro {
    server localhost:5000;
}

server {
    listen 443 ssl http2;
    server_name registro.example.com;

    ssl_certificate /opt/registro/certs/domain.crt;
    ssl_certificate_key /opt/registro/certs/domain.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    client_max_body_size 0;

    location / {
        proxy_pass http://registro;
        proxy_set_header Host \$http_host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_buffering off;
        proxy_request_buffering off;
    }
}

server {
    listen 80;
    server_name registro.example.com;
    return 301 https://\$server_name\$request_uri;
}
EOF

# Habilita site
sudo ln -sf /etc/nginx/sites-available/registro /etc/nginx/sites-enabled/registro

# Prueba Nginx config
sudo nginx -t

# Inicia Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

Configura Nginx for caching and compression:

# Actualiza Nginx config with caching
sudo tee /etc/nginx/sites-available/registro > /dev/null <<EOF
upstream registro {
    server localhost:5000;
    keepalive 32;
}

proxy_cache_path /var/cache/nginx/docker-registro levels=1:2 keys_zone=registry_cache:10m max_size=1g inactive=60d use_temp_path=off;

server {
    listen 443 ssl http2;
    server_name registro.example.com;

    ssl_certificate /opt/registro/certs/domain.crt;
    ssl_certificate_key /opt/registro/certs/domain.key;

    gzip on;
    gzip_types application/json;

    client_max_body_size 0;

    location /v2/ {
        proxy_pass http://registro;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host \$http_host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;

        # Cache GET requests
        proxy_cache registry_cache;
        proxy_cache_key "\$scheme\$request_method\$host\$request_uri";
        proxy_cache_valid 200 60d;
        proxy_cache_valid 404 10m;
        proxy_cache_bypass \$http_pragma \$http_authorization;
    }
}
EOF

# Reload Nginx
sudo systemctl reload nginx

Gestionando Imágenes and Garbage Collection

Efficiently manage imágenes and free up disk space with garbage collection.

Manually trigger garbage collection:

# Ejecuta garbage collection
docker exec registro bin/registro garbage-collect /etc/docker/registro/config.yml

# Check disk usage before
df -h /opt/registro/data

# Ejecuta collection with verbose output
docker exec registro bin/registro garbage-collect -d /etc/docker/registro/config.yml

# Check disk usage after
df -h /opt/registro/data

Schedule regular garbage collection:

# Crea cron job
sudo crontab -e

# Add line to run daily at 2 AM
0 2 * * * docker exec registro bin/registro garbage-collect /etc/docker/registro/config.yml >> /var/log/registro-gc.log 2>&1

# View scheduled jobs
sudo crontab -l

Elimina specific imágenes or tags:

# Elimina imagen by manifest digest
curl -X DELETE http://localhost:5000/v2/myimage/manifests/sha256:abc123def456

# List all repositories
curl http://localhost:5000/v2/_catalog

# List tags for repositorio
curl http://localhost:5000/v2/myimage/tags/list

# Get manifest digest
curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
  -X GET http://localhost:5000/v2/myimage/manifests/latest | grep -i docker-content-digest

# Elimina old tag
curl -X DELETE \
  http://localhost:5000/v2/myimage/manifests/sha256:abc123...

# Ejecuta cleanup after deletion
docker exec registro bin/registro garbage-collect /etc/docker/registro/config.yml

Implement retention policies:

# Crea cleanup script
cat > /opt/registro/cleanup.sh <<'EOF'
#!/bin/bash

REGISTRY="http://localhost:5000"
KEEP_TAGS=5

for repo in $(curl -s $REGISTRY/v2/_catalog | jq -r '.repositories[]'); do
    echo "Processing $repo..."
    
    # Get all tags sorted by date
    tags=$(curl -s $REGISTRY/v2/$repo/tags/list | jq -r '.tags[] // empty' | sort -r)
    
    tag_count=0
    for tag in $tags; do
        tag_count=$((tag_count + 1))
        if [ $tag_count -gt $KEEP_TAGS ]; then
            # Get manifest digest
            digest=$(curl -I -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
              -s $REGISTRY/v2/$repo/manifests/$tag | grep -i docker-content-digest | cut -d' ' -f2 | tr -d '\r')
            
            # Elimina old tag
            curl -X DELETE $REGISTRY/v2/$repo/manifests/$digest
            echo "Deleted $repo:$tag"
        fi
    done
done

# Ejecuta garbage collection
docker exec registro bin/registro garbage-collect /etc/docker/registro/config.yml
EOF

chmod +x /opt/registro/cleanup.sh

# Ejecuta cleanup
/opt/registro/cleanup.sh

High Availability Registro

Configura multiple registro instances for high availability and load distribution.

Configuración with load balancer:

# Crea docker-compose for multiple registries
cat > /opt/registro/docker-compose-ha.yml <<EOF
version: '3.9'

servicios:
  registry1:
    imagen: registro:2
    restart: always
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registro
      REGISTRY_LOG_LEVEL: info
    volúmenes:
      - /opt/registro/data:/var/lib/registro
      - /opt/registro/config.yml:/etc/docker/registro/config.yml
    redes:
      - registro-net

  registry2:
    imagen: registro:2
    restart: always
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registro
      REGISTRY_LOG_LEVEL: info
    volúmenes:
      - /opt/registro/data:/var/lib/registro
      - /opt/registro/config.yml:/etc/docker/registro/config.yml
    redes:
      - registro-net

  nginx-lb:
    imagen: nginx:alpine
    restart: always
    puertos:
      - "5000:5000"
    volúmenes:
      - /opt/registro/nginx-lb.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - registry1
      - registry2
    redes:
      - registro-net

redes:
  registro-net:

EOF

# Crea load balancer config
cat > /opt/registro/nginx-lb.conf <<EOF
events {
    worker_connections 1024;
}

http {
    upstream registry_backend {
        server registry1:5000;
        server registry2:5000;
    }

    server {
        listen 5000;
        client_max_body_size 0;

        location / {
            proxy_pass http://registry_backend;
            proxy_set_header Host \$http_host;
            proxy_set_header X-Real-IP \$remote_addr;
            proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto \$scheme;
            proxy_buffering off;
            proxy_request_buffering off;
        }
    }
}
EOF

# Inicia HA setup
docker-compose -f /opt/registro/docker-compose-ha.yml up -d

# Verifica all servicios
docker-compose -f /opt/registro/docker-compose-ha.yml ps

Monitoreo and Mantenimiento

Monitorea registro health, track metrics, and maintain reliable operation.

Habilita registro metrics:

# Crea config with Prometheus metrics
cat > /opt/registro/config.yml <<EOF
version: 0.1
almacenamiento:
  filesystem:
    rootdirectory: /var/lib/registro
http:
  addr: :5000
  relativeurls: true
metrics:
  enabled: true
  prometheus:
    namespace: registro
    subsystem: almacenamiento
EOF

# Access metrics endpoint
curl http://localhost:5000/metrics

# Example metrics:
# registry_storage_action_seconds_bucket{action="blobstore_upload",le="+Inf"} 5
# registry_storage_action_seconds_sum{action="blobstore_upload"} 0.25
# registry_storage_action_seconds_count{action="blobstore_upload"} 1

Health verifica configuration:

# Prueba registro health
curl -s http://localhost:5000/v2/ && echo "Registro is healthy" || echo "Registro is unhealthy"

# Add health verifica to contenedor
docker run -d \
  --name registro \
  --restart always \
  -p 5000:5000 \
  --health-cmd='curl -f http://localhost:5000/v2/ || exit 1' \
  --health-interval=30s \
  --health-timeout=10s \
  --health-retries=3 \
  -v /opt/registro/data:/var/lib/registro \
  registro:2

# Check health status
docker inspect registro --format='{{.State.Health.Status}}'

Monitorea disk usage and backups:

# Monitorea disk usage
du -sh /opt/registro/data

# Set up disk usage alert
cat > /opt/registro/verifica-disk.sh <<'EOF'
#!/bin/bash
USAGE=$(df /opt/registro/data | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $USAGE -gt 80 ]; then
    echo "WARNING: Registro disk usage at $USAGE%"
    # Ejecuta garbage collection
    docker exec registro bin/registro garbage-collect /etc/docker/registro/config.yml
fi
EOF

chmod +x /opt/registro/verifica-disk.sh

# Ejecuta periodically
0 */4 * * * /opt/registro/verifica-disk.sh >> /var/log/registro-disk.log 2>&1

Conclusión

A private Docker registro is an essential component of professional contenedor infrastructure. By implementing TLS encryption, authentication, and configurable almacenamiento backends, you create a secure, scalable imagen distribution system. Regular garbage collection, monitoring, and high availability configurations asegúrate de que long-term reliability. Whether you start with basic htpasswd authentication and local almacenamiento or scale to multi-instance deployments with S3 backends, the Registro de Docker proporciona a foundation for contenedor imagen management that supports your organization's growth. Invest time in proper configuration now to avoid operational headaches and security vulnerabilities as your contenedor usage expands.