Aller au contenu

Dagger Introduction

Dagger ? Qu’est ce que c’est ?

Dagger est un outil de CI/CD qui a été cofondé par Solomon Hykes, également cofondateur de Docker. Après avoir quitté Docker en 2018, Hykes a lancé Dagger en 2022, visant à révolutionner les pipelines CI/CD en offrant une solution plus flexible et programmable. Dagger permet aux développeurs de définir des pipelines en utilisant des langages de programmation tels que Go, Python ou TypeScript, plutôt que des fichiers de configuration statiques. Cette approche facilite la création de pipelines portables et modulaires, adaptés aux environnements locaux et de production.

Comment vous l’avez compris, fini les plugins au Github Action pour executer en local, puis je vois ici un autre avantage :

Les développeurs pourraient donc maintenant écrire leurs pipelines dans leurs langages préférés et build dans un environnement de bêta exactement la même application que celle qui s’execute sur leurs ordinateurs.

Installation

Il y a plusieurs méthodes d’installation, vous pouvez retrouver le quickstart juste ici https://dagger.io/quickstart Mais, je vous conseille aussi la méthode de Stéphane Robert qui est simple et rapide. Stephane Robert - Dagger

Voici la méthode de Stéphane Robert pour linux :

Fenêtre de terminal
cd /tmp
wget -O dagger_v0.14.0_linux_amd64.tar.gz https://github.com/dagger/dagger/releases/download/v0.14.0/dagger_v0.14.0_linux_amd64.tar.gz
tar xvfz dagger_v0.14.0_linux_amd64.tar.gz
sudo mv dagger /usr/local/bin/
dagger version

Et pour MacOs:

Fenêtre de terminal
brew install dagger/tap/dagger
dagger version

Dans le blog de Stéphane Robert, vous pourrez trouver un exemple en python, ici on va faire du TypeScript !

Je vais prendre en exemple ce projet qui est une petite API en Express (GitHub du Projet)

Initialisation

Donc je vais d’abord clone le projet :

Fenêtre de terminal
git clone git@github.com:Killian-Aidalinfo/node-api-demo.git

Maintenant nous allons initialiser Dagger :

Fenêtre de terminal
dagger init --sdk=typescript --source=./dagger

Nous lui avons donc demandé de s’initialiser avec le SDK TypeScript et de mettre tout ce dont il a besoin dans le dossier ./dagger.

Dagger init

Dans le dossier dagger, il y a un dossier src qui contient le index.ts, qui sera notre CI/CD.

Dagger index

On va remplacer le contenu du fichier index.ts par le code suivant :

import { dag, Container, Directory, object, func } from "@dagger.io/dagger"
@object()
class NodeApiDemo {
@func()
async publish(source: Directory): Promise<string> {
return await this.build(source).publish(
"ttl.sh/myapp-" + Math.floor(Math.random() * 10000000)
);
}
@func()
build(source: Directory): Container {
const nodeCache = dag.cacheVolume("node")
return (
dag
.container()
// start from a base Node.js container
.from("node:21-slim")
// add the source code at /src
.withDirectory("/src", source)
// mount the cache volume at /root/.npm
.withMountedCache("/root/.npm", nodeCache)
// change the working directory to /src
.withWorkdir("/src")
// run npm install to install dependencies
.withExec(["npm", "install"])
.withEntrypoint(["npm", "run", "start"])
.withExposedPort(8080)
)
}
}

Le publish me permet de publier le conteneur temporairement sur le registry ttl.sh, juste pour tester. Et comme vous le voyez ensuite, on va créer un container Node.js, on copie les fichiers de notre répertoire dans /src, on monte le cache de node, on change le dossier de travail, on lance npm install, on déclare l’entrypoint du conteneur et enfin on expose le port 8080.

Pour éviter de copier le node_modules, on peut modifier le dagger.json à la racine de notre projet et rajouter cette clé :

"exclude": [
"**/node_modules"
],
Attention !!!

J’ai perdu 1H sur un détail bête…la ‘class’ doit avoir le même nom que votre projet. Sans -, par exemple mon projet s’appelle node-api-demo, alors la class doit être NodeApiDemo.

Dernière configuration, on va aller modifier le fichier package.json dans dragger/src pour rajouter notre package manager.

"packageManager": "npm@10.8.2"

Dagger package.json

Très bien, normalement nous avons tout qui est prêt.

Build de notre pipeline

On exécute la pipeline ??

Fenêtre de terminal
dagger call publish --source=.

Dagger build

Vous voyez pendant l’exécution qu’on a quelques commandes possibles :

  • w : Ouverture du rendu de la pipeline dans Dagger Cloud

  • +/- : Détail de log

  • q: Quitter la pipeline

Si vous avez un problème, n’hésitez pas à détailler les logs ou encore à faire un docker logs dagger-engine-v0.14.0

Mais ici pas de problème et voici le résultat :

Dagger build result

Et voilà le résultat de la pipeline, on a bien notre image docker sur le registre ttl.sh, qu’on va essayer directement !

Je vais donc le run avec docker run :

Fenêtre de terminal
docker run -p 9900:8080 -d ttl.sh/myapp-3833143@sha256:94f182f0ec555abc7d923d780d922ec8f7fc9990e61027afd65a0b7ecf7e7f4c

Run container

Notre container répond bien !

Result Ready

Nous pouvons donc intégrer cette CI dans github action ou alors déployer depuis notre poste localement.

Détails

Quelques concept que j’ai oublié de mentionner :

  • call : l’agument call permet d’appeler une fonction spécifique de notre pipeline

  • Ordre d’exécution : Dagger organise automatiquement les pipelines en fonction des dépendances entre elles

  • —source : indique le dossier de notre projet, c’est un argument qui permet de récupérer la valeurs dans la fonction.

Conclusion

Je suis conscient que pour l’instant nous n’avons pas une grosse pipeline, mais l’objectif ici était de découvrir ce logiciel. Je ne vais pas tarder à faire une partie une démo avec Bun et ensuite on fera des pipelines plus conséquentes qui se rapprocheront à un environnement de production.