Un registro de contenedores es un catálogo de almacenamiento desde el que se pueden enviar y extraer imágenes de contenedores.

Hay muchos registros públicos y privados disponibles para desarrolladores, como Docker Hub, Amazon ECR y Google Cloud Artifact Registry. Sin embargo, a veces, en lugar de confiar en un proveedor externo, podría querer hospedar las imágenes por sí mismo. Esto le brinda más control sobre cómo se configura el registro y dónde se hospedan las imágenes de los contenedores.

Este artículo es un tutorial práctico que le enseñará cómo hospedar un registro de contenedores por sí mismo.

Tabla de contenido

Sacará el máximo provecho de este artículo si ya es familiarizado con herramientas como Docker y NGINX, y tiene una comprensión general de qué es una imagen de contenedor.

¿Qué es una imagen de contenedor?

Antes de hablar acerca de los registros de contenedores, vamos a comprender qué es una imagen de contenedor. En resumen, una imagen de contenedor es un paquete que incluye todos los archivos, bibliotecas y configuraciones necesarias para ejecutar un contenedor. Están compuestos de capas donde cada capa representa un conjunto de cambios en el sistema de archivos que agrega, elimina o modifica archivos.

La forma más común para crear una imagen de contenedor es utilizar un Dockerfile.

# construir una imagen
docker build -t pliutau/hello-world:v0 .

# ver las imágenes localmente
docker images
# REPOSITORIO    TAG       IMAGE ID       CREATED          SIZE
# hello-world   latest    9facd12bbcdd   22 segundos ago   11MB

Esto crea una imagen de contenedor que se almacena en su máquina local. ¿Pero qué pasa si quieres compartir esta imagen con otros o utilizarla en una máquina diferente? Aquí es donde entra en juego los registros de contenedores.

¿Qué es un Registro de Contenedores?

Un registro de contenedores es un catálogo de almacenamiento donde puede empujar y tirar imágenes de contenedores. Las imágenes se agrupan en repositorios, que son colecciones de imágenes relacionadas con el mismo nombre. Por ejemplo, en el registro de Docker Hub, nginx es el nombre del repositorio que contiene diferentes versiones de las imágenes de NGINX.

Algunos registros son públicos, lo que significa que las imágenes alojadas en ellos son accesibles a cualquier persona en Internet. Los registros públicos como Docker Hub son una buena opción para alojar proyectos de código abierto.

Por otra parte, los registros privados proporcionan una manera de incorporar seguridad y privacidad en el almacenamiento de imágenes de contenedores de empresas, ya sean hospedados en la nube o en los locales. Estos registros privados a menudo vienen con funciones de seguridad avanzadas y soporte técnico.

Existe una lista creciente de registros privados disponibles, como Amazon ECR, GCP Artifact Registry, GitHub Container Registry, y Docker Hub ofrece también una función de repositorio privado.

Como desarrollador, interactúa con un registro de contenedores cuando utiliza los comandos docker push y docker pull.

docker push docker.io/pliutau/hello-world:v0

# En caso de Docker Hub podríamos también omitir la parte del registro
docker push pliutau/hello-world:v0

Veamos la anatomía de una URL de imagen de contenedor:

docker pull docker.io/pliutau/hello-world:v0@sha256:dc11b2...
                |            |            |          |
                ↓            ↓            ↓          ↓
             registry    repository      tag       digest

Por qué podría querer auto-hostear un registro de contenedores

A veces, en lugar de confiar en un proveedor como AWS o GCP, podría querer hospedar tus imágenes por sí mismo. Esto mantiene tu infraestructura interna y te hace menos dependiente de proveedores externos. En algunas industrias altamente reguladas, esto incluso es un requisito.

Un registro auto-hosteado se ejecuta en tus propias servidores, dándote más control sobre cómo se configura el registro y dónde se hospedan las imágenes de contenedores. Al mismo tiempo, esto implica un costo de mantenimiento y seguridad del registro.

Cómo auto-hostear un registro de contenedores

Hay varias soluciones de registro de contenedores de código abierto disponibles. La más popular es oficialmente apoyada por Docker, llamada registry, con su implementación para almacenar y distribuir imágenes y artefactos de contenedores. Esto significa que puedes ejecutar tu propio registro dentro de un contenedor.

Aquí están los pasos principales para ejecutar un registro en un servidor:

  • Instala Docker y Docker Compose en el servidor.

  • Configura y ejecuta el contenedor registry.

  • Ejecute NGINX para manejar TLS y reenviar solicitudes al contenedor de registro.

  • Configure certificados SSL y configura un dominio.

Paso 1: Instale Docker y Docker Compose en el servidor

Puede usar cualquier servidor que sea compatible con Docker. Por ejemplo, puede usar una Droplet de DigitalOcean con Ubuntu. Para esta demostración, use Google Cloud Compute para crear una VM con Ubuntu.

neofetch

# SO: Ubuntu 20.04.6 LTS x86_64
# CPU: Intel Xeon (2) @ 2.200GHz
# Memoria: 3908MiB

