
Ce tutoriel vous guidera dans la création d’un pipeline CI/CD fonctionnel avec Github Actions. Vous créerez un workflow qui exécute automatiquement des tests unitaires sur toutes les demandes d’extraction et déploiera la dernière version de la branche principale sur un cluster Kubernetes.
Pour une introduction aux concepts de base de GitHub Actions, je vous recommande de lire cet article pour apprendre le vocabulaire de base utilisé dans ce tutoriel.
Exigences
Pour suivre ce tutoriel, vous aurez besoin des éléments suivants :
- Un compte GitHub, sans nécessité d’abonnement payant.
- Des connaissances de base en Git et GitHub : savoir valider les modifications sur les branches et créer des pull requests.
- Un compte DockerHub, ou un autre registre de conteneurs public pour le stockage des images.
- Un cluster Kubernetes opérationnel, configuré avec kubectl et disposant de privilèges administrateur sur le cluster. Par exemple, un cluster Google Kubernetes Engine fraîchement déployé conviendra parfaitement. Ce tutoriel est compatible avec la plupart des principaux fournisseurs de cloud.
Étape 0 : forker ce dépôt
La première chose à faire est de créer un fork de ce dépôt. Au fur et à mesure que vous progressez dans les étapes ci-dessous, vous pouvez ajouter votre travail à votre fork.
Une fois forké, clonez le dépôt :
https://github.com/YOUR_USERNAME/GITHUB-ACTIONS-TUTORIAL.git
cd GITHUB-ACTIONS-TUTORIALÉtape 1 : Explorer le référentiel
Ce dépôt contient le code pour un serveur HTTP basique. Voici un aperçu rapide des principaux fichiers disponibles, que vous pouvez explorer plus en détail si vous le souhaitez.
Les fichiers go.mod, main.go et le répertoire foobar/ implémentent un serveur HTTP minimaliste avec des tests unitaires. Le serveur expose deux points de terminaison : /foobar, qui renvoie une séquence FooBar, et /healthz, qui vérifie l’état de santé du serveur.
Un fichier Dockerfile contient les instructions pour compiler le code Go dans une image de conteneur.
Le répertoire manifests/ propose les spécifications des ressources Kubernetes ainsi qu’un fichier de configuration pour Kustomize.
Étape 2 : exécuter automatiquement les tests unitaires
Le package foobar inclut des tests unitaires. Il est recommandé de lancer ces tests pour chaque pull request et à chaque commit sur la branche principale.
Créez un fichier pour le workflow GitHub Actions dans le répertoire de votre dépôt : .github/workflows/workflow.yml. Dans ce fichier, commencez par définir un nom pour le workflow :
name: main-worklfowUtilisez le champ on pour déclencher le workflow à chaque commit sur la branche principale ou lors d’une demande de pull request :
on:
push:
branches:
- master
pull_request:
branches:
- masterUn workflow est composé de tâches indépendantes . Créez une tâche appelée run-tests qui exécutera les tests unitaires de l’application :
jobs:
# Run all unit tests.
run-tests:Chaque job nécessite un système d’exploitation pour fonctionner. Pour ce tutoriel, vous utiliserez Ubuntu. Remplissez le runs-onchamp du travail :
jobs:
# Run all unit tests.
run-tests:
runs-on: ubuntu-latestLes jobs contiennent une liste d’ étapes , qui sont exécutées consécutivement. Souvent, la première étape consiste à cloner votre dépôt pour utiliser le code source qu’il contient. Pour cela, utilisez une action fournie par Github, appeléactions/checkout. Pour utiliser cette action, remplissez le champ uses de la première étape :
jobs:
# Run all unit tests.
run-tests:
runs-on: ubuntu-latest
steps:
# Check out the pull request's source code.
- name: Check out source code
uses: actions/checkout@v3Ensuite, vous devez avoir installé Go pour exécuter vos tests unitaires. Il existe déjà une action qui configure tout pour vous, appelée actions/setup-go. Cette action prend un paramètre go-version, pour savoir quelle version de Go installer. Fournissez des paramètres à une action en remplissant le champ with :
steps:
# Check out the pull request's source code.
- name: Check out source code
uses: actions/checkout@v2
# Install Go.
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: "^1.14" # The Go version to download and use.Dans le code ci-dessus, ^1.14 signifie 1.14.x, où xpeut être n’importe quoi. Chaque version 1.14.x de Go est compatible avec votre code, ce n’est donc pas un problème. Cela étant dit, il serait bien de savoir exactement quelle version de Go vous utilisez ici. Imprimez la version à l’étape suivante. Il n’existe aucune action qui effectue cette opération, utilisez donc le champ run pour exécuter la commande go version :
# Install Go.
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: "^1.14" # The Go version to download and use.
- name: Print Go version
run: go versionLe champ run vous permet d’exécuter n’importe quelle commande shell. Utilisez-le à nouveau dans l’étape finale de la tâche pour exécuter les tests unitaires de votre application :
# Run unit tests.
- name: Run unit tests
run: go test -v ./...À ce stade, vous devriez avoir le code suivant pour votre flux de travail :
name: main-worklfow
env: {}
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
# Run all unit tests.
run-tests:
runs-on: ubuntu-latest
steps:
# Check out the pull request's source code.
- name: Check out source code
uses: actions/checkout@v3
# Install Go.
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: "^1.14" # The Go version to download and use.
- name: Print Go version
run: go version
# Run unit tests.
- name: Run unit tests
run: go test -v ./...Validez ces modifications et transmettez-les vers la branche principale :
git checkout master
git pull
git add .github/workflows/workflow.yml
git commit -m 'Add run-tests job to workflow'
git pushÉtape 3 : Vérifier les résultats du flux de travail
Lorsque vous avez envoyé votre commit sur Github, cela a automatiquement déclenché le workflow. Sur la page de votre dépôt, accédez à l’ onglet Actions . Vous devriez voir l’exécution en question.
Si l’exécution est toujours en cours, un point jaune apparaîtra à côté de votre message de validation. Une fois l’exécution terminée, selon le résultat, une croix rouge ou une coche verte apparaîtront sur l’écran. Pour cette première exécution, les tests unitaires devraient réussir et le flux de travail devrait se terminer avec succès.
Étape 4 : créer et publier automatiquement une image de conteneur
Maintenant que votre application est entièrement testée, il est temps de la conditionner en une image de conteneur et de transférer cette image vers un registre de conteneurs comme DockerHub.
Pour cette étape, vous aurez besoin d’un compte DockerHub. Le référentiel d’images sera créé automatiquement lorsque votre workflow y enverra la première image. Assurez-vous que le référentiel est public, sinon Kubernetes ne pourra pas extraire les images à déployer sans informations d’identification.
Revenez à la branche principale pour continuer la configuration de votre workflow :
git checkout master
git pullAjoutez une deuxième tâche au flux de travail, appelée build-and-release. Cette tâche s’exécute également sur Ubuntu et commence par extraire votre code source :
# Build and release.
build-and-release:
runs-on: ubuntu-latest
steps:
# Check out source code.
- name: Check out source code
uses: actions/checkout@v3Docker Inc. a publié une action qui permet de créer des images de conteneurs et de les envoyer vers un registre de conteneurs. C’est exactement ce que vous souhaitez faire, alors utilisez l’action docker/build-push-action dans l’étape suivante de votre workflow.
Cette action nécessite que vous spécifiiez le registre vers lequel envoyer votre image. C’est une excellente occasion d’utiliser des variables d’environnement. En haut de votre fichier de workflow, ajoutez une variable IMAGE_REPOSITORY dans la section env, qui correspond au registre où vous souhaitez stocker votre image :
env:
IMAGE_REPOSITORY: djrrm01/foobarPour transférer des images vers un registre d’images, Github Actions a besoin d’informations d’identification pour s’authentifier. Les informations sensibles telles que les noms d’utilisateur et les mots de passe ne doivent jamais être écrites dans des fichiers validés dans un système de contrôle de version comme git. Heureusement, Github fournit un moyen de gérer les valeurs secrètes.
Sur la page Web de votre dépôt, accédez à l’ onglet Paramètres , puis sélectionnez Secrets dans le menu de gauche. Ajoutez ensuite deux secrets : DOCKER_USERNAMEet DOCKER_PASSWORD, contenant vos informations d’identification DockerHub.
Vous êtes maintenant prêt à ajouter l’étape finale à votre tâche, en utilisant une action créée par la communauté et sans compromettre la sécurité. Vous ne devez pas simplement utiliser la balise latest pour votre image de conteneur, mais indiquez à l’action docker/build-push-action de baliser votre image avec le nom de la branche et le hachage de la validation qui a déclenché le workflow.
# Build and release.
build-and-release:
runs-on: ubuntu-latest
steps:
# Check out source code.
- name: Check out source code
uses: actions/checkout@v3
# Build and push container image.
- name: Build and push container image
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: ${{ env.IMAGE_REPOSITORY }}
tag_with_ref: true
tag_with_sha: true # sha-${GITHUB_SHA::7}Chaque fois que vous l’utilisez ${{ ... }}dans votre flux de travail, Github injectera dynamiquement des valeurs au moment de l’exécution pour que vos jobs puissent les utiliser.
Validez le workflow mis à jour dans la branche principale et transmettez la modification sur Github :
git checkout master
git pull
git add .github/workflows/workflow.yml
git commit -m 'Add build-and-release job to workflow'
git pushCela déclenchera une exécution du pipeline mis à jour. Suivez sa progression sur Github. Vous remarquerez peut-être que les tâches run-testset build-and-releaseont été exécutées en parallèle. Cela est voulu par la conception : comme les deux tâches sont indépendantes l’une de l’autre, les exécuter en même temps permet à votre flux de travail de s’exécuter plus rapidement et aux développeurs d’obtenir des commentaires sur leur travail plus tôt.
Étape 5 : Créer un fichier de configuration kubectl
Pour déployer sur Kubernetes, nous utiliserons l’outil de ligne de commande kubectl. Afin de vous connecter et de vous authentifier au cluster, vous devrez disposer d’un fichier de configuration contenant les informations d’identification d’un compte de service ayant les autorisations nécessaires pour effectuer le déploiement. Créez un compte de service nommé github-actions avec les autorisations nécessaires pour modifier l’espace de noms default.
kubectl create serviceaccount github-actions --namespace default
kubectl create rolebinding github-actions --clusterrole edit --serviceaccount default:github-actions
kubectl apply -f scripts/secret.yamlEnsuite, vous devrez récupérer le jeton d’authentification du compte de service et créer un fichier de configuration kubectl. Les commandes ci-dessous accomplissent cette tâche pour vous, car ce n’est pas l’objectif principal de ce tutoriel :
scripts/generate-kubeconfig.shAjoutez un autre secret à votre référentiel Github, appelé KUBECONFIG, contenant la chaîne codée en base64 imprimée par le script que vous venez d’exécuter.
Étape 6 : Déployer automatiquement sur Kubernetes
Maintenant que votre application est testée, créée et publiée, il ne reste plus qu’à la déployer. Ajoutez une troisième tâche appelée deployà votre workflow :
# Deploy to Kubernetes.
deploy:
runs-on: ubuntu-latestVous ne souhaitez effectuer un déploiement sur Kubernetes que lorsqu’un nouveau commit est envoyé à la branche principale, mais votre workflow est également déclenché par des requêtes d’extraction. Utilisez le champ if de la tâche pour vous assurer qu’elle s’exécute uniquement lorsqu’elle est déclenchée par la branche principale :
# Deploy to Kubernetes.
deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'Si l’une des deux premières tâches échoue, soit parce que les tests n’ont pas réussi, soit parce que Github n’a pas réussi à créer une image de conteneur, la tâche deploy ne doit pas s’exécuter. Utilisez le champ needs pour spécifier les dépendances entre les tâches :
# Deploy to Kubernetes.
deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
needs:
- run-tests
- build-and-releaseEncore une fois, la première étape de ce job consiste à vérifier votre code source :
# Deploy to Kubernetes.
deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
needs:
- run-tests
- build-and-release
steps:
# Check out source code.
- name: Check out source code
uses: actions/checkout@v2Pour permettre à kubectl d’interagir avec le cluster Kubernetes. Ajoutez une étape pour télécharger et installer le binaire sur le système :
# Set up kubectl.
- name: Set up kubectl
run: |-
curl -sfLo kubectl https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl
chmod +x kubectl
sudo mv kubectl /usr/local/bin/Notez qu’une commande ci-dessus utilise une variable d’environnement appelée KUBECTL_VERSION. Ajoutez-la au champ env en haut de votre fichier de workflow :
env:
IMAGE_REPOSITORY: busser/foobar
KUBECTL_VERSION: "1.14.10"Ajoutez une étape pour décoder la configuration de kubectl, stockée dans le secret KUBECONFIG, et l’enregistrer dans un fichier pour une utilisation ultérieure :
# Configure kubectl.
- name: Configure kubectl
run: echo ${{ secrets.KUBECONFIG }} | base64 --decode > kubeconfig.ymlSi vous avez jeté un œil au fichier manifests/deployment.yml de votre référentiel, vous avez peut-être remarqué cette ligne :
image: REPOSITORY:TAGUtilisez Kustomize pour injecter dynamiquement le nom et la balise de l’image créée lors de la dernière exécution de votre workflow. Ajoutez une étape qui installe le kustomize binaire :
# Set up Kustomize.
- name: Set up Kustomize
run: |-
curl -sfL https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${KUSTOMIZE_VERSION}/kustomize_v${KUSTOMIZE_VERSION}_linux_amd64.tar.gz | tar -xzf -
sudo mv kustomize /usr/local/bin/Une commande ci-dessus utilise la variable d’environnement. KUSTOMIZE_VERSIONAjoutez-la au champ env :
env:
IMAGE_REPOSITORY: busser/foobar
KUBECTL_VERSION: "1.14.10"
KUSTOMIZE_VERSION: "3.5.4"Ajoutez ensuite une étape qui modifie le fichier manifests/kustomization.yml pour spécifier l’image de conteneur à déployer. Assurez-vous que cette étape s’exécute dans le répertoire manifests en renseignant le champ working-directory de l’étape en conséquence :
# Kustomize Kubernetes resources.
- name: Kustomize Kubernetes resources
working-directory: ./manifests
run: kustomize edit set image REPOSITORY:TAG=${IMAGE_REPOSITORY}:sha-${GITHUB_SHA::7}Notez la variable d’environnement GITHUB_SHA. Il n’est pas nécessaire de l’ajouter dans le champ env, car elle est automatiquement définie par GitHub lors de l’exécution du workflow. Cette variable contient le hachage du commit qui a déclenché cette exécution spécifique.
Vous êtes maintenant prêt à effectuer le déploiement. Ajoutez une étape qui crée (ou met à jour) vos ressources Kubernetes :
# Deploy to Kubernetes.
- name: Deploy to Kubernetes
run: kubectl --kubeconfig kubeconfig.yml apply --kustomize manifests/Attendez maintenant que Kubernetes ait terminé de mettre à jour tous les pods de votre déploiement. Si après deux minutes, tous les pods n’ont pas démarré, supposez que le déploiement a échoué. Ajoutez une étape qui permet kubectld’effectuer cette opération :
# Validate deployment.
- name: Validate deployment
run: kubectl --kubeconfig kubeconfig.yml rollout status --timeout 120s deployment/foobarLe job deploy est maintenant prêt à déployer votre application. Validez les modifications que vous avez apportées à votre workflow et transmettez-les sur Github :
git checkout master
git pull
git add .github/workflows/workflow.yml
git commit -m 'Add deploy job to workflow'
git pushL’envoi de vos modifications sur Github déclenche l’exécution de votre workflow finalisé. Github exécute d’abord vos tests et crée une image de conteneur pour votre service. Une fois ces deux tâches terminées avec succès, Github déploie la dernière version de votre application sur votre cluster Kubernetes.
Github affichera les résultats du workflow exécuté sur la page principale de votre référentiel.
Conclusion :
Pour aller plus loin dans l’amélioration de votre workflow, voici quelques pistes à explorer :
Idées simples :
- Ajoutez un badge d’état de workflow à votre référentiel pour suivre l’état des dernières exécutions.
- Enrichissez vos manifestes Kubernetes avec des ressources supplémentaires, comme un Service, pour mieux structurer vos déploiements.
Idées avancées :
- Utilisez un chart Helm au lieu de
kubectletkustomizepour déployer votre application sur Kubernetes, ce qui apporte une meilleure gestion des versions et des configurations. - Configurez le déploiement automatique sur un cluster de staging en déclenchant des espaces de noms dédiés pour chaque requête d’extraction. Pensez à supprimer ces espaces de noms une fois les PR fermées ou fusionnées.
Ces optimisations vous permettront de rendre votre pipeline plus performant et adapté aux besoins de développement continu sur Kubernetes !
✨ J’espère qu’à présent, GitHub Actions n’a plus de secrets pour vous ! 🚀 Si vous avez aimé cet article, n’hésitez pas à laisser un commentaire 💬😊

