El autor seleccionó la Apache Software Foundation para recibir una donación como parte del programa Write for DOnations.

Introducción

Docker Registry es una aplicación que gestiona el almacenamiento y el envío de imágenes de contenedores de Docker. Los registros centralizan las imágenes de contenedores y reducen el tiempo 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 crear una imagen puede suponer una inversión significativa en términos de tiempo. Por ejemplo, en vez de instalar dependencias y paquetes por separado para usar Docker, los desarrolladores pueden descargar una imagen comprimida de un registro que contenga todos los componentes necesarios. Además, los desarrolladores pueden automatizar la introducción de imágenes en un registro usando herramientas de integración continua, como TravisCI, para actualizar imágenes sin problemas durante la producción y el desarrollo.

Docker también tiene un registro público gratuito, Docker Hub, que puede alojar sus imágenes de Docker personalizadas, pero existen situaciones en las que no le convendrá que su imagen esté disponible públicamente. Las imágenes normalmente contienen todo el código necesario para ejecutar una aplicación. Por lo tanto, usar un registro privado es preferible cuando se utiliza software propio.

A través de este tutorial, configurará y protegerá su propio Docker Registry privado. Usará Docker Compose para definir las configuraciones a fin de ejecutar Nginx y sus aplicaciones de Docker para reenviar el tráfico del servidor de HTTPS al contenedor de Docker en ejecución. Una vez que complete este tutorial, podrá introducir una imagen de Docker personalizada en su registro privado y extraer la imagen de forma segura desde un servidor remoto.

Requisitos previos

Antes de iniciar esta guía, necesitará lo siguiente:

  • Dos servidores de Ubuntu 18.04 configurados conforme a la guía de configuración inicial para servidores de Ubuntu 18.04, incluidos un usuario sudo no root y un firewall. Un servidor alojará su Docker Registry privado y el otro será su servidor cliente.
  • Docker y Docker Compose instalados en ambos servidores siguiendo el tutorial Cómo instalar Docker Compose en Ubuntu 18.04. Solo necesitará completar el primer paso de este tutorial para instalar Docker Compose. En este tutorial se explica la forma de instalar Docker como parte de sus requisitos previos.
  • Nginx instalado en su servidor de Docker Registry privado, conforme al tutorial Cómo instalar Nginx en Ubuntu 18.04.
  • Nginx protegido con Let´s Encrypt en su servidor para el Docker Registry privado, conforme a Cómo proteger Nginx con Let´s Encrypt. Asegúrese de redireccionar todo el tráfico de HTTP a HTTPS en el paso 4.
  • Un nombre de dominio que resuelve en el servidor que está usando para el Docker Registry privado. Configurará esto como parte del requisito previo de Let´s Encrypt.

Paso 1: Instalar y configurar el Docker Registry

La herramienta de línea de comandos de Docker es útil para iniciar y administrar uno o dos contenedores de Docker. Sin embargo, para una implementación completa la mayoría de las aplicaciones que se ejecutan dentro de contenedores de Docker requieren que otros componentes se ejecuten en paralelo. Por ejemplo, muchas aplicaciones web constan de un servidor web, como Nginx, que presente el código de la aplicación, un lenguaje de creación de secuencia de comandos interpretado como PHP, y un servidor de base de datos como MySQL.

Con Docker Compose, puede escribir un archivo .yml para configurar los ajustes de cada uno de los contenedores y la información que estos deben transmitirse entre sí. Puede usar la herramienta de línea de comandos docker-componse para emitir comandos a todos los componentes que forman su aplicación.

Docker Registry es en sí misma una aplicación con varios componentes, por lo que utilizará Docker Compose para administrar su configuración. Para iniciar una instancia del registro, configurará un archivo docker-compose.yml para definir la ubicación en la que su registro almacenará sus datos.

En el servidor que creó para alojar su Docker Registry privado, puede crear un directorio docker-registry, moverlo a él, y luego crear una subcarpeta data con los siguientes comandos:

  • mkdir ~/docker-registry && cd $_
  • mkdir data

Utilice su editor de texto para crear el archivo de configuración docker-compose.yml:

  • nano docker-compose.yml

Añada el siguiente contenido al archivo, que describe la configuración básica para un Docker Registry:

docker-compose.yml
version: '3'

