Open mmouterde opened 7 years ago
Il faut prendre du recul et ne pas définir le fonctionnement de notre outil de CI autour des possibilités offertes par docker. Pour commencer je renommerai cette issue en "définition et isolation de l'environnement de build" :trollface:
Comment souhaite-t-on décrire l'environnement de build ?
Comment souhaite-t-on décrire les étapes de build ?
Peut-on mixer les 2 ?
environment = [ 'oracle-jdk8', 'maven-3' ]
stage 'build' {
mvn package
}
stage 'install' {
environment = [ 'ansible-2' ]
ansible-playbook -i dev install.yml
}
pour ce qui est environnement, notre CI pourrait:
environment = java()
environment = javascript()
environment = [ tool('oracle-jdk', '^1.8'), tool('maven', '>=3.3.0') ]
et un peut HS :
+1 pour l'environnement de build plutôt déclaratif, je suis pas fan de la solution travis avec les sudo apt-get...
Personnellement j'aimerais vraiment éviter toute invention de DSL, langage, interpréteur, compilateur. Il en existe des tonnes et pour qu'ils "survivent" il faut des outils (coloration, check syntax, check sémantique, IDE, format, pluginable), il faut aussi que ce soit git friendly et de la doc par tonne. Vraiment je crois qu'il est préférable de se focaliser sur l'ouverture aux outils existant plutôt que de réinventer une surcouche à un simili docker/ansible/gradle/maven/gulp... qui sont outillés, documentés, maintenus etc...
Ceci dit, je suis d'accord pour que nous proposions une implémentation qui colle au standard et qui serait activable simplement. Ex : build:"maven" pour les cas où c'est un build standard
Moi j'aime bien l'idée de lancer simplement des commandes dans un environnement customizable. La solution docker (ou équivalent) + script permet du coup à la fois de proposer des dockerfiles standards et de les utiliser dans les cas où l'utilisateur se conforme à une convention, et de proposer qu'il fournisse un dockerFile custom + des shells pour les cas spécifiques (Java 4 sur Platon). S'il veux faire son build en makefile sur un redhat, du ant sur debian, du python, du gulp ... il choisi lui même son outil de description de build (déclaratif ou non). Comme cela on a pas à documenter ni le provisionning d'environnement, ni la description d'un pipeline.
Pour clarifier mon avis autour de docker, je pense que c'est une bonne solution technique, mais je suis pas fan de l'exposer en tant que feature.
Est-ce qu'il n'y aurait pas moyen de générer un dockerfile en fonction de ce que l'utilisateur fournit comme environnement ? Ex: Si l'utilisateur dit : Java8 + Maven3 + Node6, on devrait pouvoir à la volée créer un conteneur qui fournit tout ça. Et comme beaucoup de projets vont avoir des environnements similaires, ça permet de réutiliser des images (alors que si l'utilisateur fait à chaque fois son image custom, c'est plus compliqué à réutiliser)
Ca implique de fournir une liste d'outils supportés par l'outil, du coup ca veut dire qu'il faut en plus fournir un moyen plus avancé mais plus souple de définir l'environnement (par dockerfile par exemple). Ca pourrait donner :
environment = [ tool('oracle-jdk', '^1.8'), tool('maven', '>=3.3.0') ]
ou alors :
environment = [ docker('username/build-image', 'latest') ]
Ou encore mieux (./docker étant un dossier du dépot contenant un dockerfile) :
environment = [ docker('./docker') ]
Dans 99% des cas, fournir ce dockerfile sera inutile. Et la syntaxe permet peut-être de fournir, plus tard, des solutions non couplées à docker.
@jeremiehuchet : Concernant les outils "par défaut" comme tu dis, moi j'aime bien donner la possibilité de le faire. Il faut effectivement que l'utilisateur soit conscient que son build peut casser à cause d'un changement de version. Mais finalement c'est juste la forme la plus souple des patterns de versions à la npm dont tu parles.
Ex : si tu mets tool('maven', '>=3.3.0')
, le jour ou maven 4 sort, il sera utilisé.
Bref, pas forcément une bonne pratique mais ca peut être utile. La convention étant : pas de numéro de version spécifiée : utilisation de la dernière version.
Travis propose maintenant un mode déclaratif pour les packages, de manière à ce que tu puisses en installer même dans leur infra conteneurisée : https://docs.travis-ci.com/user/installing-dependencies/#Installing-Packages-on-Container-Based-Infrastructure C'est un peu pour ça que j'ai lancée l'idée ^^
Y'a des ~tonnes de~(j'allais exagérer un peu ^^) solutions qui se basent déjà sur docker.
Jette un oeil à drone.io et gitlab-ci. Quelles fonctions te manquent dans ces outils ? De mon point de vue ils ont tout ce qu'il faut, mais ils sont très liés à docker et c'est ça que je veux faire sauter.
Dans un docker file qu'on appelle "environnement ruby" rien n'empêche d'y mettre tout et n'importe quoi. Du coup, dire
je build dans l'image docker 'environnement ruby'
ça n'aide pas à comprendre l'environnement nécessaire au build.
Alors qu'un système déclaratif :
il y a ruby et javascript
c'est bien plus clair.
Je trouve que jenkins est parti en sucette à cause de sa multitude de plugins et son IHM infernale. La solution à ce problème c'est pas docker. ~C'est un moyen clair et maintenable de définir son environnement de build.~(en fait j'en sais rien de ce qui est la bonne solution)
Si on laisse l'utilisateur définir son environnement de build dans un dockerfile, il aura la possibilité de faire une image fourre-tout. Ça finira avec :
@BenoitAverty La mauvaise pratique dont tu parles c'est le fait que dans tool('maven', '>=3.3.0')
, j'ai utilisé la feature qui permet de dire "supérieur à". En règle générale il vaut mieux utiliser "compatible avec" (^3.3.0
). On est en phase là dessus ?
@mmouterde si la solution d'origine de travis-ci consistant à installer les outils avec apt-get install...
n'est pas idéale, j'attire ton attention sur le contenu d'un dockerfile "environnement java" ^^ :
FROM machinchouette
RUN apt-get -y update \
&& apt-get -y install java
// et tout le bazar clean cache si le mec veut optimiser la taille
// de son image, et noyer au passage l'information utile
Non seulement c'est procédural, mais ce n'est pas reproductible (apt-get update ne met pas le système dans un état prédictible à tout instant).
@jeremiehuchet : je ne pense pas que ca finira en une image generic avec tout si le dockerFile dans le cas custom fait parti des sources du repo ?!
Je ne discute pas l'intéret du apt-get dans l'absolu, juste que travis propose 'un outil de plus' pour décrire un environnement. Et je voyais d'un mauvais oeil refaire de travail qu'au final docker assure déjà.
@BenoitAverty : En effet on peut produire des images à la volée. par contre j'ai peur que ce soit un peu simpliste de définir un image avec si peu de paramètre, mais pour du build je suppose aussi que c'est viable (contrairment à un env de prod)
@jeremiehuchet En phase sur le "compatible avec". Ma question, c'est est-ce qu'on désactive carrément l'utilisation de '>=' ou est-ce qu'on laisse faire en disant que c'est mauvaise pratique ? Si on laisse faire, on peut aussi laisser la possibilité de ne pas préciser de version du tout, ce qui est équivalent à '>=0.0.0'
@mmouterde En effet, ca serait pas possible pour du run. Mais pour un environnement de build, un dockerfile dans 99% des cas va juste être une suite de apt-get install... Autant abstraire ca de l'utilisateur, ce qui permet une liberté sur le fonctionnement interne, voire de virer docker.
https://nixos.org/nix/about.html, section "Managing build environments"
Pour moi docker est un clé importante. Il permet de regrouper des projets avec des environnements de build différents. que ce soit la version de java, maven, node ou autre, chaque projet devrait être autonome.
@jeremiehuchet citais des exemples que j'ai beaucoup croisés : des projets modernes limités dans le choix de leurs libs/outils parceque la PIC contenait des projets legacy utilisant Java 6 et une JDK spécifique.
du coup j'y vois plusieurs avantages :