Lorsque vous créez une image Docker, vous souhaitez peut-être la rendre facilement accessible à vous et au monde entier. La plupart d'entre nous ont été habitués à GitHub pour partager du code et, aujourd'hui, à DockerHub pour rendre nos images Docker accessibles au public.

Auparavant, nous pouvions connecter nos comptes GitHub et DockerHub et demander à DockerHub d'écouter les modifications apportées à notre code pour reconstruire et publier les nouvelles images Docker. Malheureusement, ils ont changé leur modèle. Il faut un abonnement premium pour faire cela.

Nous pouvons toujours reconstruire et pousser toutes les modifications de notre système local vers DockerHub, mais cela est fastidieux et rend un peu plus compliqué de garder un œil sur l'historique de notre image. Heureusement, nous pouvons utiliser les actions GitHub pour effectuer ces tâches à notre place lorsque nous poussons les changements vers le dépôt.

Mise en place du dépôt GitHub

Commençons par mettre en place un dépôt Git et le connecter à notre compte GitHub pour télécharger toutes les données. Tout d'abord, dans le terminal de l'ordinateur, nous devons créer un répertoire et l'initialiser en tant que dépôt Git.

mkdir calculate-pi-image 
cd calculate-pi-image 
git init

Ensuite, nous devons nous connecter au compte GitHub et démarrer un nouveau dépôt, nous pouvons l'appeler comme nous voulons, disons calculate-pi.

Dans le terminal, nous pouvons maintenant connecter notre répertoire local à notre dépôt GitHub distant.

git remote add origin git@github.com:DennisdeBest/calculate-pi.git
git branch -M main

Ajoutons un Dockerfile basique et poussons-le vers le dépôt distant.

echo "FROM alpine:3.15" > Dockerfile
git add . && git commit -m "Init"
git push --set-upstream origin main

Ce fichier est maintenant disponible sur le dépôt public GitHub, mais ce n'est pas encore une image Docker construite et pas du tout disponible sur DockerHub pour le moment.

Création d'un compte DockerHub

Nous devons maintenant configurer un compte DockerHub. Nous devons définir, et garder à l'esprit, le DockerID. Ce sera la base du nom qui sera nécessaire pour obtenir nos images. Nous pouvons maintenant construire nos images Docker localement et les pousser vers DockerHub. Construisons donc notre image de base. L'image doit avoir un nom avec [dockerId]/[image-name] :[tag], Dans mon cas, ce sera debst/calculate-pi:latest.

docker build -f Dockerfile . -t debst/calculate-pi:latest

Nous pouvons maintenant pousser cette image pour la rendre disponible sur notre compte DockerHub. Tout d'abord, nous devons nous assurer que nous sommes connectés. Il nous sera demandé notre ID Docker et notre mot de passe.

docker login

Nous pouvons ainsi pousser notre image.

docker push debst/calculate-pi:latest

Cela fonctionne maintenant et l'image est disponible. Cependant, il s'agit de quelques actions que nous devrons effectuer à chaque mise à jour. Faisons en sorte que GitHub le fasse pour nous chaque fois que nous envoyons de nouvelles mises à jour au dépôt.

Connexion des actions GitHub à DockerHub

Comme je l'ai mentionné au début de cet article, il était autrefois facile de dire à DockerHub de garder un œil sur tout changement dans le dépôt public GitHub et de reconstruire et publier l'image. Comme cela n'est plus possible, nous allons mettre GitHub à notre place et construire, étiqueter et pousser nos images lorsque des changements sont poussés.

Actions

Pour que cela fonctionne, nous devons configurer GitHub Actions. Cela déclenchera le lancement automatique de commandes.

Ces actions sont définies dans un fichier YAML dans notre repository. Nous allons le placer dans le répertoire .github/workflows.

mkdir -p .github/workflows && touch .github/workflows/build-image.yaml

La première chose qui devra être définie dans ce fichier est le déclencheur, quand avons-nous besoin que GitHub fasse un travail pour nous. Est-ce que ce sera à chaque changement dans notre dépôt ou est-ce que nous voulons être plus spécifiques.

Pour les images Docker, j'aime avoir mes balises comme des versions, donc je veux que mon GitHub examine les changements lorsque je pousse une nouvelle balise Git qui ressemble à 0.0.1, 1.0.0, 1.2.0, ...

       │ File: calculate-pi-image/.github/workflows/build-image.yaml
───────┼──────────────────────────────────────────────────────────────────────────────
   6   │ name: Publish Docker image
   7   │ 
   8   │ on:
   9   │   push:
  10   │     tags:
  11   │       - '*.*.*'

Je lui donne un nom et je déclare dans le paramètre on quand il doit faire quelque chose. Je veux qu'il se déclenche lorsque je pousse un tag qui ressemble à quelque chose comme *.*.* .

