Cómo configurar un registro Docker privado en Ubuntu 20.04
El autor seleccionó el Fondo de Código Libre y Abierto para recibir una donación como parte del programa Write for DOnations .
Introducción
Docker Registry es una aplicación que administra el almacenamiento y la entrega de imágenes de contenedores Docker. Los registros centralizan las imágenes de contenedores y reducen los tiempos de compilación para los desarrolladores. Las imágenes de Docker garantizan el mismo entorno de ejecución a través de la virtualización, pero la compilación de una imagen puede implicar una inversión de tiempo significativa. Por ejemplo, en lugar de instalar dependencias y paquetes por separado para usar Docker, los desarrolladores pueden descargar una imagen comprimida de un registro que contiene todos los componentes necesarios. Además, los desarrolladores pueden automatizar el envío de imágenes a un registro mediante herramientas de integración continua, como TravisCI , para actualizar las imágenes sin problemas durante la producción y el desarrollo.
Docker también cuenta con un registro público gratuito, Docker Hub , que puede alojar sus imágenes de Docker personalizadas, pero existen situaciones en las que no querrá que su imagen esté disponible públicamente. Las imágenes suelen contener todo el código necesario para ejecutar una aplicación, por lo que es preferible utilizar un registro privado cuando se utiliza software propietario.
En este tutorial, configurará y protegerá su propio registro privado de Docker. Utilizará Docker Compose para definir configuraciones para ejecutar sus contenedores de Docker y Nginx para reenviar el tráfico del servidor desde Internet al contenedor de Docker en ejecución. Una vez que haya completado este tutorial, podrá enviar una imagen de Docker personalizada a su registro privado y extraer la imagen de forma segura desde un servidor remoto.
Prerrequisitos
- Dos servidores Ubuntu 20.04 configurados siguiendo la Guía de configuración inicial del servidor Ubuntu 20.04 , incluido un
sudo
usuario no root y un firewall. Un servidor alojará su registro Docker privado y el otro será su servidor cliente . - Docker se instaló en ambos servidores siguiendo los pasos 1 y 2 de Cómo instalar y usar Docker en Ubuntu 20.04 .
- Docker Compose instalado en el servidor host siguiendo el Paso 1 de Cómo instalar y usar Docker Compose en Ubuntu 20.04 .
- Nginx instalado en su servidor host siguiendo los pasos en Cómo instalar Nginx en Ubuntu 20.04 .
- Nginx protegido con Let’s Encrypt en su servidor para el registro privado de Docker, siguiendo el tutorial Cómo proteger Nginx con Let’s Encrypt en Ubuntu 20.04 . Asegúrese de redirigir todo el tráfico de HTTP a HTTPS en el paso 4 .
- Un nombre de dominio que se resuelve en el servidor que estás usando para el registro privado de Docker. Lo configurarás como parte del requisito previo de Let’s Encrypt. En este tutorial, lo llamaremos
your_domain
.
Paso 1: Instalación y configuración del registro de Docker
Docker en la línea de comandos es útil al comenzar y probar contenedores, pero resulta difícil de manejar para implementaciones más grandes que involucran múltiples contenedores ejecutándose en paralelo.
Con Docker Compose, puedes escribir un .yml
archivo para configurar cada contenedor y la información que estos necesitan para comunicarse entre sí. Puedes usar la docker-compose
herramienta de línea de comandos para enviar comandos a todos los componentes que conforman tu aplicación y controlarlos como un grupo.
Docker Registry es en sí mismo una aplicación con varios componentes, por lo que utilizará Docker Compose para administrarlo. Para iniciar una instancia del registro, configurará un docker-compose.yml
archivo para definirlo y la ubicación en el disco donde el registro almacenará sus datos.
Almacenarás la configuración en un directorio llamado docker-registry
en el servidor principal. Créalo ejecutando:
- mkdir ~/docker-registry
Navega hasta él:
- cd ~/docker-registry
Luego, crea un subdirectorio llamado data
, donde tu registro almacenará sus imágenes:
- mkdir data
Cree y abra un archivo llamado docker-compose.yml
ejecutando:
- nano docker-compose.yml
Agregue las siguientes líneas, que definen una instancia básica de un Registro Docker:
~/docker-registry/docker-compose.yml
version: '3'services: registry: image: registry:2 ports: - "5000:5000" environment: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data volumes: - ./data:/data
Primero, se le asigna un nombre al primer servicio registry
y se establece su imagen en registry
, version 2
. Luego, en ports
, se asigna el puerto 5000
en el host al puerto 5000
del contenedor. Esto le permite enviar una solicitud al puerto 5000
en el servidor y hacer que la solicitud se reenvíe al registro.
En la environment
sección, se establece la REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
variable en /data
, especificando en qué volumen debe almacenar sus datos. Luego, en la volumes
sección, se asigna el /data
directorio en el sistema de archivos del host a /data
en el contenedor, que actúa como un paso a través. Los datos se almacenarán en realidad en el sistema de archivos del host.
Guarde y cierre el archivo.
Ahora puede iniciar la configuración ejecutando:
- docker-compose up
Se descargarán e iniciarán el contenedor de registro y sus dependencias.
OutputCreating network "docker-registry_default" with the default driverPulling registry (registry:2)...2: Pulling from library/registrye95f33c60a64: Pull complete4d7f2300f040: Pull complete35a7b7da3905: Pull completed656466e1fe8: Pull completeb6cb731e4f93: Pull completeDigest: sha256:da946ca03fca0aade04a73aa94b54ff0dc614216bdd1d47585f97b4c1bdaa0e2Status: Downloaded newer image for registry:2Creating docker-registry_registry_1 ... doneAttaching to docker-registry_registry_1registry_1 | time="2021-03-18T12:32:59.587157744Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." go.version=go1.11.2 instance.id=119fe50b-2bb6-4a8d-902d-dfa2db63fc2f service=registry version=v2.7.1registry_1 | time="2021-03-18T12:32:59.587912733Z" level=info msg="redis not configured" go.version=go1.11.2 instance.id=119fe50b-2bb6-4a8d-902d-dfa2db63fc2f service=registry version=v2.7.1registry_1 | time="2021-03-18T12:32:59.598496488Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.11.2 instance.id=119fe50b-2bb6-4a8d-902d-dfa2db63fc2f service=registry version=v2.7.1registry_1 | time="2021-03-18T12:32:59.601503005Z" level=info msg="listening on [::]:5000" go.version=go1.11.2 instance.id=119fe50b-2bb6-4a8d-902d-dfa2db63fc2f service=registry version=v2.7.1...
No HTTP secret provided
Más adelante en este tutorial abordarás el mensaje de advertencia. Observa que la última línea de la salida muestra que ha comenzado a escuchar correctamente en el puerto 5000
.
Puedes presionar CTRL+C
para detener su ejecución.
En este paso, ha creado una configuración de Docker Compose que inicia un Docker Registry que escucha en el puerto 5000
. En los siguientes pasos, lo expondrá en su dominio y configurará la autenticación.
Paso 2: Configuración del reenvío de puertos de Nginx
Como parte de los requisitos previos, habilitó HTTPS en su dominio. Para exponer su registro de Docker seguro allí, solo necesitará configurar Nginx para reenviar el tráfico desde su dominio al contenedor de registro.
Ya ha configurado el archivo que contiene la configuración de su servidor. Ábralo para editarlo ejecutando:/etc/nginx/sites-available/your_domain
- sudo nano /etc/nginx/sites-available/your_domain
Encuentra el location
bloque existente:
/etc/nginx/sites-available/su_dominio
...location / { ...}...
Debe reenviar el tráfico al puerto 5000
, donde su registro escuchará el tráfico. También desea agregar encabezados a la solicitud reenviada al registro, lo que proporciona información adicional del servidor sobre la solicitud en sí. Reemplace el contenido existente del location
bloque con las siguientes líneas:
/etc/nginx/sites-available/su_dominio
...location / { # 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; } proxy_pass http://localhost:5000; 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;}...
El if
bloque comprueba el agente de usuario de la solicitud y verifica que la versión del cliente Docker sea superior a 1.5, así como que no se trate de una Go
aplicación que esté intentando acceder. Para obtener más información sobre esto, puede encontrar la nginx
configuración del encabezado en la guía de Nginx del registro de Docker .
Guarde y cierre el archivo cuando haya terminado. Aplique los cambios reiniciando Nginx:
- sudo systemctl restart nginx
Si recibe un error, vuelva a verificar la configuración que ha agregado.
Para confirmar que Nginx está reenviando correctamente el tráfico a su contenedor de registro en el puerto 5000
, ejecútelo:
- docker-compose up
Luego, en una ventana del navegador, navegue hasta su dominio y acceda al v2
punto final, de la siguiente manera:
https://your_domain/v2
Verás un objeto JSON vacío:
{}
En tu terminal recibirás un resultado similar al siguiente:
Outputregistry_1 | time="2018-11-07T17:57:42Z" level=info msg="response completed" go.version=go1.7.6 http.request.host=cornellappdev.com http.request.id=a8f5984e-15e3-4946-9c40-d71f8557652f http.request.method=GET http.request.remoteaddr=128.84.125.58 http.request.uri="/v2/" http.request.useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7" http.response.contenttype="application/json; charset=utf-8" http.response.duration=2.125995ms http.response.status=200 http.response.written=2 instance.id=3093e5ab-5715-42bc-808e-73f310848860 version=v2.6.2registry_1 | 172.18.0.1 - - [07/Nov/2018:17:57:42 +0000] "GET /v2/ HTTP/1.0" 200 2 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7"
En la última línea, puede ver que GET
se realizó una solicitud a /v2/
, que es el punto final al que envió una solicitud, desde su navegador. El contenedor recibió la solicitud que realizó, desde el reenvío de puertos, y devolvió una respuesta de {}
. El código 200
en la última línea de la salida significa que el contenedor gestionó la solicitud correctamente.
Presione CTRL+C
para detener su ejecución.
Ahora que ha configurado el reenvío de puertos, pasará a mejorar la seguridad de su registro.
Paso 3: Configuración de la autenticación
Nginx te permite configurar la autenticación HTTP para los sitios que administra, lo que puedes usar para limitar el acceso a tu Registro Docker. Para lograrlo, crearás un archivo de autenticación htpasswd
y le agregarás combinaciones de nombre de usuario y contraseña que serán aceptadas.
Puede obtener la htpasswd
utilidad instalando el apache2-utils
paquete. Para ello, ejecute:
- sudo apt install apache2-utils -y
Almacenarás el archivo de autenticación con las credenciales en ~/docker-registry/auth
. Créalo ejecutando:
- mkdir ~/docker-registry/auth
Navega hasta él:
- cd ~/docker-registry/auth
Crea el primer usuario, reemplázalo username
con el nombre de usuario que quieras utilizar. La -B
bandera ordena el uso del bcrypt
algoritmo que Docker requiere:
- htpasswd -Bc registry.password username
Ingrese la contraseña cuando se le solicite y la combinación de credenciales se agregará a registry.password
.
Nota: Para agregar más usuarios, vuelva a ejecutar el comando anterior sin -c
, lo que crea un nuevo archivo:
- htpasswd -B registry.password username
Ahora que la lista de credenciales está lista, deberá editarla docker-compose.yml
para ordenar a Docker que use el archivo que creó para autenticar a los usuarios. Ábralo para editarlo ejecutando lo siguiente:
- nano ~/docker-registry/docker-compose.yml
Añade las líneas resaltadas:
~/docker-registry/docker-compose.yml
version: '3'services: registry: image: registry:2 ports: - "5000:5000" environment: REGISTRY_AUTH: htpasswd REGISTRY_AUTH_HTPASSWD_REALM: Registry REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data volumes: - ./auth:/auth - ./data:/data
Ha añadido variables de entorno que especifican el uso de la autenticación HTTP y ha proporcionado la ruta al archivo htpasswd
creado. Para REGISTRY_AUTH
, ha especificado htpasswd
como valor, que es el esquema de autenticación que está utilizando y ha establecido REGISTRY_AUTH_HTPASSWD_PATH
la ruta del archivo de autenticación. REGISTRY_AUTH_HTPASSWD_REALM
significa el nombre del htpasswd
dominio.
También has montado el ./auth
directorio para que el archivo esté disponible dentro del contenedor de registro. Guarda y cierra el archivo.
Ahora puedes comprobar que tu autenticación funciona correctamente. Primero, dirígete al directorio principal:
- cd ~/docker-registry
Luego, ejecute el registro ejecutando:
- docker-compose up
En tu navegador, actualiza la página de tu dominio. Se te solicitará un nombre de usuario y una contraseña.
Después de proporcionar una combinación válida de credenciales, verá un objeto JSON vacío:
{}
Esto significa que se ha autenticado correctamente y ha obtenido acceso al registro. Salga presionando CTRL+C
.
Ahora su registro está protegido y solo se puede acceder a él después de la autenticación. Ahora lo configurará para que se ejecute como un proceso en segundo plano y sea resistente a los reinicios al iniciarse automáticamente.
Paso 4: iniciar Docker Registry como servicio
Puede asegurarse de que el contenedor de registro se inicie cada vez que se inicia el sistema o después de que se bloquea, instruyendo a Docker Compose para que lo mantenga siempre en ejecución. Abrir docker-compose.yml
para editar:
- nano docker-compose.yml
Añade la siguiente línea debajo del registry
bloque:
docker-compose.yml
... registry: restart: always...
La configuración restart
siempre garantiza que el contenedor sobrevivirá a los reinicios. Cuando haya terminado, guarde y cierre el archivo.
Ahora puede iniciar su registro como un proceso en segundo plano pasando -d
:
- docker-compose up -d
Con el registro ejecutándose en segundo plano, puedes cerrar libremente la sesión SSH y el registro no se verá afectado.
Debido a que las imágenes de Docker pueden ser muy grandes, ahora aumentará el tamaño máximo de archivo que Nginx aceptará para las cargas.
Paso 5: Aumentar el tamaño de carga de archivos para Nginx
Antes de poder enviar una imagen al registro, debe asegurarse de que su registro pueda manejar cargas de archivos grandes.
El límite de tamaño predeterminado para las cargas de archivos en Nginx es 1m
, lo que no es suficiente para las imágenes de Docker. Para aumentarlo, deberá modificar el archivo de configuración principal de Nginx, ubicado en /etc/nginx/nginx.conf
. Ábralo para editarlo ejecutando:
- sudo nano /etc/nginx/nginx.conf
Busque la http
sección y agregue la siguiente línea:
/etc/nginx/nginx.conf
...http { client_max_body_size 16384m; ...}...
El client_max_body_size
parámetro ahora está establecido en 16384m
, lo que hace que el tamaño máximo de carga sea igual a 16 GB.
Guarde y cierre el archivo cuando haya terminado.
Reinicie Nginx para aplicar los cambios de configuración:
- sudo systemctl restart nginx
Ahora puedes cargar imágenes grandes a tu Registro Docker sin que Nginx bloquee la transferencia o genere errores.
Paso 6: Publicación en su registro privado de Docker
Ahora que el servidor Docker Registry está en funcionamiento y acepta archivos de gran tamaño, puedes intentar enviarle una imagen. Como no tienes ninguna imagen disponible, usarás la ubuntu
imagen de Docker Hub, un Docker Registry público, para realizar la prueba.
Desde su segundo servidor cliente, ejecute el siguiente comando para descargar la ubuntu
imagen, ejecutarla y obtener acceso a su shell:
- docker run -t -i ubuntu /bin/bash
Los indicadores -i
y -t
le brindan acceso interactivo al shell del contenedor.
Una vez que estés dentro, crea un archivo llamado SUCCESS
ejecutando:
- touch /SUCCESS
Al crear este archivo, personalizaste tu contenedor. Más adelante lo usarás para comprobar que estás usando exactamente el mismo contenedor.
Salga del shell del contenedor ejecutando:
- exit
Ahora, crea una nueva imagen a partir del contenedor que acabas de personalizar:
- docker commit $(docker ps -lq) test-image
La nueva imagen ya está disponible localmente y la enviarás a tu nuevo registro de contenedor. Primero, debes iniciar sesión:
- docker login https://your_domain
Cuando se le solicite, ingrese la combinación de nombre de usuario y contraseña que haya definido en el paso 3 de este tutorial.
La salida será:
Output...Login Succeeded
Una vez que haya iniciado sesión, cambie el nombre de la imagen creada:
- docker tag test-image your_domain/test-image
Por último, envíe la imagen recién etiquetada a su registro:
- docker push your_domain/test-image
Recibirá un resultado similar al siguiente:
OutputThe push refers to a repository [your_domain/test-image]420fa2a9b12e: Pushedc20d459170d8: Pusheddb978cae6a05: Pushedaeb3f02e9374: Pushedlatest: digest: sha256:88e782b3a2844a8d9f0819dc33f825dde45846b1c5f9eb4870016f2944fe6717 size: 1150
Verificó que su registro maneja la autenticación de usuarios mediante el inicio de sesión y permite que los usuarios autenticados envíen imágenes al registro. Ahora intentará extraer la imagen de su registro.
Paso 7: extracción desde su registro privado de Docker
Ahora que has subido una imagen a tu registro privado, intentarás extraerla de él.
En el servidor principal, inicia sesión con el nombre de usuario y la contraseña que configuraste anteriormente:
- docker login https://your_domain
Intente tirar del mismo test-image
ejecutando:
- docker pull your_domain/test-image
Docker debería descargar la imagen. Ejecute el contenedor con el siguiente comando:
- docker run -it your_domain/test-image /bin/bash
Enumere los archivos presentes ejecutando:
- ls
Verás el SUCCESS
archivo que has creado anteriormente, lo que confirma que es la misma imagen que has creado:
SUCCESS bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
Salga del shell del contenedor ejecutando:
- exit
Ahora que ha probado a enviar y recibir imágenes, ha terminado de configurar un registro seguro que puede usar para almacenar imágenes personalizadas.
Conclusión
En este tutorial, configurará su propio registro Docker privado y publicará una imagen de Docker en él. Como se mencionó en la introducción, también puede usar TravisCI o una herramienta de integración continua similar para automatizar el envío a un registro privado directamente. Al aprovechar los contenedores Docker en su flujo de trabajo, puede asegurarse de que la imagen que contiene el código tenga el mismo comportamiento en cualquier máquina, ya sea en producción o en desarrollo. Para obtener más información sobre cómo escribir archivos Docker, puede visitar la documentación oficial sobre las mejores prácticas.
Deja una respuesta