services:
  registry:
    image: registry:2
    ports:
    - "5000:5000"
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./data:/data

En la sección environment se establece una variable de entorno en el contenedor de Docker Registry con la ruta /data. La aplicación Docker Registry verifica esta variable de entorno cuando se inicia, y como resultado, comienza a guardar sus datos en la carpeta /data.

Sin embargo, debido a que incluyó la línea volumes: - ./data:/data, Docker comenzará a asignar el directorio /data de ese contenedor a /data en su servidor de registro. Como resultado final, los datos de Docker Registry se almacenan en ~/docker-registry/data en el servidor de registro.

La sección ports, con la configuración 5000:5000, indica a Docker que asigne el puerto 5000 en el servidor al puerto 5000 en el contenedor en ejecución. Esto le permite enviar una solicitud al puerto 5000 en el servidor, y que la solicitud se reenvíe a la aplicación de registro.

Ahora puede iniciar Docker Compose para comprobar la configuración:

  • docker-compose up

Verá las barras de descarga en su resultado, que muestran que Docker está descargando la imagen de Docker Registry del registro propio de Docker. En un minuto o dos, verá un resultado similar al siguiente (las versiones pueden variar):

Output of docker-compose up
Starting docker-registry_registry_1 ... done Attaching to docker-registry_registry_1 registry_1 | time="2018-11-06T18:43:09Z" 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.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="redis not configured" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="Starting upload purge in 20m0s" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="listening on [::]:5000" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2

Abordará el mensaje de advertencia No HTTP secret provided posteriormente en este tutorial. El resultado muestra que el contenedor se está iniciando. La última línea del resultado muestra que comenzó a escuchar correctamente en el puerto 5000.

Por defecto, Docker Compose esperará su intervención. Por ello, pulse CTRL+C para apagar su contenedor de Docker Registry.

Configuró una escucha completa de Docker Registry en el puerto 5000. En este momento, el registro no se iniciará a menos que lo abra manualmente. Además, Docker Registry no tiene ningún mecanismo de autenticación incorporado, por lo que actualmente no es seguro y está completamente abierto al público. En los siguientes pasos, abordará estos problemas de seguridad.

Paso 2: Configurar el reenvío de puertos de Nginx

Ya tiene HTTPS configurado en su servidor de Docker Registry con Nginx, lo que significa que ahora puede configurar el enrutamiento de puertos de Nginx al puerto 5000. Una vez que complete este paso, podrá acceder a su registro directamente en example.com.

Como parte del requisito previo de Cómo proteger Nginx con Let´s Encrypt, ya configuró el archivo /etc/nginx/sites-available/example.com que contiene la configuración de su servidor.

Abra este archivo con su editor de texto:

  • sudo nano /etc/nginx/sites-available/example.com

Encuentre la línea location existente. Tendrá el siguiente aspecto:

/etc/nginx/sites-available/example.com
...
location / {
  ...
}
...

Deberá reenviar el tráfico al puerto 5000, donde se ejecutará su registro. También le conviene adjuntar encabezados a la solicitud al registro, que proporcionan información adicional desde el servidor con cada solicitud y respuesta. Elimine el contenido de la sección location, y añada el siguiente contenido a dicha sección:

/etc/nginx/sites-available/example.com
...
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;
}
...

La sección $http_user_agent verifica que la versión de Docker del cliente sea superior a la 1.5 y garantiza que UserAgent no sea una aplicación de Go. Debido a que usa la versión 2.0 del registro, los clientes más antiguos no son compatibles. Para obtener más información, puede encontrar la configuración de encabezados nginx en la guía Nginx Docker Registry.

Guarde el archivo y ciérrelo. Aplique los cambios reiniciando Nginx:

  • sudo service nginx restart

Puede confirmar que Nginx enrute el tráfico al puerto 5000 ejecutando el registro:

  • cd ~/docker-registry
  • docker-compose up

En una ventana del navegador, abra la siguiente URL:

https://example.com/v2

Verá un objeto JSON vacío, o lo siguiente:

{}

En su terminal, verá un resultado similar al siguiente:

Output of docker-compose up
registry_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.2 registry_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"

