Comment créer des images Docker dans un pipeline GitLab CI – CloudSavvy IT
Un cas d’utilisation courant des pipelines CI consiste à créer les images Docker que vous utiliserez pour déployer votre application. GitLab CI est un excellent choix pour cela car il prend en charge un service de proxy pull intégré, ce qui signifie des pipelines plus rapides et un registre intégré pour stocker vos images construites.
Dans ce guide, nous vous montrerons comment configurer des builds Docker qui utilisent les deux fonctionnalités ci-dessus. Les étapes à suivre varient légèrement en fonction du type d’exécuteur GitLab Runner que vous utiliserez pour votre pipeline. Nous couvrirons les exécuteurs Shell et Docker ci-dessous.
Sommaire
Construire avec le Shell Executor
Si vous utilisez l’exécuteur Shell, assurez-vous que Docker est installé sur la machine qui héberge votre exécuteur. L’exécuteur fonctionne en exécutant des commandes shell régulières à l’aide de la docker
binaire sur l’hôte du Runner.
Dirigez-vous vers le référentiel Git du projet pour lequel vous souhaitez créer des images. Créer un .gitlab-ci.yml
fichier à la racine du référentiel. Ce fichier définit le pipeline GitLab CI qui s’exécutera lorsque vous pousserez des modifications dans votre projet.
Ajoutez le contenu suivant au fichier :
stages: - build docker_build: stage: build script: - docker build -t example.com/example-image:latest . - docker push example.com/example-image:latest
Cette configuration simpliste est suffisante pour démontrer les bases des créations d’images alimentées par pipeline. GitLab clone automatiquement votre référentiel Git dans l’environnement de construction afin de fonctionner docker build
utilisera votre projet Dockerfile
et rendre le contenu du référentiel disponible en tant que contexte de construction.
Une fois la construction terminée, vous pouvez docker push
l’image dans votre registre. Sinon, il ne serait disponible que pour l’installation Docker locale qui a exécuté la construction. Si vous utilisez un registre privé, exécutez docker login
d’abord pour fournir les détails d’authentification appropriés :
script: - docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD
Définissez les valeurs des deux variables d’identification en vous rendant dans Paramètres > CI/CD > Variables dans l’interface utilisateur Web GitLab. Cliquez sur le bouton bleu « Ajouter une variable » pour créer une nouvelle variable et lui attribuer une valeur. GitLab rendra ces variables disponibles dans l’environnement shell utilisé pour exécuter votre travail.
Construire avec l’exécuteur Docker
L’exécuteur Docker de GitLab Runner est couramment utilisé pour fournir un environnement complètement propre pour chaque tâche. La tâche s’exécutera dans un conteneur isolé afin que le docker
binaire sur l’hôte Runner sera inaccessible.
L’exécuteur Docker vous propose deux stratégies possibles pour créer votre image : soit utiliser Docker-in-Docker, soit lier le socket Docker de l’hôte dans l’environnement de construction du Runner. Vous utilisez ensuite l’image officielle du conteneur Docker comme image de votre travail, ce qui rend le docker
commande disponible dans votre script CI.
Docker dans Docker
L’utilisation de Docker-in-Docker (DinD) pour créer vos images vous offre un environnement entièrement isolé pour chaque travail. Le processus Docker qui effectue la construction sera un enfant du conteneur que GitLab Runner crée sur l’hôte pour exécuter la tâche CI.
Vous devez enregistrer votre exécuteur GitLab Runner Docker avec le mode privilégié activé pour utiliser DinD. Ajouter le --docker-privileged
drapeau lors de l’inscription de votre coureur :
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
Dans votre pipeline CI, ajoutez le docker:dind
l’image en tant que service. Cela rend Docker disponible en tant qu’image distincte liée à l’image de la tâche. Vous pourrez utiliser le docker
commande pour créer des images à l’aide de l’instance Docker dans le docker:dind
récipient.
services: - docker:dind docker_build: stage: build image: docker:latest script: - docker build -t example-image:latest .
L’utilisation de DinD vous donne des versions entièrement isolées qui ne peuvent pas avoir d’impact les unes sur les autres ou sur votre hôte. L’inconvénient majeur est un comportement de mise en cache plus compliqué : chaque tâche obtient un nouvel environnement dans lequel les couches précédemment créées ne seront pas accessibles. Vous pouvez partiellement résoudre ce problème en essayant d’extraire la version précédente de votre image avant de créer, puis en utilisant le --cache-from
build flag pour rendre les calques de l’image extraite disponibles en tant que source de cache :
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 .
Supports de liaison à douille
Le montage du socket Docker de votre hôte dans l’environnement de votre tâche est une autre option lorsque vous utilisez l’exécuteur Docker. Cela vous donne une mise en cache transparente et élimine le besoin d’ajouter le docker:dind
service à votre configuration CI.
Pour configurer cela, enregistrez votre Runner avec un docker-volumes
drapeau qui lie le socket Docker de l’hôte à /var/run/docker.sock
à l’intérieur des conteneurs de tâches :
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
Désormais, les tâches qui s’exécutent avec le docker
l’image pourra utiliser le docker
binaire comme d’habitude. Les opérations se produiront réellement sur votre machine hôte, devenant des frères et sœurs du conteneur du travail au lieu d’enfants.
Ceci est en fait similaire à l’utilisation de l’exécuteur de shell avec l’installation Docker de votre hôte. Les images résideront sur l’hôte, ce qui facilitera l’utilisation transparente des docker build
mise en cache des couches.
Bien que cette approche puisse conduire à des performances plus élevées, à moins de configuration et à aucune des limitations de DinD, elle comporte ses propres problèmes uniques. Les plus importantes d’entre elles sont les implications en matière de sécurité : les tâches pourraient exécuter des commandes Docker arbitraires sur votre hôte Runner, de sorte qu’un projet malveillant dans votre instance GitLab pourrait s’exécuter. docker run -it malicious-image:latest
ou docker rm -f $(docker ps -a)
avec des conséquences dévastatrices.
GitLab avertit également que la liaison de socket peut causer des problèmes lorsque les travaux s’exécutent simultanément. Cela se produit lorsque vous comptez sur des conteneurs créés avec des noms spécifiques. Si deux instances d’une tâche s’exécutent en parallèle, la seconde échouera car le nom du conteneur existe déjà sur votre hôte.
Vous devriez envisager d’utiliser DinD à la place si vous pensez que l’un de ces problèmes sera gênant. Bien que DinD ne soit généralement plus recommandé, il peut être plus logique pour les instances GitLab publiques qui exécutent des tâches CI simultanées.
Pousser des images vers le registre de GitLab
Les projets GitLab ont l’option d’un registre intégré que vous pouvez utiliser pour stocker vos images. Vous pouvez afficher le contenu du registre en accédant à Packages et registres > Container Registry dans la barre latérale de votre projet. Si vous ne voyez pas ce lien, activez le registre en accédant à Paramètres > Général > Visibilité, Projet, Fonctionnalités et autorisations et en activant la bascule « Registre de conteneurs ».
GitLab définit automatiquement des variables d’environnement dans vos tâches CI qui vous permettent de référencer le registre de conteneurs de votre projet. Ajuste le script
section pour vous connecter au registre et pousser votre image :
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 génère un ensemble sécurisé d’informations d’identification pour chacune de vos tâches CI. le $CI_JOB_TOKEN
La variable d’environnement contiendra un jeton d’accès que le travail peut utiliser pour se connecter au registre en tant que gitlab-ci-token
utilisateur. L’URL du serveur de registre est disponible en tant que $CI_REGISTRY
.
La variable finale, $CI_REGISTRY_IMAGE
, fournit le chemin d’accès complet au registre de conteneurs de votre projet. C’est une base appropriée pour vos balises d’image. Vous pouvez étendre cette variable pour créer des sous-dépôts, tels que $CI_REGISTRY_IMAGE/production/api:latest
.
D’autres clients Docker peuvent extraire des images du registre en s’authentifiant à l’aide d’un jeton d’accès. Vous pouvez les générer sur l’écran Paramètres > Jetons d’accès de votre projet. Ajouter le read_registry
portée, puis utilisez les informations d’identification affichées pour docker login
au registre de votre projet.
Utilisation du proxy de dépendance de GitLab
Le proxy de dépendance de GitLab fournit une couche de mise en cache pour les images en amont que vous extrayez de Docker Hub. Il vous aide à rester dans les limites de débit de Docker Hub en extrayant uniquement le contenu des images lorsqu’elles ont réellement changé. Cela améliorera également les performances de vos builds.
Le proxy de dépendance est activé au niveau du groupe GitLab en allant dans Paramètres > Packages et registres > Proxy de dépendance. Une fois activé, préfixez les références d’image dans votre .gitlab-ci.yml
dossier avec $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX
pour les faire passer par le 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
C’est tout ce qu’on peut en dire! GitLab Runner se connecte automatiquement au registre du proxy de dépendance, il n’est donc pas nécessaire de fournir manuellement vos informations d’identification.
GitLab mettra désormais en cache vos images, vous offrant des performances améliorées ainsi qu’une résilience aux pannes de réseau. Notez que le services
la définition a également dû être ajustée – les variables d’environnement ne fonctionnent pas avec le formulaire en ligne utilisé précédemment, donc l’image complète name
doit être spécifié, puis une commande alias
à référencer dans votre script
section.
Bien que nous ayons maintenant configuré le proxy pour les images directement utilisées par nos étapes de travail, il reste du travail à faire pour ajouter la prise en charge de l’image de base dans le Dockerfile
construire. Une instruction régulière comme celle-ci ne passera pas par le proxy :
FROM ubuntu:latest
Pour ajouter ce dernier élément, utilisez les arguments de construction de Docker pour rendre l’URL du proxy de dépendance disponible lorsque vous parcourez le Dockerfile :
ARG GITLAB_DEPENDENCY_PROXY FROM ${GITLAB_DEPENDENCY_PROXY}/ubuntu:latest
Modifiez ensuite votre docker build
commande pour définir la valeur de la variable :
script: > - docker build --build-arg GITLAB_DEPENDENCY_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX} -t example-image:latest .
Maintenant, votre image de base sera également extraite via le proxy de dépendance.
Résumé
Les builds d’images Docker s’intègrent facilement dans vos pipelines GitLab CI. Après la configuration initiale de Runner, docker build
et docker push
commandes dans votre travail script
sont tout ce dont vous avez besoin pour créer une image avec la Dockerfile
dans votre référentiel. Le registre de conteneurs intégré de GitLab vous offre un stockage privé pour les images de votre projet.
Au-delà des versions de base, il vaut la peine d’intégrer le proxy de dépendance de GitLab pour accélérer les performances et éviter d’atteindre les limites de débit de Docker Hub. Vous devez également vérifier la sécurité de votre installation en évaluant si la méthode que vous avez sélectionnée permet à des projets non approuvés d’exécuter des commandes sur votre hôte Runner. Bien qu’il comporte ses propres problèmes, Docker-in-Docker est l’approche la plus sûre lorsque votre instance GitLab est publiquement accessible ou accessible par une large base d’utilisateurs.