MinIO como Backend de Almacenamiento para Docker Registry
MinIO es un sistema de almacenamiento de objetos compatible con la API de S3 que puedes usar como backend de almacenamiento para Docker Registry, reemplazando el almacenamiento local con una solución escalable y redundante. Esta combinación permite centralizar el almacenamiento de imágenes de contenedores con alta disponibilidad, recolección de basura automatizada y soporte TLS, manteniendo todo en tu propia infraestructura.
Requisitos Previos
- Servidor Linux con Docker y Docker Compose
- Mínimo 4 GB de RAM (8 GB recomendado para producción)
- Almacenamiento suficiente para las imágenes Docker
- Dominio con HTTPS para el registro
- Acceso root o sudo
Instalación de MinIO
# Crear directorios de trabajo
mkdir -p /opt/minio/{data,config}
cd /opt/minio
# Descargar MinIO (instalación directa)
wget https://dl.min.io/server/minio/release/linux-amd64/minio \
-O /usr/local/bin/minio
chmod +x /usr/local/bin/minio
# Descargar el cliente MinIO
wget https://dl.min.io/client/mc/release/linux-amd64/mc \
-O /usr/local/bin/mc
chmod +x /usr/local/bin/mc
# Verificar instalación
minio --version
mc --version
Crea el servicio systemd para MinIO:
# Crear usuario dedicado
sudo useradd -r -s /sbin/nologin minio
sudo mkdir -p /data/minio
sudo chown minio:minio /data/minio
sudo tee /etc/systemd/system/minio.service << 'EOF'
[Unit]
Description=MinIO Object Storage
After=network.target
[Service]
Type=notify
User=minio
Group=minio
EnvironmentFile=/etc/minio/minio.env
ExecStart=/usr/local/bin/minio server $MINIO_VOLUMES \
--console-address ":9001"
Restart=always
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
# Crear fichero de variables de entorno
sudo mkdir -p /etc/minio
sudo tee /etc/minio/minio.env << 'EOF'
# Credenciales de acceso a MinIO
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=CAMBIA_ESTA_CONTRASEÑA_SEGURA
# Ruta de almacenamiento
MINIO_VOLUMES="/data/minio"
# URL pública (para generación de URLs pre-firmadas)
MINIO_SERVER_URL=https://s3.tudominio.com
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now minio
# Verificar que está funcionando
sudo systemctl status minio
curl http://localhost:9000/minio/health/live
Configuración del Bucket para Docker Registry
Configura el cliente mc y crea el bucket:
# Configurar el cliente mc apuntando a MinIO
mc alias set local http://localhost:9000 minioadmin TU_CONTRASEÑA
# Verificar la conexión
mc admin info local
# Crear el bucket para Docker Registry
mc mb local/docker-registry
# Configurar el bucket como privado (no acceso público)
mc anonymous set none local/docker-registry
# Crear usuario específico para Docker Registry (mejor práctica de seguridad)
mc admin user add local registryuser CONTRASEÑA_REGISTRY_USER
# Crear política de acceso al bucket
mc admin policy create local registry-policy /dev/stdin << 'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:ListBucketMultipartUploads"
],
"Resource": ["arn:aws:s3:::docker-registry"]
},
{
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload",
"s3:DeleteObject",
"s3:GetObject",
"s3:ListMultipartUploadParts",
"s3:PutObject"
],
"Resource": ["arn:aws:s3:::docker-registry/*"]
}
]
}
EOF
# Asignar la política al usuario del registro
mc admin policy attach local registry-policy --user registryuser
Despliegue de Docker Registry con MinIO
mkdir -p /opt/docker-registry
cd /opt/docker-registry
# Crear configuración del registro
tee config.yml << 'EOF'
version: 0.1
log:
level: info
formatter: json
storage:
s3:
accesskey: registryuser
secretkey: CONTRASEÑA_REGISTRY_USER
regionendpoint: http://localhost:9000
bucket: docker-registry
region: us-east-1 # Valor requerido aunque MinIO no lo use
encrypt: false
secure: false # True si MinIO usa HTTPS
v4auth: true
chunksize: 5242880 # 5MB en bytes
rootdirectory: /registry
delete:
enabled: true # Habilitar borrado de capas/manifiestos
maintenance:
uploadpurging:
enabled: true
age: 168h # Limpiar uploads incompletos después de 7 días
interval: 24h
dryrun: false
http:
addr: :5000
secret: GENERA_UN_SECRET_ALEATORIO_AQUI
auth:
htpasswd:
realm: "Docker Registry"
path: /auth/htpasswd
EOF
# Crear directorio de autenticación
mkdir -p /opt/docker-registry/auth
# Crear usuario de acceso al registro
docker run --rm --entrypoint htpasswd \
httpd:2 -Bbn admin CONTRASEÑA_ADMIN \
> /opt/docker-registry/auth/htpasswd
# Docker Compose para el registro
tee docker-compose.yml << 'EOF'
version: "3.8"
services:
registry:
image: registry:2
container_name: docker-registry
restart: unless-stopped
ports:
- "5000:5000"
environment:
REGISTRY_HTTP_ADDR: 0.0.0.0:5000
volumes:
- ./config.yml:/etc/docker/registry/config.yml:ro
- ./auth:/auth:ro
EOF
docker compose up -d
docker compose logs -f registry
Configuración TLS
Configura HTTPS para el registro Docker:
# Obtener certificado SSL para el registro
sudo certbot certonly --standalone \
-d registry.tudominio.com
# Actualizar docker-compose.yml para usar TLS
tee /opt/docker-registry/docker-compose.yml << 'EOF'
version: "3.8"
services:
registry:
image: registry:2
container_name: docker-registry
restart: unless-stopped
ports:
- "443:5000"
volumes:
- ./config.yml:/etc/docker/registry/config.yml:ro
- ./auth:/auth:ro
- /etc/letsencrypt/live/registry.tudominio.com:/certs:ro
environment:
REGISTRY_HTTP_TLS_CERTIFICATE: /certs/fullchain.pem
REGISTRY_HTTP_TLS_KEY: /certs/privkey.pem
EOF
docker compose up -d
# Probar el registro con TLS
docker login registry.tudominio.com
docker pull ubuntu:22.04
docker tag ubuntu:22.04 registry.tudominio.com/ubuntu:22.04
docker push registry.tudominio.com/ubuntu:22.04
Recolección de Basura
Docker Registry almacena capas huérfanas cuando se borran imágenes. Ejecuta el recolector de basura regularmente:
# Ver el espacio usado antes de la limpieza
mc du local/docker-registry
# Listar manifiestos en el registro (para referencia)
curl -u admin:CONTRASEÑA \
https://registry.tudominio.com/v2/_catalog
# Ejecutar recolección de basura en modo dry-run primero
docker exec docker-registry registry garbage-collect \
--dry-run /etc/docker/registry/config.yml
# Ejecutar la recolección de basura real
# IMPORTANTE: El registro debe estar en modo solo-lectura o parado
docker exec docker-registry registry garbage-collect \
--delete-untagged /etc/docker/registry/config.yml
# Automatizar con cron (ejecutar en modo solo-lectura)
sudo tee /etc/cron.weekly/registry-gc << 'EOF'
#!/bin/bash
# Poner el registro en modo solo lectura
docker exec docker-registry \
sed -i 's/# readonly: false/readonly: true/' /etc/docker/registry/config.yml
# Ejecutar garbage collection
docker exec docker-registry registry garbage-collect \
--delete-untagged /etc/docker/registry/config.yml
# Restaurar modo escritura
docker exec docker-registry \
sed -i 's/readonly: true/# readonly: false/' /etc/docker/registry/config.yml
# Reiniciar el registro
docker restart docker-registry
EOF
chmod +x /etc/cron.weekly/registry-gc
Alta Disponibilidad
Para entornos de producción con alta disponibilidad:
# docker-compose-ha.yml - Múltiples réplicas del registro
version: "3.8"
services:
registry-1:
image: registry:2
volumes:
- ./config.yml:/etc/docker/registry/config.yml:ro
- ./auth:/auth:ro
registry-2:
image: registry:2
volumes:
- ./config.yml:/etc/docker/registry/config.yml:ro
- ./auth:/auth:ro
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- /etc/letsencrypt:/etc/letsencrypt:ro
depends_on:
- registry-1
- registry-2
Configuración de MinIO en modo distribuido para HA:
# MinIO en modo distribuido con 4 nodos
# En cada nodo, crear el mismo servicio apuntando a todos
MINIO_ROOT_USER=admin \
MINIO_ROOT_PASSWORD=contraseña \
minio server \
http://nodo1.tudominio.com/data \
http://nodo2.tudominio.com/data \
http://nodo3.tudominio.com/data \
http://nodo4.tudominio.com/data \
--console-address ":9001"
Solución de Problemas
Error "blob unknown" al hacer pull:
# Verificar que el bucket existe y tiene los datos
mc ls local/docker-registry/registry/
# Comprobar permisos del usuario del registro en MinIO
mc admin policy ls local
mc admin user info local registryuser
Error de autenticación en el registro:
# Probar las credenciales del htpasswd
docker run --rm --entrypoint htpasswd \
httpd:2 -v /tmp/htpasswd admin
# Ver los logs del registro para más detalles
docker logs docker-registry --tail 50
Recolección de basura no libera espacio:
# Verificar que las imágenes están realmente desreferenciadas
# Primero borrar los tags manualmente
curl -X DELETE -u admin:CONTRASEÑA \
"https://registry.tudominio.com/v2/imagen/manifests/$(
curl -u admin:CONTRASEÑA \
"https://registry.tudominio.com/v2/imagen/manifests/latest" \
-H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-I | grep Docker-Content-Digest | awk '{print $2}'
)"
Conclusión
La combinación de MinIO y Docker Registry proporciona una solución de almacenamiento de imágenes de contenedores completamente autoalojada, escalable y compatible con los flujos de trabajo estándar de Docker. MinIO ofrece la capacidad de crecer horizontalmente con el tiempo, mientras que Docker Registry mantiene compatibilidad total con el ecosistema de herramientas existente. Implementa la recolección de basura regularmente para mantener el uso del almacenamiento bajo control.