Puede ver la última línea desde la cual se realizó una solicitud GET a /v2/, que es el punto final al que envío la solicitud desde su navegador. El contenedor recibió la solicitud que realizó, desde el puerto del enrutamiento, y devolvió una respuesta {}. El código 200 en la última línea del resultado significa que el contenedor gestionó la solicitud correctamente.

Ahora que configuró el enrutamiento de puertos, puede mejorar la seguridad de su registro.

Paso 3: Configurar la autenticación

Con las solicitudes de proxy de Nginx, puede proteger su registro con autenticación HTTP para administrar el acceso a su Docker Registry. Para conseguir esto, creará un archivo de autenticación con htpasswd y le añadirá usuarios. La autenticación HTTP se configura rápidamente y es segura a través de una conexión HTTPS, que es la que el registro usará.

Puede instalar el paquete htpasswd ejecutando lo siguiente:

  • sudo apt install apache2-utils

Ahora creará el directorio en el que almacenará nuestras credenciales de autenticación y se posicionará en ese directorio. $ se expande al último argumento del comando anterior; en este caso, ~/docker-registry/auth:

  • mkdir ~/docker-registry/auth && cd $_

A continuación, creará el primer usuario de como se muestra a continuación, sustituyendo username por el nombre de usuario que desee usar. El indicador -B especifica el cifrado bcrypt, que es más seguro que el cifrado predeterminado. Introduzca la contraseña cuando se le solicite:

  • htpasswd -Bc registry.password username

*Nota: *Para agregar más usuarios, vuelva a ejecutar el comando anterior sin la opción -c, (la “c” significa “crear”):

  • htpasswd registry.password username

A continuación, editará el archivo docker-compose.yml para indicar a Docker que utilice el archivo que creó con el propósito de autenticar usuarios.

  • cd ~/docker-registry
  • nano docker-compose.yml

Puede añadir variables de entorno y un volumen para el directorio auth/ que creó editando el archivo docker-compose.yml, para indicar a Docker la forma en que desea autenticar usuarios. Añada el siguiente contenido resaltado al archivo:

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

Para REGISTRY_AUTH especificó htpasswd, que es el esquema de autenticación que está usando, y fijó REGISTRY_AUTH_HTPASSWD_PATH en la ruta del archivo de autenticación. Por último, REGISTRY_AUTH_HTPASSWD_REALM es el nombre de dominio de htpasswd.

Ahora puede verificar que su autenticación funcione correctamente ejecutando el registro y comprobando que solicite a los usuarios un nombre de usuario y una contraseña.

  • docker-compose up

En una ventana del navegador, abra https://example.com/v2.

Después de ingresar username y la contraseña correspondiente, verá {} una vez más. Con esto, confirmó la configuración básica de autenticación; el registro solo mostró el resultado después de que usted introducido el nombre de usuario y la contraseña correctos. De esta manera, protegió su registro y puede continuar usándolo.

Paso 4: Iniciar Docker Registry como un servicio

Le convendrá asegurarse de que su registro se inicie siempre que el sistema se cargue. Si se produce un error imprevisto en el sistema, le convendrá asegurarse de que el registro se reinicie cuando el servidor lo haga. Abra docker-compose.yml:

  • nano docker-compose.yml

Añada la siguiente línea de contenido en registry:

docker-compose.yml
...
  registry:
    restart: always
...

Puede iniciar su registro como proceso en segundo plano, lo que le permitirá cerrar la sesión ssh y persistir el proceso:

  • docker-compose up -d

Con su registro ejecutándose en segundo plano, ahora podrá preparar Nginx para subir archivos.

Paso 5: Aumentar el tamaño para la carga de archivos para Nginx

Para poder introducir una imagen en el registro, deberá asegurarse de que este pueda gestionar cargas de archivos grandes. Aunque Docker divide las cargas de imágenes grandes en capas separadas, a veces pueden ocupar más de 1 GB. Por defecto, Nginx tiene un límite de 1 MB para las cargas de archivos, de modo que deberá editar el archivo de configuración para nginx y fijar en 2 GB el tamaño máximo para la carga de archivos.

  • sudo nano /etc/nginx/nginx.conf

Busque la sección http y añada la siguiente línea:

/etc/nginx/nginx.conf
...
http {
        client_max_body_size 2000M;
        ...
}
...

