
En este artículo les voy a explicar como armar su propio Container Registry para alojar imágenes de Docker y no depender de servicios como DockerHub.
La necesidad de tener nuestro propio Container Registry nació porque empezamos a usar Kamal (la herramienta que desarrolló 37signals para hacer deployments usando Docker) y entre los requerimientos de la herramienta está el tener que usar un Container Registry para subir las imágenes de Docker de nuestras apps.
Al principio empezamos a usar DockerHub pero, dada la limitación del plan gratuito de tener un solo un repo privado por cuenta y con la idea de no depender de terceros, decidimos buscar alternativas.
Allí fue que nos cruzamos con CNCF Distribution, un Registry Open Source bajo la licencia Apache. Una de las grandes ventajas de este Registry, además de ser gratis y Open Source, es que implementa OCI Distribution Spec que define un protocolo de API para facilitar y estandarizar la distribución de contenido. Este protocolo va de la mano con OCI Image Format Specification, que permite que sea totalmente compatible con servicios como:
- Docker Hub
- Quay.io
- GitHub Packages
A continuación, les voy a contar los pasos que deberían realizar para tener un Container Registry corriendo en un servidor con un dominio definido, como por ejemplo registry.acme.com.
Los pasos serían:
- Obtener un dominio
- Crear un servidor
- Instalar las dependencias
- Armar un certificado con Let’s Encrypt
- Agregar seguridad
- Configurar un servicio con el registry
1. Obtener un dominio
El servidor podría ser accedido a través de la IP, pero es recomendable usarlo con un dominio para poder configurar un certificado y en el caso que cambie la IP de nuestro servidor no tengas que modificar todas las referencias. Hay distintas alternativas para obtener un dominio, les dejo algunos sitios donde pueden registrar dominios:
- GoDaddy
- Hostinger
- A2Hosting
- InmotionHosting
- nic.ar (Argentina)
2. Crear un servidor
A modo de ejemplo vamos a armar un droplet de DigitalOcean, pero se podría usar cualquier proveedor. No es objetivo de este artículo explicar cómo armar un servidor. Si tienen curiosidad, les dejo un link que explica como hacerlo.
Una vez completado el tutorial es necesario conectarse por ssh al servidor que hayamos creado.
3. Instalar las dependencias
Debemos instalar las siguientes dependencias/paquetes:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- lsb-release
- unattended-upgrades
- certbot
Para hacerlo debemos correr el siguiente comando:
apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release unattended-upgrades certbot
4. Armar un certificado con Let’s Encrypt
Basándonos en este tutorial tenemos que correr una serie de comandos
En primer lugar debemos agregar el repositorio para el paquete certbot (en ciertas versiones de Linux no es necesario)
add-apt-repository ppa:certbot/certbot
Luego, actualizar los repositorios
apt-get update -y
Instalar Certbot (Se puede omitir ya que se instaló en las dependencias)
apt-get install certbot -y
Abrir puerto 80 para que Let’s Encrypt se pueda comunicar con nuestro servidor
ufw allow 80
Crear certificado con certbot (reemplazar MI_DOMINIO con el que vamos a usar. EJ registry.acme.com.ar)
certbot certonly — standalone — preferred-challenges http -d [MI_DOMINIO]
Como resultado deberíamos tener un directorio con el mismo nombre de dominio en /etc/letsencrypt/live/ con los archivos:
README cert.pem chain.pem fullchain.pem privkey.pem
5. Agregar seguridad
Para que nuestro registry no quede expuesto es recomendable agregar algún mecanismo de autenticación. Hay varios, pero el más simple y que además te permite autenticarte con el comando “docker login”, es el Native basic auth.
Este mecanismo usa un Apache htpasswd file para definir un usuario y contraseña. Es necesario tener en cuenta que soporta solo un formato de contraseña: bcypt.
Para crear este archivo tenemos 2 formas: usar un contenedor de docker o un comando:
Contenedor de docker
docker run — entrypoint htpasswd httpd:2 -Bbn [USUARIO] [CONTRASEÑA] > auth/htpasswd
Comando
htpasswd -c -B -b auth/htpasswd [USUARIO] [CONTRASEÑA]
Ambos crean el archivo auth/htpasswd en el directorio donde corramos cualquier de los 2 métodos. Tanto el directorio como el nombre del archivo se pueden cambiar. Lo importante es pasar el path correcto a nuestro servicio.
6. Configurar un servicio con el registry
Crear el archivo registry.service en el directorio /etc/systemd/system/ con el siguiente contenido. Es necesario cambiar [MI_DOMINIO] por el que estés usando.
En el ejemplo estamos usando el directorio auth y el archivo htpasswd. En la primera línea -v /auth:/auth estamos agregando el directorio auth del servidor al contenedor y en la otra línea -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd estamos indicando donde está el archivo dentro del contenedor. Es decir, lo que definimos después de los : en la primera línea. En caso de modificar el directorio o el nombre del archivo en el paso anterior hay que modificar estas 3 líneas.
[Unit]
Description=Distribution registry
After=docker.service
Requires=docker.service
[Service]
#TimeoutStartSec=0
Restart=always
ExecStartPre=-/usr/bin/docker stop %N
ExecStartPre=-/usr/bin/docker rm %N
ExecStart=/usr/bin/docker run — name %N \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /auth:/auth \
-p 443:443 \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/etc/letsencrypt/live/${domain}/fullchain.pem \
-e REGISTRY_HTTP_TLS_KEY=/etc/letsencrypt/live/${domain}/privkey.pem \
-e REGISTRY_HTTP_SECRET=${http_secret} \
registry:3.0.0-alpha.1
[Install]
WantedBy=multi-user.target
Hacer un reload para que systemd lea el nuevo archivo
systemctl daemon-reload
Habilitar el nuevo servicio
systemctl enable registry.service
Iniciar el nuevo servicio systemctl start registry.service
Revisar que el servicio este corriendo correctamente
> systemctl status registry.service
En próximos artículos les voy a contar cómo instalar y configurar el mismo Container Registry con la herramienta Terraform.
Conclusión
En este artículo, hemos cubierto el proceso detallado para crear y configurar un Container Registry propio, utilizando un proyecto Open Source basado en la especificación OCI Distribution. Esta solución nos permite gestionar de manera eficiente nuestras imágenes de Docker sin depender de servicios comerciales como DockerHub, lo cual resulta especialmente útil cuando trabajamos con múltiples aplicaciones y necesitamos controlar el acceso y los costos asociados.
Realizar este tipo de tareas manualmente no solo mejora nuestra comprensión técnica sobre el funcionamiento interno de herramientas como Docker y los registros de contenedores, sino que también nos brinda una perspectiva más profunda sobre la importancia de la seguridad y la configuración eficiente en entornos de producción. También adquirimos experiencia valiosa en la solución de problemas reales y en la personalización de herramientas según nuestras necesidades, lo que no solo enriquece nuestro conocimiento técnico, sino que también nos prepara para enfrentar desafíos más complejos en el futuro.