Creando un Docker Registry en nuestro GitLab

Con el permiso de mi compañero Jon y su post montando un docker registry «Como Dios Manda ™» , ahora que ya hicimos una introducción, muy breve y desenfadada, a Docker y sabemos desarrollar con Docker vamos a retomar el asunto de crear un registry pero haciendo uso de nuestro entorno GitLab, para así unificar código y despliegue en una misma herramienta.

Han pasado casi 4 años y medio desde que os comentamos cómo montar un entorno git multiusuario con GitLab, y eso en informática es un mundo. Nosotros hemos estado actualizando nuestro GitLab de manera periódica para tener las nuevas características y las correcciones de seguridad, incluso hemos actualizado el sistema base a la última versión de Debian. Si tenéis alguna duda o necesitáis ayuda actualizando vuestro sistema GitLab no dudéis en poneros en contacto con nosotros.

 

Repasando: ¿qué es un Registry en Docker y para qué lo quiero?

No está de más hacer un pequeño repaso de para qué sirve un registry y por qué queremos tener uno. Un registry es un lugar donde almacenar imágenes de contenedores y lo vamos a necesitar en cuanto queramos crear nuestras propias imágenes Docker.

La idea de tener un registry propio es el poder tenerlo cerca de nuestros entornos de producción, poder ahorrarnos ancho de banda y tiempo a la hora de realizar los despliegues. No hay que olvidar que por el camino vamos a aprender, y tal como dijo Confucio: «Me lo contaron y lo olvidé; lo vi y lo entendí; lo hice y lo aprendí«. Así que ¡¡manos a la obra!!

 

¿Cómo lo hago funcionar en GitLab?

Debemos tener al menos la versión 8.9 de GitLab para poder tener la opción de crear un registry. Es una versión bastante vieja, por lo que si lo has ido actualizando, no deberías tener problemas. Para activar la opción del registry añadiremos a nuestro fichero /etc/gitlab/gitlab.rb lo siguiente, permitiendo que todos los proyectos por defecto puedan hacer uso del Registry:

gitlab_rails['registry_enabled'] = true

gitlab_rails['gitlab_default_projects_features_container_registry'] = true

gitlab_rails['registry_host'] = hublab.example.com

registry['storage_delete_enabled'] = true

Tras esto tenemos que recargar la configuración de nuestro GitLab y debería empezar a funcionar

gitlab-ctl reconfigure

Las imágenes creadas se almacenan en /var/opt/gitlab/gitlab-rails/shared/registry, por lo que si esperáis hacer uso intensivo y tener mucho histórico de imágenes, aseguraros que en ese path tenéis espacio suficiente.

 

¿Cómo lo puedo probar?

Vamos a crear un repositorio de pruebas que contenga los siguientes ficheros:

  • index.php
<?php

echo "<h1>HOLA MUNDO!</h1>";
phpinfo();

No hay que explicar qué hace este index.php, ¿no? 😉

 

  • docker/Dockerfile:
FROM webdevops/php-nginx:7.4

COPY . /app

EXPOSE 80 443

Este Dockerfile es muy sencillo, básicamente lo que dice es que hace uso de la imagen de la gente de webdevops y copia el contenido que tenemos en nuestro repositorio dentro del directorio /app de la imagen (el path que luego se usa en Nginx para servir la web). Esta imagen «padre» está preparada con un servicio web Nginx y la última release candidate de PHP 7.4, así lo probamos 😀

 

  • .gitlab-ci.yml
variables:
  REGISTRY_HOST: hublab.example.com


build:
  stage: build
  image: docker:stable
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_BUILD_TOKEN $REGISTRY_HOST
    - docker build -t $REGISTRY_HOST/$CI_PROJECT_PATH:$CI_COMMIT_SHA -t $REGISTRY_HOST/$CI_PROJECT_PATH:latest -f docker/Dockerfile .
    - docker push $REGISTRY_HOST/$CI_PROJECT_PATH:$CI_COMMIT_SHA
    - docker push $REGISTRY_HOST/$CI_PROJECT_PATH:latest