Una vez dentro de nuestra VM, deberíamos instalar Docker y Docker Compose. Docker Compose es opcional, pero facilita la administración de aplicaciones multi-contenedor.

# instale el motor de docker y docker-compose
sudo snap install docker

# verifique la instalación
docker --version
docker-compose --version

Paso 2: Configure y ejecute el contenedor de registro

Después necesitamos configurar nuestro contenedor de registro. El siguiente archivo compose.yaml creará un contenedor de registro con un volumen para almacenar las imágenes y un volumen para almacenar el archivo de contraseña.

services:
  registry:
    image: registry:latest
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      # Montar el archivo de contraseñas
      - ./registry/registry.password:/auth/registry.password
      # Montar el directorio de datos
      - ./registry/data:/data
    ports:
      - 5000

El archivo de contraseñas definido en REGISTRY_AUTH_HTPASSWD_PATH se utiliza para autenticar a los usuarios cuando intentan push o pull de imágenes desde el registro. Debemos crear un archivo de contraseñas usando el comando htpasswd. También debemos crear una carpeta para almacenar las imágenes.

mkdir -p ./registry/data

# instalar htpasswd
sudo apt install apache2-utils

# crear un archivo de contraseñas. nombre de usuario: busy, contraseña: bee
htpasswd -Bbn busy bee > ./registry/registry.password

Ahora podemos iniciar el contenedor de registro. Si ven este mensaje, entonces todo funciona como debería:

docker-compose up

# ejecución exitosa debería mostrar algo como esto:
# registry | level=info msg="listening on [::]:5000"

Paso 3: Ejecutar NGINX para manejar TLS

Como mencionamos anteriormente, podemos usar NGINX para manejar TLS y reenviar solicitudes al contenedor de registro.

El Registro de Docker requiere un certificado SSL válido y confiable para funcionar. Puedes usar algo como Let’s Encrypt o obtenerlo manualmente. Asegúrate de que tienes un nombre de dominio que apunte a tu servidor (registry.pliutau.com en mi caso). Para esta demostración, ya he obtenido los certificados usando certbot y los he colocado en el directorio ./nginx/certs.

Como estamos ejecutando nuestro Registry de Docker en un contenedor, también podemos ejecutar NGINX en un contenedor agregando el siguiente servicio al archivo compose.yaml:

services:
  registry:
    # ...
  nginx:
    image: nginx:latest
    depends_on:
      - registry
    volumes:
      # montar la configuración de nginx
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      # montar los certificados obtenidos de Let's Encrypt
      - ./nginx/certs:/etc/nginx/certs
    ports:
      - "443:443"

Nuestro archivo nginx.conf podría verse así:

worker_processes auto;

events {
    worker_connections 1024;
}

http {
    upstream registry {
        server registry:5000;
    }

    server {
        server_name registry.pliutau.com;
        listen 443 ssl;

        ssl_certificate /etc/nginx/certs/fullchain.pem;
        ssl_certificate_key /etc/nginx/certs/privkey.pem;

        location / {
            # configuración importante para imágenes grandes
            client_max_body_size                1000m;

            proxy_pass                          http://registry;
            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_read_timeout                  900;
        }
    }
}

Listo para empezar!

Después de estos pasos podemos ejecutar nuestros contenedores de registry y Nginx.

docker-compose up

Ahora, en el lado del cliente, puedes empujar y tirar imágenes de tu registry. Pero primero necesitamos iniciar sesión en el registry.

docker login registry.pliutau.com

# Usuario: busy
# Contraseña: bee
# Inicio de sesión exitoso

Listo para construir y empujar nuestra imagen a nuestro registry auto-gestionado:

docker build -t registry.pliutau.com/pliutau/hello-world:v0 .

docker push registry.pliutau.com/pliutau/hello-world:v0
# v0: digest: sha256:a56ea4... size: 738

En tu servidor puedes ver las imágenes subidas en la carpeta de datos:

ls -la ./registry/data/docker/registry/v2/repositories/

Otras opciones

Según el ejemplo anterior, también puedes ejecutar el registry en Kubernetes. O podrías usar un servicio de registry gestionado como Harbor, que es un registry de código abierto que ofrece funciones de seguridad avanzadas y es compatible con Docker y Kubernetes.

También, si desea tener una interfaz de usuario para su registro autohosteado, podría utilizar un proyecto como joxit/docker-registry-ui y ejecutarlo en un contenedor separado.

Conclusión

Los registros de contenedores autohosteados le permiten tener un control completo sobre su registro y la forma en que se despliega. Al mismo tiempo, esto implica el costo de mantener y proteger el registro.

Cualquiera sea su motivo para ejecutar un registro autohosteado, ahora sabe cómo se realiza. Desde aquí puede comparar las diferentes opciones y elegir la que mejor se ajuste a sus necesidades.

Puede encontrar el código fuente completo de esta demostración en GitHub. También, puede verlo como un vídeo en nuestro canal de YouTube.