Si c'était toujours à nous de faire le travail, nous devrions faire les choses suivantes :

  • Obtenir les fichiers de notre image.
  • Se connecter à notre compte DockerHub
  • Obtenir le nom correct et les balises que nous voulons pour notre image
  • construire l'image, la baliser et la pousser vers DockerHub.

Nous devrons donc définir des steps dans notre flux de travail pour lui indiquer ce qu'il doit faire.

  13   │ jobs:
  14   │   push_to_registry:
  15   │     name: Push Docker image to Docker Hub
  16   │     runs-on: ubuntu-latest
  17   │     steps:

Nous devons également lui donner un nom et lui indiquer sur quel système il doit fonctionner pour effectuer son travail.

Obtenir les fichiers pour notre image

Si nous étions sur un nouvel ordinateur et avions besoin d'obtenir tous les fichiers pour travailler dessus, nous allions sur GitHub et les téléchargions.

  17   │     steps:
  18   │       - name: Check out the repo
  19   │         uses: actions/checkout@v2

Ici, le paramètre uses indique à GitHub d'aller chercher l'action Checkout action. Il s'agit d'une action partagée qui est configurée pour obtenir le code et le rendre disponible pour les étapes suivantes qui seront déclenchées.

Se connecter au compte DockerHub

  21   │       - name: Log in to Docker Hub
  22   │         uses: docker/login-action@v1
  23   │         with:
  24   │           username: ${{ secrets.DOCKERHUB_USERNAME }}
  25   │           password: ${{ secrets.DOCKERHUB_PASSWORD }}

Ici, nous obtiendrons l'action docker/login-action. Comme l'action précédente, elle aura toutes les fonctionnalités dont nous avons besoin sous le capot, mais elle ne sera pas en mesure de se connecter à notre compte sans notre nom d'utilisateur et notre mot de passe DockerHub. C'est pourquoi nous devons lui passer quelques paramètres dans la clé with. Le problème ici est que le référentiel GitHub est public et que nous ne voulons pas mettre nos informations d'identification dans un fichier qui se trouve dans ce repository. Avec GitHub, nous pouvons créer des secrets dans notre référentiel et y accéder dans nos actions.

Sur la page paramètres du référentiel, en bas du menu de gauche, nous pouvons voir secrets et, en dessous, actions. Lorsque nous allons dans ce sous-menu, nous pouvons ajouter un nouveau secret de référentiel. Ici, nous pouvons lui donner un nom comme DOCKERHUB_USERNAME et la valeur qui est notre ID Docker. Ensuite, nous pouvons en ajouter un autre pour le mot de passe. Nous ne serons pas en mesure de voir les valeurs que nous venons de définir, nous pouvons seulement les mettre à jour ou les supprimer.

Pour accéder à ces valeurs dans notre fichier action yaml, on peut les récupérer en entourant la valeur d'accolades, d'un signe dollar et en ajoutant secrets.[le nom que nous venons de définir] comme ${{ secrets.DOCKERHUB_USERNAME }}.

Ensuite, nous voulons qu'il prenne en compte le nom et les balises de l'image.

Nom et tags

Nous voulons que nos balises DockerHub correspondent aux balises git qui sont poussées vers le dépôt et nous assurer que la dernière version obtient également la balise latest. Ici, nous pouvons utiliser l'action docker/metadata-action. Elle nécessite une certaine configuration.

  27   │       - name: Extract metadata (tags, labels) for Docker
  28   │         id: meta
  29   │         uses: docker/metadata-action@v3
  30   │         with:
  31   │           images: debst/calculate-pi
  32   │           tags: |
  33   │             type=semver,pattern={{version}}

Tout d'abord, nous devons définir le nom de l'image vers laquelle nous voulons que cette opération soit poussée sur notre DockerHub, il doit s'agir de [Docker ID]/[image name]. Nous allons également lui indiquer comment taguer l'image, ce sont les informations de la clé tags.

Vous pouvez trouver les différentes configurations sur le readme actions' github readme. Nous voulons obtenir les balises de version numérotées et mettre à jour la balise latest, c'est donc la configuration que nous utiliserons.

Construire et pousser l'image

Dernière étape, maintenant que nous sommes connectés à DockerHub et que nous avons tous les fichiers et informations pour construire et étiqueter notre image, nous allons la construire et la pousser !

  35   │       - name: Build and push Docker image
  36   │         uses: docker/build-push-action@v2
  37   │         with:
  38   │           context: .
  39   │           file: Dockerfile
  40   │           push: true
  41   │           tags: ${{ steps.meta.outputs.tags }}

Nous pouvons utiliser le docker/build-push-action. Ici, nous allons lui donner un peu de configuration :

  • Le contexte de la construction de notre image, rien de spécial ici juste le répertoire actuel dans lequel la construction sera exécutée.
  • Le nom du fichier qui contient la configuration de la compilation.
  • S'il doit pousser
  • Les balises qu'il devra pousser, ici nous obtenons le résultat de notre étape précédente ${{ steps.meta.outputs.tags }}.