Los ficheros .gitlab-ci.yml son los utilizados en GitLab para realizar la Integración Continua (Continuous Integration en inglés), pero también para el desarrollo y el despliegue continuo (Continuous Delivery Continuous Deployment). En este caso lo vamos a utilizar para que en cada commit que realicemos en el repositorio, se cree una imagen nueva en el propio registry que hemos configurado. De manera muy resumida, y sin entrar en detalle, lo que hacemos en este fichero es:

  • se conecta al registry
  • crea la imagen teniendo en cuenta el fichero docker/Dockerfile que hemos añadido en el repositorio
  • hace push de la imagen con el hash del commit
  • hace push de la imagen y la marca como latest

No voy a negar que esto no es lo más óptimo, ya que lo más probable es que no nos interese hacer una imagen de cada commit, y lo ideal sería⁽™⁾ hacerlo sólo cuando creamos un tag. Pero eso lo dejo para que lo investiguéis vosotros 😉

 

GitLab-Runner

Los Gitlab-Runner son los ejecutores de trabajos (jobs) que devuelven la información a GitLab. Estos jobs pueden realizar cualquier cosa, desde analizar que el código es óptimo y no tiene problemas de ejecución, hasta, como es el caso de hoy, realizar una imagen y subirla a nuestro registry. Nosotros hemos ido generando una red de runners por nuestra infraestructura para realizar distintas tareas, pero para la de hoy necesitamos uno (nosotros lo tenemos instalado en el mismo servidor que Gitlab) que tenga la siguiente configuración:

[[runners]]
  name = "gitlab.example.com"
  url = "https://gitlab.example.com"
  token = "TOKEN_RUNNER"
  executor = "docker"
  [runners.custom_build_dir]
  [runners.docker]
    dns = ["8.8.8.8"]
    tls_verify = false
    image = "docker:latest"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
    shm_size = 0
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]

 

Tras esto, cada commit que hagamos, se ejecutará un pipeline, que será ejecutado por nuestro runner, que generará una imagen nueva. En la siguiente imagen podemos ver cómo en mi proyecto de pruebas se han generado varias imágenes Docker

 

Probando nuestra nueva imagen Docker

Ahora que ya tenemos nuestra imagen Docker, vamos a asegurar que podemos descargar la imagen y la podemos ejecutar en nuestro entorno Docker. Primero nos tenemos que loguear contra nuestro nuevo registry:

docker login hublab.example.com       

Username: rubengomez
Password: 

WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

El registry está autenticado con los credenciales de GitLab, y nos avisa que se guardará la contraseña en nuestro ~/.docker/config.json, así que cuidado. Y ahora levantamos un contenedor con la imagen generada:

docker run --name mi-prueba -p 8080:80 -d hublab.example.com/rubengomez/prueba:latest

Lo que hacemos es mapear nuestro puerto 8080 al puerto 80 del contenedor, vamos a a nuestro navegador al puerto 8080 y vemos el contenido de nuestro index.php que está en nuestra imagen:

 

Resumen

En el post de hoy hemos hecho que nuestro servicio GitLab, aparte de servir como repositorio de código fuente, nos sirva a modo de Registry para nuestra infraestructura Docker. No hemos entrado en detalle, pero también hemos realizado nuestro primer job de integración continua, que genera una imagen de nuestro repositorio. Y por último, hemos desplegado la nueva imagen. En breve os traeremos nuevos posts en los que  profundizaremos más en Docker, en integración continua, despliegue continuo y análisis de código.

Esperamos que os haya gustado y os sirva como base para vuestros despliegues. Ya sabéis que si necesitáis cualquier ayuda estamos aquí para poder ayudaros en lo que necesitéis.



¿Te gusta este post? Es solo un ejemplo de cómo podemos ayudar a tu empresa...
Sobre Roman Gomez

Desarrollador full stack

1 Comentario

¿Por qué no comentas tú también?

Queremos tu opinión :)