Un caso de uso común para las canalizaciones de CI es la creación de las imágenes de Docker que usará para implementar su aplicación. GitLab CI es una excelente opción para esto, ya que admite un servicio de proxy de extracción integrado, lo que significa canalizaciones más rápidas y un registro integrado para almacenar sus imágenes creadas.
En esta guía, le mostraremos cómo configurar compilaciones de Docker que usan las dos funciones anteriores. Los pasos que debe seguir varían ligeramente según el tipo de ejecutor de GitLab Runner que usará para su canalización. Cubriremos los ejecutores de Shell y Docker a continuación.
Crear con el ejecutor de shell
Si está utilizando el ejecutor de Shell, asegúrese de tener Docker instalado en la máquina que aloja su ejecutor. El ejecutor funciona mediante la ejecución de comandos regulares de shell utilizando docker
binario en el host de Runner.
Dirígete al repositorio de Git para el proyecto para el que deseas crear imágenes. Crea un .gitlab-ci.yml
archivo en la raíz del repositorio. Este archivo define la canalización de GitLab CI que se ejecutará cuando envíe cambios a su proyecto.
Agregue el siguiente contenido al archivo:
stages: - build docker_build: stage: build script: - docker build -t example.com/example-image:latest . - docker push example.com/example-image:latest
Esta configuración simplista es suficiente para demostrar los conceptos básicos de las compilaciones de imágenes impulsadas por canalización. GitLab clona automáticamente su repositorio Git en el entorno de compilación, por lo que ejecuta docker build
utilizará el Dockerfile
de su proyecto y hacer que el contenido del repositorio esté disponible como contexto de compilación.
Una vez completada la compilación, puede docker push
la imagen a su registro. De lo contrario, solo estaría disponible para la instalación local de Docker que ejecutó la compilación. Si está utilizando un registro privado, ejecute docker login
primero en proporcionar los detalles de autenticación adecuados:
script: - docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD
Defina los valores de las dos variables de credenciales dirigiéndose a Configuración> CI/CD> Variables en la interfaz de usuario web de GitLab. Haga clic en el botón azul "Agregar variable" para crear una nueva variable y asignarle un valor. GitLab hará que estas variables estén disponibles en el entorno de shell utilizado para ejecutar su trabajo.
Crear con el ejecutor Docker
El ejecutor Docker de GitLab Runner se usa comúnmente para proporcionar un entorno completamente limpio para cada trabajo. El trabajo se ejecutará en un contenedor aislado, por lo que docker
el binario en el host de Runner será inaccesible.
El ejecutor de Docker le brinda dos estrategias posibles para construir su imagen:usar Docker-in-Docker o vincular el socket de Docker del host al entorno de construcción de Runner. Luego usa la imagen oficial del contenedor de Docker como la imagen de su trabajo, haciendo que docker
comando disponible en su secuencia de comandos CI.
Docker-en-Docker
El uso de Docker-in-Docker (DinD) para crear sus imágenes le brinda un entorno completamente aislado para cada trabajo. El proceso de Docker que realiza la compilación será un elemento secundario del contenedor que GitLab Runner crea en el host para ejecutar el trabajo de CI.
Debe registrar su ejecutor Docker de GitLab Runner con el modo privilegiado habilitado para usar DinD. Agregue el --docker-privileged
marca cuando registras a tu corredor:
sudo gitlab-runner register -n --url https://example.com --registration-token $GITLAB_REGISTRATION_TOKEN --executor docker --description "Docker Runner" --docker-image "docker:20.10" --docker-volumes "/certs/client" --docker-privileged
Dentro de su canalización de CI, agregue el docker:dind
imagen como servicio. Esto hace que Docker esté disponible como una imagen separada que está vinculada a la imagen del trabajo. Podrás usar el docker
comando para crear imágenes utilizando la instancia de Docker en docker:dind
contenedor.
services: - docker:dind docker_build: stage: build image: docker:latest script: - docker build -t example-image:latest .
El uso de DinD le brinda compilaciones completamente aisladas que no pueden afectarse entre sí ni a su host. El principal inconveniente es un comportamiento de almacenamiento en caché más complicado:cada trabajo obtiene un nuevo entorno en el que no se podrá acceder a las capas creadas previamente. Puede abordar esto parcialmente al intentar extraer la versión anterior de su imagen antes de compilarla y luego usar --cache-from
marca de compilación para que las capas de la imagen extraída estén disponibles como fuente de caché:
docker_build: stage: build image: docker:latest script: - docker pull $CI_REGISTRY_IMAGE:latest || true - docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:latest .
Monturas de enlace de socket
Montar el socket Docker de su host en el entorno de su trabajo es una opción alternativa cuando utiliza el ejecutor Docker. Esto le brinda un almacenamiento en caché sin problemas y elimina la necesidad de agregar el docker:dind
servicio a su configuración de CI.
Para configurar esto, registre su Runner con un docker-volumes
bandera que une el socket Docker del host a /var/run/docker.sock
dentro de contenedores de trabajo:
sudo gitlab-runner register -n --url https://example.com --registration-token $GITLAB_REGISTRATION_TOKEN --executor docker --description "Docker Runner" --docker-image "docker:20.10" --docker-volumes /var/run/docker.sock:/var/run/docker.sock
Ahora los trabajos que se ejecutan con docker
la imagen podrá usar el docker
binario como normal. Las operaciones en realidad ocurrirán en su máquina host, convirtiéndose en hermanos del contenedor del trabajo en lugar de hijos.
Esto es efectivamente similar a usar el ejecutor de shell con la instalación de Docker de su host. Las imágenes residirán en el host, lo que facilitará el uso continuo de docker build
normal. almacenamiento en caché de capas.
Si bien este enfoque puede conducir a un mayor rendimiento, menos configuración y ninguna de las limitaciones de DinD, tiene sus propios problemas únicos. Las más destacadas son las implicaciones de seguridad:los trabajos podrían ejecutar comandos Docker arbitrarios en su host Runner, por lo que un proyecto malicioso en su instancia de GitLab podría ejecutar docker run -it malicious-image:latest
o docker rm -f $(docker ps -a)
con consecuencias devastadoras.
GitLab también advierte que la vinculación de sockets puede causar problemas cuando los trabajos se ejecutan simultáneamente. Esto ocurre cuando confía en que se crean contenedores con nombres específicos. Si dos instancias de un trabajo se ejecutan en paralelo, la segunda fallará porque el nombre del contenedor ya existirá en su host.
Debería considerar usar DinD en su lugar si espera que cualquiera de estos problemas sea problemático. Si bien DinD ya no se recomienda en general, puede tener más sentido para las instancias de GitLab públicas que ejecutan trabajos de CI simultáneos.
Enviar imágenes al registro de GitLab
Los proyectos de GitLab tienen la opción de un registro integrado que puede usar para almacenar sus imágenes. Puede ver el contenido del registro navegando a Paquetes y registros> Registro de contenedores en la barra lateral de su proyecto. Si no ve este enlace, habilite el registro yendo a Configuración> General> Visibilidad, Proyecto, Funciones y Permisos y activando la opción "Registro de contenedor".
GitLab establece automáticamente variables de entorno en sus trabajos de CI que le permiten hacer referencia al registro de contenedores de su proyecto. Ajustar el script
sección para iniciar sesión en el registro y enviar su imagen:
script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - docker build -t $CI_REGISTRY_IMAGE:latest . - docker push $CI_REGISTRY_IMAGE:latest
GitLab genera un conjunto seguro de credenciales para cada uno de sus trabajos de CI. El $CI_JOB_TOKEN
La variable de entorno contendrá un token de acceso que el trabajo puede usar para conectarse al registro como gitlab-ci-token
usuario. La URL del servidor de registro está disponible como $CI_REGISTRY
.
La variable final, $CI_REGISTRY_IMAGE
, proporciona la ruta completa al registro de contenedores de su proyecto. Esta es una base adecuada para sus etiquetas de imagen. Puede extender esta variable para crear sub-repositorios, como $CI_REGISTRY_IMAGE/production/api:latest
.
Otros clientes de Docker pueden extraer imágenes del registro al autenticarse mediante un token de acceso. Puede generarlos en la pantalla Configuración> Tokens de acceso de su proyecto. Agregue el read_registry
alcance, luego use las credenciales mostradas para docker login
al registro de su proyecto.
Uso del proxy de dependencia de GitLab
Dependency Proxy de GitLab proporciona una capa de almacenamiento en caché para las imágenes ascendentes que extrae de Docker Hub. Le ayuda a mantenerse dentro de los límites de velocidad de Docker Hub extrayendo solo el contenido de las imágenes cuando realmente han cambiado. Esto también mejorará el rendimiento de tus compilaciones.
El proxy de dependencia se activa en el nivel de grupo de GitLab dirigiéndose a Configuración> Paquetes y registros> Proxy de dependencia. Una vez que esté habilitado, prefije las referencias de imágenes en su .gitlab-ci.yml
archivo con $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX
para pasarlos a través del proxy:
docker_build: stage: build image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:latest services: - name: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:dind alias: docker
¡Eso es todo al respecto! GitLab Runner inicia sesión automáticamente en el registro de proxy de dependencia, por lo que no es necesario que proporcione manualmente sus credenciales.
GitLab ahora almacenará en caché sus imágenes, brindándole un mejor rendimiento y resistencia a las interrupciones de la red. Tenga en cuenta que los services
la definición también tuvo que ajustarse:las variables de entorno no funcionan con el formulario en línea utilizado anteriormente, por lo que la imagen completa name
debe especificarse, luego un comando alias
para hacer referencia en su script
sección.
Si bien ya hemos configurado el proxy para imágenes utilizadas directamente por nuestras etapas de trabajo, se necesita más trabajo para agregar soporte para la imagen base en el Dockerfile
para construir. Una instrucción regular como esta no pasará por el proxy:
FROM ubuntu:latest
Para agregar esta pieza final, use los argumentos de compilación de Docker para que la URL del proxy de dependencia esté disponible al recorrer el Dockerfile:
ARG GITLAB_DEPENDENCY_PROXY FROM ${GITLAB_DEPENDENCY_PROXY}/ubuntu:latest
Luego modifique su docker build
comando para definir el valor de la variable:
script: > - docker build --build-arg GITLAB_DEPENDENCY_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX} -t example-image:latest .
Ahora su imagen base también se extraerá a través del proxy de dependencia.
Resumen
Las compilaciones de imágenes de Docker se integran fácilmente en sus canalizaciones de GitLab CI. Después de la configuración inicial de Runner, docker build
y docker push
comandos en el script
de su trabajo es todo lo que necesita para crear una imagen con el Dockerfile
en tu repositorio. El registro de contenedores incorporado de GitLab le brinda almacenamiento privado para las imágenes de su proyecto.
Más allá de las compilaciones básicas, vale la pena integrar el proxy de dependencia de GitLab para acelerar el rendimiento y evitar alcanzar los límites de velocidad de Docker Hub. También debe verificar la seguridad de su instalación evaluando si su método seleccionado permite que proyectos que no sean de confianza ejecuten comandos en su host Runner. Aunque conlleva sus propios problemas, Docker-in-Docker es el enfoque más seguro cuando su instancia de GitLab es de acceso público o una gran base de usuarios accede a ella.