Ce sont toutes les étapes pour que GitHub fasse ce que nous avons fait au début. Maintenant, nous allons lui faire faire son travail.

Taguer les mises à jour

Maintenant que nous avons le fichier .github/workflow/build-image.yaml nous pouvons mettre à jour le code, ajouter une première balise et voir si tout fonctionne.

git add .
git commit -m "Init workflow"
git tag -a 0.0.1 -m "Init workflow"
git push 
git push --tags

Si nous nous rendons sur notre compte DockerHub, nous devrions maintenant voir l'image calculate-pi avec un nouveau tag 0.0.1 et un tag latest mis à jour.

C'est déjà très bien, mais l'image ne fait rien du tout. Nous voulons en fait qu'elle calcule Π et renvoie la valeur. Pourquoi ne pas ajouter en même temps le temps qu'il a fallu à notre ordinateur pour obtenir le résultat. Nous pouvons ajouter un fichier entrypoint.sh dans notre dépôt, le copier dans notre Dockerfile et le faire tourner lorsque l'image est lancée.

#!/usr/bin/env sh

echo "scale=10;4*a(1)" > /pi_expression
time bc -l /pi_expression

L'ajouter à notre Dockerfile

FROM alpine:3.15

COPY entrypoint.sh /usr/bin/entrypoint
RUN chmod +x /usr/bin/entrypoint

ENTRYPOINT ["entrypoint"]

Mettre à jour le repository avec un nouveau tag.

git add .
git commit -m "Add the pi calculator"
git tag -a 0.1.0 -m "Add the pi calculator"
git push 
git push --tags

Le nouveau tag est maintenant 0.1.0 car l'image fait enfin quelque chose. Une fois les actions effectuées et les nouvelles images téléchargées sur DockerHub, tout le monde peut maintenant exécuter cette image.

docker run --rm debst/calculate-pi:0.1.0 
Unable to find image 'debst/calculate-pi:0.1.0' locally
0.1.0: Pulling from debst/calculate-pi
df9b9388f04a: Pull complete 
fdfddb275d83: Pull complete 
9da7f07aea67: Pull complete 
Digest: sha256:0e49cef1c65d34e69a2a10564cbc22150915b51df6ec04030509c4b3eade271b
Status: Downloaded newer image for debst/calculate-pi:0.1.0
3.1415926532
real    0m 0.00s
user    0m 0.00s
sys     0m 0.00s

Nous pouvons le mettre à jour une fois de plus pour permettre à l'utilisateur de définir le nombre de chiffres qu'il souhaite que le conteneur renvoie une fois qu'il a été exécuté. Pour cela, nous devons mettre à jour notre point d'entrée.

#!/usr/bin/env sh

DIGITS=10

if [ -n "$1" ]; then
    DIGITS=$1
fi

echo "scale=$DIGITS;4*a(1)" > /pi_expression
time bc -l /pi_expression

Maitenant on add, commit, tag en tant que 0.1.1 et push.

git add .
git commit -m "Make the output digits variable"
git tag -a 0.1.1 -m "Make the output digits variable"
git push 
git push --tags

Si nous exécutons maintenant la version précédente, le paramètre ne sera pas pris en compte, mais il le sera pour notre nouvelle version 0.1.1.

docker run --rm debst/calculate-pi:0.1.0 500              
3.1415926532
real    0m 0.00s
user    0m 0.00s
sys     0m 0.00s

docker run --rm debst/calculate-pi:0.1.1 500
Unable to find image 'debst/calculate-pi:0.1.1' locally
0.1.1: Pulling from debst/calculate-pi
df9b9388f04a: Already exists 
c51b9c849ca8: Pull complete 
a7b553074023: Pull complete 
Digest: sha256:412966a92ff929ea652053724b95b58797538a0bba91d79064c08ba100876b7a
Status: Downloaded newer image for debst/calculate-pi:0.1.1
3.141592653589793238462643383279502884197169399375105820974944592307\
81640628620899862803482534211706798214808651328230664709384460955058\
22317253594081284811174502841027019385211055596446229489549303819644\
28810975665933446128475648233786783165271201909145648566923460348610\
45432664821339360726024914127372458700660631558817488152092096282925\
40917153643678925903600113305305488204665213841469519415116094330572\
70365759591953092186117381932611793105118548074462379962749567351885\
75272489122793818301194912
real    0m 0.22s
user    0m 0.21s
sys     0m 0.01s

Automatisez tout !

Voilà, même si DockerHub a supprimé la fonction de construction, de marquage et de mise à jour automatiques des images, nous pouvons toujours automatiser ces opérations grâce aux actions GitHub. J'espère que cela vous aidera à créer et à partager vos images Docker !