Cómo configurar un registro Docker privado en Ubuntu 22.04
Si trabajas para una organización y quieres mantener tus imágenes Docker internamente para un despliegue rápido, entonces alojar un repositorio Docker privado es perfecto. Tener un registro Docker privado te permite ser dueño de tu canal de distribución de imágenes y tener un control más estricto sobre el almacenamiento y la distribución de imágenes. Puedes integrar tu registro con tu sistema CI/CD mejorando tu flujo de trabajo.
Este tutorial te enseñará a configurar y utilizar un registro Docker privado en un servidor Ubuntu 22.04 utilizando Amazon S3 como ubicación de almacenamiento.
Requisitos previos
- Dos servidores Linux con Ubuntu 22.04. Un servidor actuará como anfitrión del registro, mientras que el otro se utilizará como cliente para enviar solicitudes y recibir imágenes del anfitrión.
- Un nombre de dominio registrado que apunte al servidor anfitrión. Utilizaremos
registry.example.com
para nuestro tutorial. - Un usuario no root con privilegios sudo en ambas máquinas.
- Asegúrate de que todo está actualizado.
$ sudo apt update $ sudo apt upgrade
- Pocos paquetes que necesite tu sistema.
$ sudo apt install wget curl nano software-properties-common dirmngr apt-transport-https gnupg2 ca-certificates lsb-release ubuntu-keyring unzip -y
Puede que algunos de estos paquetes ya estén instalados en tu sistema.
Paso 1 – Configurar el Cortafuegos
El primer paso es configurar el cortafuegos. Ubuntu viene con ufw (Uncomplicated Firewall) por defecto.
Comprueba si el cortafuegos se está ejecutando.
$ sudo ufw status
Deberías obtener la siguiente salida.
Status: inactive
Permite el puerto SSH para que el cortafuegos no rompa la conexión actual al activarlo.
$ sudo ufw allow OpenSSH
Permite también los puertos HTTP y HTTPS.
$ sudo ufw allow http
$ sudo ufw allow https
Habilita el cortafuegos
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
Comprueba de nuevo el estado del cortafuegos.
$ sudo ufw status
Deberías ver un resultado similar.
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
80/tcp ALLOW Anywhere
443 ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
80/tcp (v6) ALLOW Anywhere (v6)
443 (v6) ALLOW Anywhere (v6)
Paso 2 – Instala Docker y Docker Compose
Este paso es necesario tanto en el servidor como en las máquinas cliente.
Ubuntu 22.04 incluye una versión antigua de Docker. Para instalar la última versión, importa primero la clave GPG de Docker.
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
Crea un archivo de repositorio Docker.
$ echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Actualiza la lista de repositorios del sistema.
$ sudo apt update
Instala la última versión de Docker.
$ sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
Comprueba que se está ejecutando.
$ sudo systemctl status docker
? docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2023-04-13 09:37:09 UTC; 3min 47s ago
TriggeredBy: ? docker.socket
Docs: https://docs.docker.com
Main PID: 2106 (dockerd)
Tasks: 7
Memory: 26.0M
CPU: 267ms
CGroup: /system.slice/docker.service
??2106 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Por defecto, Docker requiere privilegios de root. Si quieres evitar utilizar sudo
cada vez que ejecutes el comando docker
, añade tu nombre de usuario al grupo docker
.
$ sudo usermod -aG docker $(whoami)
Tendrás que salir del servidor y volver a entrar como el mismo usuario para activar este cambio o utilizar el siguiente comando.
$ su - ${USER}
Confirma que tu usuario se ha añadido al grupo Docker.
$ groups
navjot wheel docker
Paso 3 – Configurar el Registro Docker
Crear directorios de usuario
Crea un directorio para la configuración del registro.
$ mkdir ~/docker-registry
Cambia al directorio docker-registry
.
$ cd ~/docker-registry
Crea un directorio para almacenar la contraseña de autenticación HTTP, los archivos de configuración de Nginx y los certificados SSL.
$ mkdir auth
Crea otro directorio para almacenar los logs de Nginx.
$ mkdir logs
Crea un bucket de Amazon S3
Puedes almacenar los datos del registro y las imágenes en tu servidor o utilizar un servicio de alojamiento en la nube. Para nuestro tutorial, utilizaremos el servicio en la nube Amazon S3.
El siguiente paso es configurar el archivo de configuración con algunos ajustes importantes. Estos ajustes también se pueden definir en el archivo docker-compose.yml
, pero tener un archivo separado es mucho mejor.
Crea un bucket con los siguientes ajustes.
- ACL debe estar desactivado.
- El acceso público al cubo debe estar desactivado.
- El versionado del bucket debe estar desactivado.
- Activa el cifrado del bucket mediante claves gestionadas por Amazon S3. (SSE-S3)
- El bloqueo de objetos debe estar desactivado.
Crea un usuario IAM con la siguiente política.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:ListBucketMultipartUploads"
],
"Resource": "arn:aws:s3:::S3_BUCKET_NAME"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListMultipartUploadParts",
"s3:AbortMultipartUpload"
],
"Resource": "arn:aws:s3:::S3_BUCKET_NAME/*"
}
]
}
Sustituye S3_BUCKET_NAME
por el nombre de tu cubo de S3.
Anota la clave secreta, el valor secreto y la región de tu bucket para utilizarlos más adelante.
Crea el archivo Docker Compose
Crea el archivo docker-compose.yml
y ábrelo para editarlo.
$ nano docker-compose.yml
Pega en él el siguiente código.
services:
registry:
image: registry:2
restart: always
environment:
- REGISTRY_STORAGE=s3
- REGISTRY_STORAGE_S3_REGION=us-west-2
- REGISTRY_STORAGE_S3_BUCKET=hf-docker-registry
- REGISTRY_STORAGE_S3_ENCRYPT=true
- REGISTRY_STORAGE_S3_CHUNKSIZE=5242880
- REGISTRY_STORAGE_S3_SECURE=true
- REGISTRY_STORAGE_S3_ACCESSKEY=AKIA3FIG4NVFNXKQXMSJ
- REGISTRY_STORAGE_S3_SECRETKEY=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
- REGISTRY_STORAGE_S3_V4AUTH=true
- REGISTRY_STORAGE_S3_ROOTDIRECTORY=/image-registry
- REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR=inmemory
- REGISTRY_HEALTH_STORAGEDRIVER_ENABLED=false
nginx:
image: "nginx:alpine"
ports:
- 443:443
links:
- registry:registry
volumes:
- ./auth:/etc/nginx/conf.d
- ./auth/nginx.conf:/etc/nginx/nginx.conf:ro
- ./logs:/var/log/nginx
- /etc/letsencrypt:/etc/letsencrypt
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida.
Repasemos lo que hemos configurado en nuestro archivo de composición.
- El primer paso es coger la última imagen de la versión 2 del registro Docker del hub. No estamos utilizando la última etiqueta porque puede causar problemas en caso de una actualización importante de la versión. Establecerla en 2 te permite obtener todas las actualizaciones de la versión 2.x y evitar que se actualice automáticamente a la siguiente versión principal, lo que puede introducir cambios de última hora.
- El contenedor de registro está configurado para reiniciarse siempre en caso de fallo o apagado inesperado.
- Hemos establecido varias variables de entorno para el almacenamiento en Amazon S3. Repasémoslas rápidamente.
- REGISTRY_STORAGE establece el tipo de almacenamiento. Hemos seleccionado s3 ya que estamos utilizando Amazon S3.
- REGISTRY_STORAGE_S3_REGION establece la región de tu bucket S3.
- REGISTRY_STORAGE_S3_BUCKET establece el nombre de tu cubo S3.
- REGISTRY_STORAGE_S3_ENCRYPT – ponlo a true si has activado la encriptación del bucket.
- REGISTRY_STORAGE_S3_CHUNKSIZE establece el tamaño de los trozos de subida. Debe ser superior a 5MB (5 * 1024 * 1024).
- REGISTRY_STORAGE_S3_SECURE – ponlo a true si vas a utilizar HTTPS.
- REGISTRY_STORAGE_S3_ACCESSKEY y REGISTRY_STORAGE_S3_SECRETKEY – Credenciales de usuario que has obtenido tras crear tu usuario IAM.
- REGISTRY_STORAGE_S3_V4AUTH – ponlo a true si utilizas la v4 de autenticación de AWS. Si recibes errores relacionados con el inicio de sesión en S3, establécelo en false.
- REGISTRY_STORAGE_S3_ROOTDIRECTORY – establece el directorio raíz de tu bucket en el que se almacenarán tus datos de registro.
- REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR – establece la ubicación de la Caché. En nuestro caso, la almacenaremos en memoria. También puedes configurarlo para que utilice Redis.
- REGISTRY_HEALTH_STORAGEDRIVER_ENABLED – Ponlo a false para desactivar el servicio de comprobación de la salud del almacenamiento del Registro. Hay un error en el Registro que puede causar problemas si no lo pones a false.
- El Registro Docker se comunica a través del puerto 5000, que es el que hemos expuesto en nuestro servidor al docker.
./auth:/etc/nginx/conf.d
El mapeo garantiza que todos los ajustes de Nginx estén disponibles en el contenedor../auth/nginx.conf:/etc/nginx/nginx.conf:ro
mapea el archivo de configuración de Nginx del sistema a uno del contenedor en modo sólo lectura../logs:/var/log/nginx
permite el acceso a los registros de Nginx en el sistema mediante el mapeo al directorio de registros de Nginx en el contenedor.- La configuración del registro Docker se almacena en el archivo
/etc/docker/registry/config.yml
en el contenedor, y lo hemos mapeado al archivoconfig.yml
en el directorio actual, que crearemos en el siguiente paso.
Configurar la autenticación
Para configurar la autenticación HTTP, necesitas instalar el paquete httpd-tools
.
$ sudo apt install apache2-utils -y
Crea el archivo de contraseña en el directorio ~/docker-registry/auth
.
$ htpasswd -Bc ~/docker-registry/auth/nginx.htpasswd user1
New password:
Re-type new password:
Adding password for user user1
La bandera -c
indica al comando que cree un nuevo archivo, y la bandera -B
que utilice el algoritmo bcrypt soportado por Docker. Sustituye user1
por un nombre de usuario de tu elección.
Si quieres añadir más usuarios, ejecuta de nuevo el comando, pero sin la bandera -c
.
$ htpasswd -B ~/docker-registry/auth/registry.password user2
Ahora, el archivo se asignará al contenedor de registro para la autenticación.
Paso 4 – Instalar SSL
Necesitamos instalar Certbot para generar el certificado SSL. Puedes instalar Certbot utilizando el repositorio de Ubuntu o conseguir la última versión utilizando la herramienta Snapd. Nosotros utilizaremos la versión Snapd.
Ubuntu 22.04 viene con Snapd instalado por defecto. Ejecuta los siguientes comandos para asegurarte de que tu versión de Snapd está actualizada.
$ sudo snap install core && sudo snap refresh core
Instala Certbot.
$ sudo snap install --classic certbot
Utiliza el siguiente comando para asegurarte de que se puede ejecutar el comando Certbot creando un enlace simbólico al directorio /usr/bin
.
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Ejecuta el siguiente comando para generar un certificado SSL.
$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d registry.example.com
El comando anterior descargará un certificado en el directorio /etc/letsencrypt/live/registry.example.com
de tu servidor.
Genera un certificado de grupo Diffie-Hellman.
$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096
Comprueba el servicio programador de renovaciones de Certbot.
$ sudo systemctl list-timers
Encontrarás snap.certbot.renew.service
como uno de los servicios programados para ejecutarse.
NEXT LEFT LAST PASSED UNIT ACTIVATES
.....
Sun 2023-04-14 00:00:00 UTC 19min left Sat 2023-02-25 18:04:05 UTC n/a snap.certbot.renew.timer snap.certbot.renew.service
Sun 2023-04-14 00:00:20 UTC 19min left Sat 2023-02-25 10:49:23 UTC 14h ago apt-daily-upgrade.timer apt-daily-upgrade.service
Sun 2023-04-14 00:44:06 UTC 3h 22min left Sat 2023-02-25 20:58:06 UTC 7h ago apt-daily.timer apt-daily.service
Realiza una ejecución en seco del proceso para comprobar si la renovación SSL funciona correctamente.
$ sudo certbot renew --dry-run
Si no ves ningún error, ya está todo listo. Tu certificado se renovará automáticamente.
Copia el archivo Dhparam en el contenedor
Copia el certificado del grupo Diffie-Hellman en el directorio ~/docker-registry/auth
, que se asignará al contenedor.
$ sudo cp /etc/ssl/certs/dhparam.pem ~/docker-registry/auth
Paso 5 – Configurar Nginx
El siguiente paso consiste en configurar el servidor Nginx como proxy front-end para el servidor del registro Docker. El registro Docker viene con un servidor incorporado que opera en el puerto 5000. Lo pondremos detrás de Nginx.
Crea y abre el archivo ~/docker-registry/auth/nginx.conf
para editarlo.
$ sudo nano ~/docker-registry/auth/nginx.conf
Pega en él el siguiente código.
events {
worker_connections 1024;
}
http {
upstream docker-registry {
server registry:5000;
}
## Set a variable to help us decide if we need to add the
## 'Docker-Distribution-Api-Version' header.
## The registry always sets this header.
## In the case of nginx performing auth, the header is unset
## since nginx is auth-ing before proxying.
map $upstream_http_docker_distribution_api_version $docker_distribution_api_version {
'' 'registry/2.0';
}
server {
listen 443 ssl http2;
server_name registry.example.com;
# SSL
ssl_certificate /etc/letsencrypt/live/registry.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/registry.example.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/registry.example.com/chain.pem;
access_log /var/log/nginx/registry.access.log;
error_log /var/log/nginx/registry.error.log;
# Recommendations from https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1;
ssl_session_cache shared:SSL:10m;
ssl_dhparam /etc/nginx/conf.d/dhparam.pem;
resolver 8.8.8.8;
# disable any limits to avoid HTTP 413 for large image uploads
client_max_body_size 0;
# required to avoid HTTP 411: see Issue #1486 (https://github.com/moby/moby/issues/1486)
chunked_transfer_encoding on;
location /v2/ {
# Do not allow connections from docker 1.5 and earlier
# docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
return 404;
}
# To add basic authentication to v2 use auth_basic setting.
auth_basic "Registry realm";
auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
## If $docker_distribution_api_version is empty, the header is not added.
## See the map directive above where this variable is defined.
add_header 'Docker-Distribution-Api-Version' $docker_distribution_api_version always;
proxy_pass http://docker-registry;
proxy_set_header Host $http_host; # required for docker client's sake
proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 900;
}
}
}
Guarda el archivo pulsando Ctrl + X e introduciendo Y cuando se te pida una vez hayas terminado.
Paso 6 – Inicia el Registro Docker
Cambia al directorio del Registro Docker.
$ cd ~/docker-registry
Inicia el contenedor Docker.
$ docker compose up -d
Comprueba el estado de los contenedores.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3328b7e36bb2 nginx:alpine "/docker-entrypoint.…" About a minute ago Up 3 seconds 80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp docker-registry-nginx-1
bf7cdfc0e013 registry:2 "/entrypoint.sh /etc…" About a minute ago Up About a minute 5000/tcp docker-registry-registry-1
Accede al Registro Docker.
$ docker login -u=user1 -p=password https://registry.example.com
Obtendrás el siguiente resultado.
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/username/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
También puedes abrir la URL https://registry.example.com/v2/
en tu navegador, y te pedirá un nombre de usuario y una contraseña. Deberías ver una página vacía con {}.
Puedes comprobar la URL en el terminal utilizando curl
.
$ curl -u user1 -X GET https://registry.example.com/v2/
Enter host password for user 'user1':
{}
Descarga la última imagen docker de Ubuntu.
$ docker pull ubuntu:latest
Etiqueta esta imagen para el registro privado.
$ docker tag ubuntu:latest registry.example.com/ubuntu2204
Empuja la imagen al registro.
$ docker push registry.example.com/ubuntu2204
Comprueba si el push se ha realizado correctamente.
$ curl -u user1 -X GET https://registry.example.com/v2/_catalog
Enter host password for user 'user1':
{"repositories":["ubuntu2204"]}
Introduce tu contraseña de autenticación Nginx cuando se te solicite, y verás la lista de repositorios disponibles a través del registro.
Cierra la sesión utilizando el terminal para borrar las credenciales.
$ docker logout https://registry.example.com
Removing login credentials for registry.example.com
Comprueba la lista de imágenes Docker disponibles actualmente para su uso.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry 2 8db46f9d7550 2 weeks ago 24.2MB
nginx alpine 8e75cbc5b25c 2 weeks ago 41MB
ubuntu latest 08d22c0ceb15 5 weeks ago 77.8MB
registry.example.com/ubuntu2204 latest 08d22c0ceb15 5 weeks ago 77.8MB
Paso 7 – Acceder y utilizar el registro Docker desde la máquina cliente
Accede a tu servidor-cliente. En el paso 1, instalamos Docker en la máquina cliente.
Accede al registro privado de Docker desde la máquina cliente.
$ docker login -u=user1 -p=password https://registry.example.com
Extrae la imagen de Ubuntu del registro.
$ docker pull registry.example.com/ubuntu2204
Lista todas las imágenes en tu máquina cliente.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.example.com/ubuntu2204 latest 08d22c0ceb15 5 weeks ago 77.8MB
Crea y lanza un contenedor utilizando la imagen descargada.
$ docker run -it registry.example.com/ubuntu2204 /bin/bash
Accederás al Shell dentro del contenedor Ubuntu.
root@647899f255db:
Ejecuta el siguiente comando para comprobar la versión de Linux.
root@a2da49fdbea9$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.2 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
Ahora, puedes empezar a utilizar tu registro Docker desde tus máquinas cliente.
Conclusión
Con esto concluye nuestro tutorial sobre la configuración de un registro Docker privado en un servidor Ubuntu 22.04 que utiliza Amazon S3 como almacenamiento. Si tienes alguna pregunta, publícala en los comentarios a continuación.