Finalmente, reinicie Nginx para aplicar los cambios en la configuración:

  • sudo service nginx restart

Ahora puede subir imágenes grandes a su Docker Registry sin errores de Nginx.

Paso 6: Hacer publicaciones en su Docker Registry privado

Ahora estará listo para publicar una imagen en su Docker Registry privado, pero primero deberá crear una imagen. Para este tutorial, creará una imagen sencilla basada en la imagen de ubuntu de Docker Hub. Docker Hub es un registro alojado públicamente, con muchas imágenes preconfiguradas que pueden utilizarse para “dockerizar” rápidamente aplicaciones. Usando la imagen de ubuntu, probará la introducción en su registro y la y extracción de este.

Desde su servidor cliente, cree una imagen pequeña y vacía para la introducción en su nuevo registro; los indicadores -i y -t le proporcionan acceso de shell interactivo al contenedor:

  • docker run -t -i ubuntu /bin/bash

Tras terminar la descarga, se posicionará dentro de una instrucción de Docker. Tenga en cuenta que el ID de su contenedor después de root@ variará. Realice un cambio rápido en el sistema de archivos creando un archivo llamado SUCCESS. En el siguiente paso, podrá usar este archivo para determinar si el proceso de publicación se realiza correctamente:

  • touch /SUCCESS

Cierre el contenedor de Docker:

  • exit

Con el siguiente comando, se crea una nueva imagen llamada test-image basada en la imagen que ya está en ejecución y se suma cualquier cambio que haya realizado. En nuestro caso, la adición del archivo /SUCCESS se incluye en la nueva imagen.

Aplique el cambio:

  • docker commit $(docker ps -lq) test-image

En este punto, la imagen solo existe a nivel local. Ahora podrá introducirla en el nuevo registro que creó. Inicie sesión en su Docker Registry:

  • docker login https://example.com

Introduzca el username y la contraseña correspondiente antes utilizados. A continuación, etiquetará la imagen con la ubicación del registro privado para introducirla en él:

  • docker tag test-image example.com/test-image

Introduzca la imagen recién etiquetada en el registro:

  • docker push example.com/test-image

El resultado debe tener un aspecto similar al siguiente:

Output
The push refers to a repository [example.com/test-image] e3fbbfb44187: Pushed 5f70bf18a086: Pushed a3b5c80a4eba: Pushed 7f18b442972b: Pushed 3ce512daaf78: Pushed 7aae4540b42d: Pushed ...

Con esto, habrá verificado que su registro gestione la autenticación de usuarios y permita que los usuarios autenticados introduzcan imágenes en el registro. A continuación, confirmará que también puede extraer imágenes del registro.

Paso 7: Realizar extracciones desde su Docker Registry privado

Vuelva al servidor de su registro para poder probar la extracción de la imagen desde su servidor de cliente. También es posible probar esto desde un tercer servidor.

Inicie sesión con el nombre de usuario y la contraseña que estableció previamente:

  • docker login https://example.com

Con esto, estará listo para extraer la imagen. Utilice el nombre de su dominio e imagen, que etiquetó en el paso previo:

  • docker pull example.com/test-image

Docker descargará la imagen y lo conducirá a la línea de comandos. Si ejecuta la imagen en el servidor de registro, verá que el archivo SUCCESS que creó antes estará allí:

  • docker run -it example.com/test-image /bin/bash

Liste sus archivos dentro del shell de bash:

  • ls

Verá el archivo SUCCESS que creó para esta imagen:

SUCCESS  bin  boot  dev  etc  home  lib  lib64  media   mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Con esto, habrá terminado de configurar un registro seguro en el cual los usuarios puedan introducir imágenes personalizadas y desde el cual pueden extraerlas.

Conclusión

A través de este tutorial, configuró su propio Docker Registry privado y publicó una imagen de Docker. Como se mencionó en la introducción, también puede usar TravisCI o una herramienta CI similar para automatizar la introducción directa en un registro privado. Al aprovechar Docker y los registros en su flujo de trabajo, puede garantizar que la imagen que contiene el código tendrá el mismo comportamiento en cualquier máquina, ya sea para la producción o el desarrollo. Para obtener más información sobre la escritura de archivos de Docker, puede leer este tutorial de Docker en el que se explica el proceso.

0 Comments

Creative Commons License