\mode* %Follow up of Beamer configuration when using ignorenonframetext. \begin{abstract} Ce document s'attache à montrer quelques fonctionnalités de l'outil \href{https://guix.gnu.org}{GNU Guix}. Il correspond à un tutoriel court d'une durée de 1 heure, cependant les informations données ici peuvent prendre plus de temps. \end{abstract} \indent GNU Guix est un gestionnaire de paquets transactionnel et déclaratif. Il implémente une discipline de gestion de paquet fonctionnelle. Autrement dit, le processus de construction et d’installation des paquets est vu comme une fonction dans le sens mathématique du terme : cette fonction a des entrées (comme des scripts de construction, un compilateur, des bibliothèques ou dépendances) et renvoie une construction (comme un programme compilé). En tant que fonction pure, son résultat ne dépend que de ses entrées ; par exemple, il ne peut pas faire référence à des logiciels ou des scripts qui n’ont pas été explicitement passés en entrée. Par conséquent, une fonction de construction produit toujours le même résultat quand on lui donne le même ensemble d’entrée. Les constructions sont dites reproductibles. \indent Basé sur ces fondations, Guix est un gestionnaire d'environnements logiciels : il peut utiliser les paquets qu’il connaît pour créer des environnements sous différentes formes, temporaires ou «~permanentes~». Un environnement (collection de paquets) peut être déclaré par un manifeste pour générer un « profil~», chaque profil ayant son propre historique permettant de revenir en arrière ou en avant. Un environnement temporaire peut aussi être créé à la volée, et optionnellement isolé (conteneur Linux), ou n'autorisant lecture, écriture ou réseau que spécifiquement. Aussi, ces environnements peuvent être empaquetés dans des images Docker, Singularity ou simplement des archives repositionnables. Pour finir, Guix permet, sur le même principe, la génération de «~machines virtuelles~» à partir d'une déclaration pouvant contenir un système d'exploitation. Une fois installé, Guix ne nécessite pas de droits spécifiques pour manipuler ses différents environnements. \indent Dans ce tutoriel, nous nous proposons d'illustrer quelques spécificités de Guix. Ce tutoriel fait echo à la présentation «~Administration système reproductible avec GNU Guix~» par Julien Lepiller au JRES 2019 (\hrefsf{https://replay.jres.org/videos/watch/c77b3a44-b75f-4c10-9f39-8fb55ae096d7}{vidéo} et \hrefsf{https://conf-ng.jres.org/2019/document_revision_5343.html?download}{article}). \begin{center} (Les termes en police \textsf{sans serif} sont des hyperliens.) \end{center} Ce tutoriel n'est qu'une introduction à l'outil Guix. Nous avons pris le parti d'une approche aussi didactique que possible. Ce document se veut une invitation et non pas un menu exhaustif. \thisslide{why} \begin{frame}[label=why, fragile, plain, noframenumbering]{Pourquoi j'en suis venu à GNU Guix} \begin{alertblock}{\(\approx\) 2010 \textbf{Thésard}} Développement d'1-2 outils utilisant un gestionnaire de paquets \uline{classique} \hfill (Simulation numérique \texttt{C} et \texttt{Fortran} avec Debian / Ubuntu / \texttt{apt}) \end{alertblock} \begin{exampleblock}{\(\approx\) 2014 \textbf{Post-doc}} Développement de 2-3 outils utilisant un gestionnaire de paquets sans droit administrateur \hfill (Simulation numérique \texttt{Python} et \texttt{C++} avec \texttt{conda}) \end{exampleblock} \begin{block}{2016 \textbf{Ingénieur. de Recherche}} \begin{itemize} \item Administration d'un \emph{cluster} (\texttt{modulefiles}) \item Utilisation de 10+ outils pour un même projet \end{itemize} \hfill (Analyse «~bioinformatique~») \end{block} \begin{center} \textbf{Question : \alert{pourquoi cela fonctionne-t-il pour Alice et pas pour Bob ? Et vice-versa.}} \end{center} \end{frame} De cette expérience, la question qui se dégage est la continuité du déploiement de l'environnement computationnel : comment développer sur son ordinateur portable, faire la mise au point sur son ordinateur de bureau et calculer massivement sur la grappe de calcul (\emph{cluster}) mutualisée sans perdre trop de temps sur des problèmes d'administration ? Notre motivation dans l'utilisation de Guix est d'apporter une réponse aux questions : \begin{itemize} \item Comment refaire demain là-bas ce que l'on a fait hier ici ? \item Quelle granularité sur la transparence ? \end{itemize} \paragraph{Pour information :} \begin{itemize} \item \hrefsf{https://docs.conda.io/en/latest/}{Conda} est un gestionnaire d'environnement issu de la communauté Python et visant particulièrement le contexte de logiciels scientifiques. \item La \hrefsf{https://modules.readthedocs.io/en/latest/modulefile.html}% {commande \texttt{module}} est un outil largement répandu sur les grappes de calcul qui permet, en jouant sur les variables d'environnement, de charger des outils spécifiques. \end{itemize} Nous précisons plus loin pourquoi nous ne les considérons pas satisfaisants. \begin{frame}[plain, noframenumbering]{Ce que nous allons aborder} \begin{center} \begin{minipage}{0.7\textwidth} \begin{itemize} \item Comment refaire demain là-bas ce que l'on a fait hier ici ? \item Quelle granularité sur la transparence ? \end{itemize} \end{minipage} \end{center} \setcounter{tocdepth}{2} \tableofcontents \end{frame} \clearpage \section{Introduction} Dans cette section, nous cherchons à souligner le cadre des problèmes et des solutions existantes, ce qui permet, nous l'espérons d'avoir une idée où se positionne l'outil Guix. \subsection{Pourquoi seriez-vous intéressé par Guix ?} Comme nous allons parler de \emph{logiciels}, de \emph{paquets}, \emph{dépendances}, puis de ce que fait un \emph{gestionnaire de paquets} pour créer des environnements computationnels, voici quelques définitions (dans des sens très larges) qui permettent de fixer les idées. \thisslide{start} \begin{frame}[label=start, fragile]{Pour fixer les idées} \begin{tabular}{rl} \rule[-0.3cm]{0cm}{0.3cm} Logiciel & code source ou programme \emph{binaire} associé \\ \rule[-0.3cm]{0cm}{0.3cm} Paquet & recette pour configurer, construire, installer un logiciel \\ \rule[-0.3cm]{0cm}{0.3cm} Dépendance & autre paquet nécessaire \\ \rule[-0.6cm]{0cm}{0.6cm} Gestionnaire de paquets & \begin{minipage}{0.6\linewidth} automatisation du processus traitant la recette du paquet (et ses dépendances) \end{minipage} \\ Environnement computationnel & \begin{minipage}{0.6\linewidth} pile de tous les logiciels nécessaires pour la configuration, construction et installation d'une collection de logiciels \end{minipage} \end{tabular} \begin{exampleblock}{} \begin{center} Comment Alice et ses collaborateurs peuvent-ils obtenir le même environnement \\ pour \emph{calculer} avec Python et Numpy ? \end{center} \end{exampleblock} \begin{alertblock}{} \begin{center} Tuto avec un biais issu d’un environnement plus «~scientifique~» et moins «~ASR~» \textbf{\uline{mais} \red{Guix s’adapte à tous les cas d’usage}} \scriptsize{(ou presque)} \end{center} \end{alertblock} \end{frame} Les collaborateurs d'Alice sont Carole, Charlie et Bob. Tous travaillent sur des machines différentes avec des distributions GNU/Linux différentes. Dan n'a pas d'interaction avec Alice et a sous la main uniquement un document (article de recherche ou fichier de configuration). \thisslide{scenarii} \begin{frame}[label=scenarii, fragile]{Scenarii} \begin{itemize} \item Alice utilise \texttt{python@3.9} et \texttt{numpy@1.20.3} \vspace{-0.25cm} \begin{center} \begin{minipage}{0.75\linewidth} \begin{exampleblock}{} \begin{verbatim} $ sudo apt install python python-numpy \end{verbatim} \end{exampleblock} \end{minipage} \end{center} \item Carole \textbf{collabore} avec Alice\ldots{} mais utilise \texttt{python3.8} et \texttt{numpy@1.16.5} pour un autre projet \vspace{-0.6cm} \begin{center} \begin{minipage}{0.75\linewidth} \begin{exampleblock}{} \begin{verbatim} $ apt-cache madison python-numpy python-numpy | 1:1.16.5-2ubuntu7 | ... \end{verbatim} \end{exampleblock} \end{minipage} \end{center} \item Charlie \textbf{mets à jour} son système et \textbf{tout est cassé} \vspace{-0.25cm} \begin{center} \begin{minipage}{0.75\linewidth} \begin{exampleblock}{} \begin{verbatim} $ sudo apt upgrade The following packages have unmet dependencies: E: Broken packages \end{verbatim} \end{exampleblock} \end{minipage} \end{center} \item Bob utilise les \textbf{\alert{mêmes} versions} qu'Alice mais n'a \textbf{pas le \alert{même} résultat} \item Dan essaie de \textbf{rejouer plus tard} le scénario d'Alice mais rencontre l'\alert{enfer des dépendances} \begin{center} \begin{minipage}{0.75\linewidth} \href{http://repeatability.cs.arizona.edu}% {Repeatability in Computer Science (lien)} \end{minipage} \end{center} \end{itemize} \end{frame} \begin{itemize} \item Qui n’a pas été dans la situation de Carole qui devait installer plusieurs versions d'un même logiciel ? Et ces versions peuvent entrer en conflit. En général, par défaut, une distribution Linux installe uniquement une seule version d'un logiciel avec toutes ses dépendances. Le problème est l'endroit où résident ces logiciels, par défaut le dossier nommé \texttt{/usr/}, et il ne peut pas y avoir deux exécutables, par exemple \texttt{python3}, à deux versions différentes, par exemple \texttt{3.9} et \texttt{3.10}. Il faut donc un logiciel externe qui s'occupe de la gestion de \uline{différentes versions} (et leurs dépendances). \item Qui n'a pas été dans la situation de Charlie la veille d'un évènement important et plus rien ne fonctionnait ? À ma connaissance, cette difficulté de \uline{mise à jour} est une difficulté des administrateurs systèmes de machine partagée : une fois la mise à jour faite, s'il y a de la casse, pas de possibilités de \uline{revenir en arrière}. \item Qui n'a pas été dans la situation de Bob «~pourquoi cela ne fonctionne pas pour moi, et pourtant tout est pareil~» ? Car peut-être que les versions \texttt{python} et \texttt{numpy} de Bob sont bien les mêmes que celles d’Alice, mais le problème est : est-ce bien le cas pour toutes les dépendances et toutes les dépendances de dépendances ? \item Qui n’a pas été dans la situation de Dan en lisant un article scientifique ou un tutoriel ou une documentation ? Le problème est qu’il est difficile de s’assurer que la liste des logiciels requis (ainsi que toutes les dépendances et leurs dépendances) sont à la bonne version sur deux systèmes différents à deux moments différents. \end{itemize} Pour résumer, les problèmes sont : \begin{enumerate} \item installer le logiciel ainsi que toutes les dépendances, \item installer plusieurs versions d’un même logiciel, \item capturer l’état complet du système. \end{enumerate} \thisslide{solutions} \begin{frame}[label=solutions, fragile]{Solution(s)} \begin{enumerate} \item gestionnaire de paquets : APT (Debian/Ubuntu), YUM (RedHat), etc. \item gestionnaire d'environnements : Modulefiles, Conda, etc. \item conteneur : Docker, Singularity \end{enumerate} \begin{alertblock}{} \begin{center} Guix = \#1 + \#2 + \#3 \end{center} \end{alertblock} \begin{description} \item[APT, Yum] Difficile de faire coexister plusieurs versions ou revenir en arrière ? \item[Modulefiles] Comment sont-ils maintenus ? (qui les utilise sur son \emph{laptop} ?) \item[Conda] Quelle granularité sur la transparence ? (qui sait comment a été produit PyTorch dans \texttt{pip install torch} ? \href{http://hpc.guix.info/blog/2021/09/whats-in-a-package/}% {\scriptsize{(lien)}}) \item[Docker] Dockerfile basé sur APT, YUM etc. \begin{minipage}{1.0\linewidth} \begin{exampleblock}{} \begin{verbatim} RUN apt-get update && apt-get install \end{verbatim} \end{exampleblock} \end{minipage} \end{description} \end{frame} Rappelons brièvement les termes des solutions : \begin{itemize} \item un gestionnaire de paquets automatise le processus pour configurer, construire et installer le logiciel ainsi que toutes les dépendances, \item un gestionnaire d'environnements autorise la coexistence de plusieurs versions d'un même logiciel, le plus souvent en jouant sur les variables d’environnement, \item un conteneur fournit tous les binaires pour être transporté d’une machine à l’autre et donc fonctionne indépendamment de la configuration de la machine hôte. \end{itemize} \bigskip La double difficulté majeure est : \begin{itemize} \item d’une part, un contrôle fin dans la production du binaire, \item d’autre part, la reproductibilité, au sens «~refaire ailleurs~» (autre configuration, autre moment). \end{itemize} \medskip Guix, en étant un gestionnaire d’environnements sous \emph{stéroïde}, tente de répondre à cette double difficulté. \thisslide{interet} \begin{frame}[label=interet]{Concrètement} Soit \begin{itemize} \item vous vous reconnaissez dans un scénario, \item vous n'êtes pas satisfait par une des solutions, \item vous êtes curieux d'un nouveau outil. \end{itemize} \bigskip Dans les 3 cas, ce tutoriel illustre : \begin{itemize} \item Comment faire en pratique avec GNU Guix. \item Quel est le problème à traiter ? Et pourquoi c'est compliqué. \end{itemize} \begin{alertblock}{} \begin{center} Guix est un gestionnaire d'environnements sous \emph{stéroïde} \end{center} \end{alertblock} Ce tutoriel est complémentaire de la présentation de Julien Lepiller en 2019 (\href{https://replay.jres.org/videos/watch/c77b3a44-b75f-4c10-9f39-8fb55ae096d7}{vidéo} et \href{https://conf-ng.jres.org/2019/document_revision_5343.html?download}{article}) \end{frame} \thisslide{steroide} \begin{frame}[label=steroide]{\emph{Stéroïde} signifie\dots} \begin{tabular}{lr} un \uline{\textbf{gestionnaire de paquets}} & (comme APT, Yum, etc.) \\ \ \ transactionnel et déclaratif & (revenir en arrière, versions concurrentes) \\ \ \ \ \ qui produit des \uline{\textbf{\emph{packs} distribuables}} & (conteneur Docker ou Singularity) \\ \ \ \ \ \ \ qui génèrent des \textbf{\uline{\emph{machines virtuelles}} isolées} & (\emph{à la} Ansible ou Packer) \\ \ \ \ \ \ \ \ \ sur lequel on construit une distribution Linux & (nous n'en parlerons pas) \\ \ \ \ \ \ \ \ \ \ \ \dots et aussi une bibliothèque Scheme\dots & (nous n'en parlerons pas, non plus) \end{tabular} \begin{alertblock}{} Ce tuto court est un coup de projecteur sur : \begin{itemize} \item la gestion de paquets \emph{fonctionnelle} \item création de \emph{machines virtuelles} \end{itemize} \begin{center} \textbf{\alert{Ce que nous présentons fonctionne sur n'importe quelle distribution Linux}} \end{center} \end{alertblock} \begin{flushright} \small{% (Facile à essayer\dots) } \end{flushright} \end{frame} \paragraph{Convention.} Nous notons \texttt{foo@1.2} pour le logiciel \texttt{foo} à la version \texttt{1.2}. Usuellement, une ligne commençant par \texttt{\$} (dollar) représente une commande \emph{shell}, ainsi que par la suite toutes les lignes commençant par \texttt{guix}. La commande \texttt{sudo} signifie des droits administrateur. \clearpage \subsection{Installation de GNU Guix} Il est important de noter en tout premier lieu le \hrefsf{https://guix.gnu.org/en/manual/devel/fr/}{manuel} (traduit en français) qui fournit le point d’entrée pour l’installation et la configuration. La version de référence est la \hrefsf{https://guix.gnu.org/en/manual/devel/en/}% {version anglaise}. \subsubsection{Installation recommandée} Nous recommandons d’installer Guix sur une distribution Linux, voir la section \href{https://guix.gnu.org/en/manual/devel/fr/guix.fr.html#Installation-binaire}% {\textsf{Installation binaire}} du manuel. En tant que \texttt{root} (avec les droits administrateur), il faut exécuter les commandes : \begin{verbatim} cd /tmp wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh chmod +x guix-install.sh ./guix-install.sh \end{verbatim} \paragraph{Attention.} Nous vous recommandons de parcourir le script \emph{shell} \texttt{guix-install.sh} et de ne pas l’exécuter aveuglément. Ce script fait principalement 2 choses : \begin{enumerate} \item télécharge, installe et configure le démon \texttt{guix-daemon}, \item crée les différents dossiers nécessaires au bon fonctionnement. \end{enumerate} \paragraph{Cette installation n'interfère en rien avec la distribution hôte.} Pour «~désinstaller~» Guix, il suffit de supprimer les dossiers \texttt{/gnu}, \texttt{/var/guix}, \texttt{\$HOME/\{.cache,.config\}/guix}, \texttt{/root/.config/guix} et les mécanismes de complétion de \emph{shell} (p. ex. \texttt{/etc/bash\_completion.d}). \paragraph{Remarques.} Pour une utilisation plus agréable, nous recommandons d’au\-to\-ri\-ser les substituts binaires (voir la section \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Substituts}{\textsf{Substituts}}) lors de l’installation via le script. Nous recommandons aussi de configurer \emph{Name Service Switch} (\texttt{nscd}) sur la distribution hôte (voir la \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Name-Service-Switch-1}{\textsf{section}} du manuel pour une explication du pourquoi). \medskip Pour des constructions locales, il est aussi possible d’utiliser un mécanisme de déchargement (\emph{offload}) sur une machine tierce. Nous renvoyons à la section du manuel \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#R_00e9glages-du-d_00e9chargement-du-d_00e9mon}% {\textsf{Utiliser le dispositif de déchargement}}. \medskip Pour finir, nous recommandons d’installer le paquet \texttt{glibc-locales}, dans le \emph{profil} \texttt{root} ainsi que dans le \emph{profil} utilisateurs (voir la section \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Regionalisation}% {\textsf{Régionalisation}}). \begin{center} \texttt{sudo guix install glibc-locales} \texttt{guix install glibc-locales} \end{center} et d’exporter la variable d’environnement \begin{center} \texttt{export GUIX\_LOCPATH=\$HOME/.guix-profile/lib/locale} \end{center} ce qui évite des messages de \emph{warning}. \begin{frame}[fragile]{\emph{distro externe}} \begin{alertblock}{} \begin{center} Guix s’installe sur \textbf{\uline{n’importe quelle distribution}} Linux récente. \end{center} \end{alertblock} Il faut les droits administrateur (\texttt{root}) pour l’installation. \begin{exampleblock}{} \begin{verbatim} $ cd /tmp $ wget https://git.savannah.gnu.org/cgit/guix.git/plain/etc/guix-install.sh $ chmod +x guix-install.sh $ sudo ./guix-install.sh \end{verbatim} \end{exampleblock} \begin{center} (Quelques réglages supplémentaires sont expliqués dans les notes additionnelles) \end{center} Pour commencer : \begin{center} \begin{minipage}{0.75\linewidth} \begin{verbatim} $ guix help \end{verbatim} \end{minipage} \end{center} \end{frame} \subsubsection{Autres méthodes d'installation} \paragraph{Guix System, Guix dans une VM.} Il nous apparaît plus aisé de commencer par installer Guix sur une distribution Linux et d’utiliser l’outil comme gestionnaire de paquets sous \emph{stéroïde}. Mais les plus téméraires d’entre vous peuvent vouloir installer Guix comme système d’exploitation complet ou dans une machine virtuelle. Dans ce cas, le manuel fournit une \hrefsf{https://guix.gnu.org/en/manual/devel/fr/guix.fr.html\#Installation-du-syst\_00e8me}% {section} dédiée. Nous recommandons d’utiliser l’\hrefsf{https://guix.gnu.org/en/manual/devel/fr/guix.fr.html\#Installation-graphique-guid\_00e9e}% {installateur graphique}. \medskip Par ailleurs, il est à noter que Guix n’a pas un modèle stable versus expérimental mais des révisions considérées comme \emph{release}, intensivement testées mais ne recevant pas de correctifs. Actuellement, c’est l’étiquette \hrefsf{https://guix.gnu.org/en/blog/2021/gnu-guix-1.3.0-released/}{v1.3.0} sortie au mois de mai 2021. Il est possible de télécharger des images soit de la version dite «~\hrefsf{https://guix.gnu.org/fr/download/}{standard}~» (v1.3.0), soit des images générées à partir des derniers \hrefsf{https://guix.gnu.org/fr/download/latest/}{développements}. Chacun a ses avantages et inconvénients : \begin{description} \item[avantage «~standard~» :] bien testé, \item[inconvénient «~standard~» :] potentiel manque de substituts binaires, \item[avantage «~derniers développements~» :] inclus les correctifs depuis le dernier étiquetage, \item[inconvénient «~derniers développements~» :] potentiellement instable ; ça peut fonctionner parfaitement comme cela peut être cassé. \end{description} \paragraph{Installation via le paquet Debian.} Nous n’avons pas intensivement testé cette méthode d’installation, c’est pourquoi nous la ne recommanderions pas. Mais elle est peut-être d’intérêt pour certains d’entre vous. La version Debian \hrefsf{https://packages.debian.org/bullseye/guix}{Bullseye} fournit le paquet Guix : \begin{verbatim} $ sudo apt install guix \end{verbatim} \paragraph{Installation sur une grappe de calcul.} Les grappes de calcul (\emph{cluster}) ont souvent des configurations très spécifiques, nous renvoyons à cette \hrefsf{https://hpc.guix.info/blog/2017/11/installing-guix-on-a-cluster/}{explications} pour les points essentiels. Sinon, nous recommandons de prendre contact avec la communauté via p. ex. \texttt{guix-science@gnu.org}. \subsubsection{Révision de Guix pour ce tutoriel} Ce tutoriel devrait être pouvoir être joué quelque soit la révision. Cependant, il est possible que les exemples fournis évoluent ; comme les versions des paquets Python ou autres. La commande, en tant qu’utilisateur sans privilège particulier, \begin{center} \texttt{\$ guix pull -{}-commit=eb34ff1} \end{center} permet de se placer dans l’exact même révision que celle utilisée lors de l’écriture de ce document. \paragraph{Remarques.} Les \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Serveur-de-substituts-officiel}% {\textsf{fermes de substituts officielles}} n’étant pas des ressources illimitées, il est possible que les substituts ne soient plus disponibles dans quelques mois ou années après mai 2022. Le projet Guix s’efforce autant que possible d’assurer la conservation des substituts binaires qu’il produit et nous espérons que cette remarque soit caduque. \medskip Dans le cas d’absence de substituts binaires, cela signifie que la commande précédente (\texttt{pull}) risque de prendre plus de temps, mais surtout que les exemples utilisant les piles logicielles risquent de compiler depuis les sources toutes les dépendances (binaires) manquantes de la dite pile. D’un côté, c’est pour cela que Guix est un outil puissant pour la reproductibilité. \medskip D’un autre côté, si les substituts ne sont plus disponibles, alors il sera difficile de suivre ce tutoriel avec votre ordinateur portable et nous conseillons donc d’utiliser un \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#R_00e9glages-du-d_00e9chargement-du-d_00e9mon}% {\textsf{déchargement (\emph{offload})}}. Ou de saisir l’esprit général et d’utiliser vos propres exemples avec substituts. \begin{frame}[plain,fragile,noframenumbering]{} \vfill{} \begin{center} \textbf{Comment faire la gestion de paquets ?} \end{center} \vfill{} \begin{flushright} (Exemple : Alice sans privilège particulier) \end{flushright} \vfill{} \begin{minipage}{0.57\linewidth} \begin{alertblock}{} \begin{itemize} \item Démos avec des outils du «~\emph{monde scientifique}~» \item Guix représente 20k+ paquets \scriptsize{(constante progression)}\normalsize{} \item Cela serait identique pour d'autres outils\\ \hfill{} comme Nginx, LDAP, SSH, etc. \end{itemize} \end{alertblock} \end{minipage} \end{frame} \clearpage \section{Gestion de paquets} À partir de cette section, nous considérons une installation fonctionnelle de l’outil Guix sur une distribution Linux récente. Toutes les commandes seront exécutées dans un terminal en tant qu’utilisateur régulier (sans droit d’administration particulier). La révision de Guix utilisée est \texttt{eb34ff1}. \medskip Nous recommandons la lecture de la section «~\href{https://guix.gnu.org/en/manual/devel/fr/guix.fr.html\#Pour-d\_00e9marrer}{Pour démarrer}~» du manuel. \subsection{Utilisation de \texttt{guix package}} Guix est avant tout un gestionnaire de paquets, c.-à-d. que Guix automatise le processus pour configurer, construire et installer le logiciel ainsi que toutes les dépendances. Les fonctionnalités de gestion de paquets sont données par la commande \texttt{guix package}. \begin{frame}[fragile]{Commandes basiques} \begin{center} Exemple : outils scientifiques classiques en Python \end{center} \bigskip \begin{center} (\texttt{demo/getting-started}) \end{center} \end{frame} \thisslide{cli-basic} \begin{frame}[label=cli-basic, fragile]{Commandes basiques : Résumé} \begin{exampleblock}{} \begin{verbatim} guix search dynamically-typed programming language # 1. guix show python # 2. guix install python # 3. guix install python-ipython python-numpy # 4. guix remove python-ipython # 5. guix install python-matplotlib python-scipy # 6. \end{verbatim} \end{exampleblock} \begin{center} alias de \texttt{guix package}, p. ex. \verb+guix package --install+ \end{center} \begin{alertblock}{Transactionnel} \begin{verbatim} guix package --install python # 3. guix package --install python-ipython python-numpy # 4. guix package -r python-ipython -i python-matplotlib python-scipy # 5. & 6. \end{verbatim} \end{alertblock} \end{frame} Les commandes précédentes sont des alias de la commande \texttt{guix package}. \begin{center} \begin{tabular}{clcl} $1.$ & \texttt{guix search} & $\leftrightarrow$ & \texttt{guix package -{}-search=}\\ $2.$& \texttt{guix show} & $\leftrightarrow$ & \texttt{guix package -{}-show=}\\ $3.$& \texttt{guix install} & $\leftrightarrow$ & \texttt{guix package -{}-install=}\\ $4.$& \texttt{guix remove} & $\leftrightarrow$ & \texttt{guix package -{}-remove=}\\ \end{tabular} \end{center} Pour de plus amples informations sur chacune des commandes, se référer au manuel (section \hrefsf{https://guix.gnu.org/en/manual/devel/fr/guix.fr.html\#Invoquer-guix-package}% {Invoquer \texttt{guix package}}). En quelques mots : \begin{enumerate} \item \texttt{guix search} : Recherche dans tous les paquets disponibles les termes \texttt{dynamically-typed programming language} dans les noms, synopsis et descriptions des paquets. \item \texttt{guix show} : Affiche les informations relatives au paquet : nom, version, dépendances, synopsis, description, etc. Par convention si aucune version n’est donnée, il choisit la dernière. \item \texttt{guix install} : Installe le paquet \texttt{python}, par convention si aucune version n’est donnée, il choisit la dernière. \item Installe les paquets \texttt{python-ipython python-numpy}. \item \texttt{guix remove} : Supprime l’installation du paquet \texttt{python-ipython}. \item Installe les deux autres paquets \texttt{python-matplotlib python-scipy}. \end{enumerate} Il est important de noter que les opérations d'installation / suppression sont transactionnelles. D'une part, une action (transaction) peut comporter plusieurs opérations. D'autre part, cette action (transaction) transforme un état dans un autre et ces états sont sauvegardés (voir \emph{génération} et la {Gestion de \emph{profil}}, section \textsf{\ref{sec:profil}}) ; en d'autres termes il est toujours possible de défaire une action (transaction). \thisslide{pkg-man} \begin{frame}[label=pkg-man]{Guix, un gestionnaire de paquets comme les autres ?} \begin{alertblock}{} \begin{itemize} \item Interface \emph{ligne de commande} comme les autres gestionnaires de paquets \item Installation/suppression sans privilège particulier \item Transactionnel (= pas d'état «~\emph{cassé}~») \item \emph{Substituts} binaires (téléchargement d'éléments pré-construits) \end{itemize} \end{alertblock} \begin{center} \textbf{Trois fonctionnalités puissantes :} \end{center} \begin{exampleblock}{} \begin{itemize} \item Les \emph{profils} et leur composition \item Gestion déclarative \item Environnement isolé à la volée \end{itemize} \end{exampleblock} \end{frame} Toutes ces commandes ressemblent très fortement à toutes celles d’autres gestionnaires de paquets, comme \texttt{apt} (Debian/Ubuntu) ou \texttt{yum} (RedHat). À la différence qu'il ne faut pas de droits d'administration particuliers pour installer des paquets. \medskip Nous allons maintenant illustrer trois fonctionnalités qui font de Guix le couteau suisse des gestionnaires d'environnement. Les \emph{profils} permettent de garder sous contrôle l'installation d'outils (paquets) potentiellement en conflit. La \emph{gestion déclarative} permet de configurer les \emph{profils} dans un style de programmation fonctionnelle. Pour finir, nous verrons la création à la volée d'un environnement computationnel et optionnellement isolé. \clearpage \subsection{Gestion de \emph{profil}} \label{sec:profil} Un notion essentielle dans l’utilisation de Guix est la notion de \emph{profil} : un répertoire contenant les paquets installés. \thisslide{profil-default} \begin{frame}[label=profil-default, fragile]{Le \emph{profil} par défaut} Les commandes d’installation précédentes finissent avec le conseil : \begin{exampleblock}{} \begin{verbatim} hint: Consider setting the necessary environment variables by running: GUIX_PROFILE="/home/alice/.guix-profile" . "$GUIX_PROFILE/etc/profile" Alternately, see `guix package --search-paths -p "$HOME/.guix-profile"'. \end{verbatim} \end{exampleblock} \begin{alertblock}{} \begin{center} \texttt{\$HOME/.guix-profile} est le \emph{profil} par défaut \end{center} \end{alertblock} \end{frame} Il n'est pas nécessaire d'entrer dans ces détails pour utiliser Guix mais ce tutoriel nous apparaît opportun pour décortiquer. \medskip Le profil par défaut est \texttt{\$HOME/.guix-profile} et nous pouvons afficher les variables d'environnements de ce profil avec la commande \begin{verbatim} $ guix package --search-paths -p $HOME/.guix-profile export PATH="/home/alice/.guix-profile/bin" export GUIX_PYTHONPATH="/home/alice/.guix-profile/lib/python3.9/site-packages" export GI_TYPELIB_PATH="/home/alice/.guix-profile/lib/girepository-1.0" export XDG_DATA_DIRS="/home/alice/.guix-profile/share" \end{verbatim} et ce profil est un lien symbolique \begin{verbatim} $ file $HOME/.guix-profile /home/alice/.guix-profile: symbolic link to /var/guix/profiles/per-user/alice/guix-profile \end{verbatim} et vers quoi pointe le lien ? \begin{verbatim} $ readlink -f $HOME/.guix-profile /gnu/store/jy24qk0vdgqvysnryldqn52b3fg03z10-profile \end{verbatim} où \texttt{jy24qk...} ressemble à un condensat (\emph{hash}) -- il condense toutes les entrées (dépendances) pour la construction dudit profil. Le type du lien pointé est un dossier \begin{verbatim} $ file $(readlink -f ~/.guix-profile) /gnu/store/jy24qk0vdgqvysnryldqn52b3fg03z10-profile: directory \end{verbatim} et ce dossier contient \begin{verbatim} $ tree -L 1 $(readlink -f ~/.guix-profile) /gnu/store/jy24qk0vdgqvysnryldqn52b3fg03z10-profile |-- bin |-- etc |-- include |-- lib |-- manifest `-- share \end{verbatim} \thisslide{profil} \begin{frame}[label=profil, fragile]{Mais qu'est-ce un \emph{profil} ?} \begin{center} Filesystem Hierarchy Standard (FHS) = norme de la hiérarchie des systèmes de fichiers \medskip (définit l'arborescence et contenu des répertoires systèmes pour les systèmes Unix) \end{center} \begin{exampleblock}{} \begin{Verbatim} usr |-- bin Binaires exécutables |-- etc Fichiers de configuration |-- include Entêtes des bibliothèques partagées |-- lib Bibliothèques partagées |-- share Documentation entre autres \end{Verbatim} \end{exampleblock} \begin{center} % XXXX: demo ? \verb+ls $HOME/.guix-profile+ \end{center} \begin{alertblock}{} \begin{center} Un \emph{profil} est un répertoire contenant les paquets installés \end{center} \end{alertblock} \end{frame} \textbf{Conclusion} \begin{itemize} \item Un \emph{profil} contient les variables d’environnements ajustées. \item Un \emph{profil} est un lien symbolique. \item Un \emph{profil} pointe vers un dossier du dépôt (\emph{store}). \item Un \emph{profil} a la structure hiérarchique de FHS (comme \texttt{/usr/}). \end{itemize} Sans entrer dans les détails, le dépôt (\emph{store}) est monté à \texttt{/gnu/store} et il est dédupliqué, c.-à-d. qu'il pourrait être vu comme une forêt de liens symboliques (voir \textsf{Fig. \ref{fig:symlinks}}). \begin{figure}[!htb] \centering \includegraphics[width=0.7\textwidth]{static/forest-symlinks.pdf} \caption{Forêt de liens symboliques \label{fig:symlinks}} \end{figure} L'exemple \textsf{Fig. \ref{fig:symlinks}} utilise des paquets qui sont classiques dans le contexte bioinformatique. Cependant, on peut se poser la question des nombres 42 et 43. Examinons ceci. \begin{verbatim} $ ls -l /var/guix/profiles/per-user/alice/guix-profile* /var/guix/profiles/per-user/alice/guix-profile -> guix-profile-5-link /var/guix/profiles/per-user/alice/guix-profile-0-link -> /gnu/store/0fv...-profile /var/guix/profiles/per-user/alice/guix-profile-1-link -> /gnu/store/vsr...-profile /var/guix/profiles/per-user/alice/guix-profile-2-link -> /gnu/store/k3c...-profile /var/guix/profiles/per-user/alice/guix-profile-3-link -> /gnu/store/dks...-profile /var/guix/profiles/per-user/alice/guix-profile-4-link -> /gnu/store/33d...-profile /var/guix/profiles/per-user/alice/guix-profile-5-link -> /gnu/store/jy2...-profile \end{verbatim} Par conséquent, l'historique est en quelque sorte conservé et Guix donne la possibilité de changer vers quoi les liens pointent. Le profil lui-même est donc immutable. \thisslide{profil2} \begin{frame}[label=profil2, fragile]{Exemples de fonctionnalités des \emph{profils}} \begin{alertblock}{} \begin{itemize} \item Historique des paquets installés / supprimés (\verb+--list-generations+) \item Retour en arrière (\verb+--roll-back+ or \verb+--switch-generations+) \end{itemize} \end{alertblock} \begin{center} (\texttt{demo/generations}) \end{center} \begin{alertblock}{} \begin{itemize} \item Profils indépendants \item Contrôle fin des variables d'environnement (\verb+--search-paths+) \item Composition \end{itemize} \end{alertblock} \begin{center} (\texttt{demo/multi-profiles}) \end{center} \end{frame} Une première fonctionnalité est la conservation des actions (installation ou suppression) sur un profil. Chaque action complète va créer une \emph{génération} (état) -- c'est en ce sens que Guix est transactionnel. Il est donc possible de revenir en arrière (\texttt{roll-back}) ou de basculer vers une autre génération (\texttt{switch-generation}). Par exemple, \begin{verbatim} $ guix package --list-generations Generation 1 avril 21 2022 20:22:28 + python 3.9.9 out /gnu/store/sz7...-python-3.9.9 Generation 2 avril 21 2022 20:38:30 + python-numpy 1.20.3 out /gnu/store/s89...-python-numpy-1.20.3 + python-ipython 7.27.0 out /gnu/store/rj0...-python-ipython-7.27.0 Generation 3 avril 21 2022 20:41:38 - python-ipython 7.27.0 out /gnu/store/rj0...-python-ipython-7.27.0 Generation 4 avril 21 2022 21:05:14 + python-scipy 1.7.3 out /gnu/store/x3x...-python-scipy-1.7.3 + python-matplotlib 3.5.1 out /gnu/store/inl...-python-matplotlib-3.5.1 Generation 5 avril 21 2022 21:19:34 (current) + tree 2.0.2 out /gnu/store/b9z..-tree-2.0.2 \end{verbatim} où le symbole \texttt{+} représente un ajout de paquet, le symbole \texttt{-} une suppression pour chaque génération et \texttt{guix package -{}-list-installed} fournit la liste complète des paquets de l'état courant. \medskip Il est possible de supprimer une (ou plusieurs) génération avec l'option \texttt{-{}-delete-generations}. Nous renvoyons à la section du manuel sur le \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Invoquer-guix-gc}% {\textsf{ramasse-miette}} qui permet une gestion de ce que contient le dépôt (\emph{store}). \bigskip Pour finir, autant de profils que l'on souhaite peuvent être créés. D'une part, chaque profil est indépendant et d'autre part, ils peuvent être composés. En d'autres termes \begin{verbatim} guix install python --profile=interpreteur guix install python-numpy --profile=bibliotheque eval $(guix package --search-paths=prefix -p interpreteur -p bibliotheque) \end{verbatim} et l'environnement résultant contiendra \texttt{python} et \texttt{python-numpy}. D'autre part, l'ajout des variables d'environnement (\texttt{search-paths}) est contrôlable avec la valeur de l'argument \texttt{prefix}, \texttt{suffix} ou \texttt{exact} ; les variables d'en\-vi\-ron\-nement peuvent être, respectivement, placées avant ou après les valeurs actuelles, ou remplacer les valeurs actuelles. \bigskip Nous recommandons \href{https://guix.gnu.org/en/cookbook/fr/guix-cookbook.fr.html#Gestion-avanc_00e9e-des-paquets}% {\textsf{Les profils en pratique}} du livre de cuisine. \thisslide{profil3} \begin{frame}[label=profil3, fragile]{\emph{Profil}, en résumé} Les paquets sont installés dans un \emph{profil} qui est : $\left. \text{\parbox{0.55\linewidth}{ \begin{itemize} \item un lien symbolique, \item pointant vers un élément du dépôt (\emph{store}), \end{itemize} }} \only<1|article:1>{\right.}\only<2-|article:0>{\right\}} $ \only<2-|article:0>{% \hfill \begin{minipage}{0.3\linewidth} \begin{alertblock}{Dépôt (\emph{store})} \begin{itemize} \item Monté à \texttt{/gnu/store} \item Dédupliqué \end{itemize} \end{alertblock} \end{minipage} } $\left. \text{\parbox{1.0\linewidth}{ \begin{itemize} \item et les éléments ont une structure hiérarchique type FHS (comme \texttt{/usr/}). \end{itemize} }} \right.$ \begin{exampleblock}{} \begin{center} On peut créer autant de profils que l’on souhaite \end{center} \end{exampleblock} \vfill \begin{alertblock}{} \begin{center} \textbf{Toutes les options de \texttt{guix package} s’appliquent à n’importe quel profil} \end{center} \end{alertblock} \vfill \begin{center} \texttt{guix install python python-numpy -{}-profile=outils-python} \end{center} \end{frame} \clearpage \subsection{Gestion déclarative} Il devient vite fastidieux de saisir à l'invite du \emph{shell} la liste des paquets et il apparaît naturel de vouloir sauvegarder cette liste dans un fichier. Par exemple, il n'est pas rare de versionner cette liste. Guix permet ceci, et un peu plus, au travers d'une gestion déclarative. \thisslide{declarative} \begin{frame}[label=declarative, fragile]{Gestion déclarative} \vspace{-0.3cm} \begin{center} déclaratif = fichier de configuration \end{center} \begin{exampleblock}{% Un fichier \texttt{some-python.scm} peut contenir cette déclaration :% } \lstinputlisting[language=Scheme,columns=space-flexible]{example/some-python.scm} \end{exampleblock} \begin{center} \verb+guix package --manifest=some-python.scm+ \end{center} équivalent à \begin{center} \verb+guix install python python-matplotlib python-numpy python-scipy+ \end{center} \end{frame} Le fichier de configuration est usuellement appelé \texttt{manifest}. Il contient la liste des paquets comme saisi à l'invite du \emph{shell}. Cette liste est une spécification du manifeste à instancier dans le profil. \thisslide{declarative2} \begin{frame}[label=declarative2, fragile]{Gestion \emph{déclarative} : remarques} \begin{description} \item[Version ?] Nous le verrons dans la suite \medskip \item[Langage ?] \emph{Domain-Specific Language} (DSL) basé sur \href{https://fr.wikipedia.org/wiki/Scheme}% {Scheme} \href{https://fr.wikipedia.org/wiki/Lisp}% {(«~langage fonctionnel Lisp~»)}% \medskip \begin{itemize} \item \verb+(Oui (quand (= Lisp parenthèses) (baroque)))+ \medskip \item Mais \uline{\textbf{continuum}} : \begin{enumerate} \item configuration (\texttt{manifest}) \item définition des paquets (ou services) \item extension \item le c\oe ur est écrit aussi en Scheme \end{enumerate} \end{itemize} \end{description} \begin{alertblock}{} \begin{center} Guix est \textbf{adaptable} à ses besoins \end{center} \end{alertblock} \vfill \footnotesize{% \href{https://fr.wikipedia.org/wiki/Programmation_déclarative}{Déclaratif} vs \href{https://fr.wikipedia.org/wiki/Programmation_impérative}{Impératif} } \hfill \scriptsize{% (% et non pas % \hfill Donnée inerte vs Programme% ) } \footnotesize{% Programmation déclarative = programmation fonctionnelle ou descriptive (\LaTeX) ou logique (Prolog) } \end{frame} Tout d'abord, il est important de noter que \emph{déclaratif} ne signifie pas donnée inerte, comme l'on pourrait retrouver avec un format comme \hrefsf{https://fr.wikipedia.org/wiki/Comma-separated_values}{CSV} ou \hrefsf{https://fr.wikipedia.org/wiki/YAML}{YAML}. Le terme \hrefsf{https://fr.wikipedia.org/wiki/Programmation_déclarative}{déclaratif} («~on décrit le \emph{quoi}, c'est-à-dire le problème~») s'oppose à \hrefsf{https://fr.wikipedia.org/wiki/Programmation_impérative}{impératif} («~on décrit le \emph{comment}, c'est-à-dire la structure de contrôle correspondant à la solution~»). Avec le \textsf{Tableau \ref{tab:cloc}}, nous espérons illustrer ce \emph{continuum} dans Guix. \begin{table}[!htb] \centering \begin{tabular}{l|rrrr} Language &files &blank &comment &code\\ \hline Scheme &1105 &47761 &63485 &804643\\ ~\texttt{\textasciigrave-{}-~packages} &538 &26787 &37972 &642152\\ ~\texttt{\textasciigrave-{}-~guix} &272 &9699 &13346 &75577\\ ~\texttt{\textasciigrave-{}-~services} &53 &3232 &2764 &26723\\ C++ & 50 &3425 &2198 &10635\\ make & 4 &213 &292 &3087\\ Bourne Shell & 29 &850 &1213 &2891 \end{tabular} \caption{\texttt{cloc -{}-exclude-ext=patch -{}-exclude-dir=po .}} \label{tab:cloc} \end{table} Les paquets, les services et Guix lui-même sont écrits dans le même langage \hrefsf{https://fr.wikipedia.org/wiki/Scheme}{Scheme} (pour être précis \hrefsf{https://www.gnu.org/software/guile/}{GNU Guile}). Ce langage est dérivé du langage fonctionnel Lisp et il facilite la définition de langages dédiés (DSL, \emph{domain-specific language}). \thisslide{trans-declarative} \begin{frame}[label=trans-declarative, fragile]{Gestion déclarative : exemple de transformation \small{% (\href{https://fr.wikipedia.org/wiki/Machine_de_Rube_Goldberg}% {machine de \smiley{Goldberg} \tiny{(lien)}})}} % \ddot\smile \vspace{-0.3cm} \begin{exampleblock}{} \lstinputlisting[language=Scheme,columns=space-flexible]{example/some-python-bis.scm} \end{exampleblock} Guix DSL, \somevariable{\emph{variables}}, \someguile{Scheme} et \somestring{chaîne de caractères}. \end{frame} Par exemple, nous illustrons la capacité de manipuler \emph{programmatiquement} les paquets. Avec le mots-clé \texttt{append}, deux listes sont concaténées. Le mot-clé \texttt{map} applique une fonction aux éléments d’une liste et retourne une liste. Le mot-clé \texttt{lambda} définit une fonction (anonyme). \medskip Ainsi, il est possible de déclarer des transformations à appliquer aux paquets. \clearpage \paragraph{Transformation de paquets.} Les \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Options-de-transformation-de-paquets}% {\textsf{transformations de paquets}} sont des options qui rendent possible la définition de variantes de paquets -- par exemple, des paquets construit en utilisant une \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#La-cha_00eene-d_0027outils-GCC}% {\textsf{chaîne d’outils}} différente que celle par défaut. \thisslide{transformation} \begin{frame}[label=transformation, fragile]{Transformations de paquet : survol} \begin{exampleblock}{} \begin{center} Comment utiliser GCC@7 pour compiler le paquet \texttt{python} ? \end{center} \end{exampleblock} \begin{center} Un paquet = recette pour configurer, construire, installer un logiciel \medskip (\texttt{./configure \&\& make \&\& make install}) \end{center} La recette définit : \begin{itemize} \item un \blue{code source} et potentiellement des modifications \emph{ad-hoc} (\verb+patch+) \item des \magenta{outils de construction} (compilateurs, moteur de production etc., p. ex. \verb+gcc+, \verb+cmake+) \item des \violet{dépendances} \end{itemize} \begin{alertblock}{} \begin{center} Une transformation permet de les réécrire \end{center} \end{alertblock} \end{frame} \thisslide{cli-trans} \begin{frame}[label=cli-trans, fragile]{Transformations : ligne de commande} \begin{exampleblock}{} \begin{center} \verb+guix package --help-transformations+ \end{center} \end{exampleblock} \begin{Verbatim}[commandchars=\\\{\}] \blue{--with-source use SOURCE when building the corresponding package} \blue{--with-branch build PACKAGE from the latest commit of BRANCH} \blue{--with-commit build PACKAGE from COMMIT} \blue{--with-git--url build PACKAGE from the repository at URL} \blue{--with-patch add FILE to the list of patches of PACKAGE} \blue{--with-latest use the latest upstream release of PACKAGE} \magenta{--with-c-toolchain build PACKAGE and its dependents with TOOLCHAIN} \magenta{--with-debug-info build PACKAGE and preserve its debug info} \magenta{--without-tests build PACKAGE without running its tests} \violet{--with-input replace dependency PACKAGE by REPLACEMENT} \violet{--with-graft graft REPLACEMENT on packages that refer to PACKAGE} \end{Verbatim} \end{frame} Les transformations sont appliquées récursivement, donc elles s’appliquent aussi aux dépendances de dépendances. Par exemple, la ligne de commande pour recompiler le paquet \texttt{python} et toutes ses dépendances avec le compilateur GCC à la version 7 à la place de la version 10 (par défaut) est \begin{verbatim} guix install python --with-c-toolchain=python=gcc-toolchain@7 \end{verbatim} et ceci se traduit naturellement dans un fichier de configuration \emph{manifest}. \thisslide{trans-manif} \begin{frame}[label=trans-manif, fragile]{Transformations via fichier manifeste} \vspace{-0.3cm} \begin{exampleblock}{} \lstinputlisting[language=Scheme,columns=space-flexible]{example/some-python-with-gcc7.scm} \end{exampleblock} \end{frame} Ici, nous utilisons le module définissant les transformations et nous définissions la transformation \texttt{transform} via \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#index-options_002d_003etransformation}{la procédure \texttt{options->transformation}} ; autrement dit \texttt{transform} est une fonction prenant en argument un paquet et retournant un nouveau paquet dans lequel la chaîne de compilation a été remplacée. Pour finir, \texttt{compose} permet de composer deux fonctions et nous aurions pu écrire à la place \begin{center} \texttt{(lambda (pkg) (transform (specification->package pkg)))} \end{center} Le manuel fournit un \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Index-de-programmation}% {\textsf{index de programmation}} qui aide à se familiariser avec le langage dédié. \clearpage \subsection{Environnement isolé à la volée} À ce stade, nous sommes capables de créer des profils. Par exemple, la commande \texttt{guix package -{}-list-profiles} liste tous les profils de l'utilisateur. Tant qu'il y a un élément qui pointe dans un profil, le \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Invoquer-guix-gc}{ramasse-miettes} ne peut pas \emph{glaner} les paquets non utilisés. Dans certains cas, nous voulons temporairement tester un outil sans se préoccuper de la gestion du profil. C'est la fonctionnalité de \texttt{guix shell}. \begin{frame}[fragile]{Profils temporaires} \begin{center} Exemple : ajouter temporairement \texttt{IPython} \end{center} \bigskip \begin{center} (\texttt{demo/shell-ipython}) \end{center} \end{frame} \thisslide{shell} \begin{frame}[label=shell,fragile]{Étendre temporairement un \emph{profil}} \begin{exampleblock}{} \begin{verbatim} guix shell -m manifest.scm guix shell -m manifest.scm python-ipython -- ipython3 \end{verbatim} \end{exampleblock} \begin{alertblock}{} \begin{tabular}{lcl} \red{$\blacktriangleright$} \verb+--pure+ &:& réinitialise des variables d’environnement existantes \\ \red{$\blacktriangleright$} \verb+--container+ &:& lance un conteneur isolé \\ \red{$\blacktriangleright$} \verb+--development+ &:& inclus les dépendances du paquet \end{tabular} \end{alertblock} \begin{exampleblock}{} \begin{verbatim} guix shell -m some-python.scm python-ipython # 1. guix shell -m some-python.scm python-ipython --pure # 2. guix shell -m some-python.scm python-ipython --container # 3. \end{verbatim} \end{exampleblock} \begin{center} Bonus : \verb+guix shell emacs git git:send-email --development guix+ \end{center} \end{frame} La commande \texttt{guix shell} permet de créer ou étendre temporairement un profil. Par exemple, dans la section précédente, le programme \texttt{cloc} est utilisé pour compter les lignes de code. La commande \texttt{guix shell cloc} a permis de lancer un \emph{shell} temporaire contenant le programme. \medskip Les options \texttt{pure} et \texttt{container} permettent de vérifier que toutes les dépendances de l'application sur laquelle on travaille sont bien capturées. En particulier, l'option \texttt{container} permet de lancer un \emph{shell} temporaire totalement isolé. \bigskip \paragraph{Nota bene~:} La commande \texttt{guix shell} a été introduite récemment pour remplacer \texttt{guix environment}. Cette dernière est encore conservée pour assurer une rétro-compatibilité. Toutefois, nous recommandons d'utiliser \texttt{guix shell}, en particulier si vous n'avez jamais utilisé Guix auparavant. \begin{frame}[plain,fragile,noframenumbering]{} À ce stade, il semble naturel de vouloir \uline{partager ou construire des conteneurs isolés}. \vfill{} \begin{center} \textbf{Comment créer des images ?} \end{center} \vfill{} \begin{flushright} (Exemple : Alice sans privilège particulier) \end{flushright} \end{frame} \clearpage \section{Création d'images} Dans la section précédente, nous avons vu comment créer des environnements «~isolés~». Il semble naturel de vouloir les partager ou les distribuer. \subsection{Création d’un \emph{pack}} La technologie usuelle pour transporter du matériel est celle d’un \textbf{conteneur}. Cependant, il ne faut \uline{\textbf{pas perdre de vue}} la \uline{\textbf{transparence}} et la \textbf{\uline{re\-pro\-duc\-ti\-bi\-li\-té}}. \thisslide{conteneur} \begin{frame}[label=conteneur,fragile]{Comment capturer un environnement ? Conteneur} \begin{center} Conteneur = \smiley{smoothie} \end{center} \begin{itemize} \item Comment est construit le conteneur ? Dockerfile ? \item Comment sont construits les binaires inclus dans le conteneur ? \end{itemize} \begin{exampleblock}{} \begin{verbatim} FROM amd64/debian:stretch RUN apt-get update && apt-get install git make curl gcc g++ ... RUN curl -L -O https://... && ... && make -j 4 && ... RUN git clone https://... && ... && make ... /usr/local/lib/libopenblas.a ... \end{verbatim} \begin{center} \href{https://gitlab.onelab.info/gmsh/gmsh/-/blob/c7544ec812982dbe15e105059983f1b0c3896536/utils/docker/Dockerfile.debian.stretch.64bit}% {source (lien) : Gmsh~}% \href{http://gmsh.info/}% {A three-dimensional finite element mesh generator (lien)} \end{center} \end{exampleblock} \begin{alertblock}{} \begin{center} Avec un Dockerfile au temps t, comment regénérer l'image au temps t’ ? \end{center} \end{alertblock} \end{frame} \bigskip % workaround Un conteneur est comme un «~smoothie~» dans le sens où nous pouvons immédiatement dire si nous l’aimons ou non, mais il est difficile, si ce n’est impossible, de donner précisément la liste exhaustive des ingrédients. Par conséquent, comment, à deux moments différents, reproduire exactement le même conteneur sur deux machines différentes ? \bigskip \thisslide{pack} \begin{frame}[label=pack, fragile]{Qu’est-ce qu’un \emph{pack} ?} \begin{center} \emph{pack} = collection de paquets dans un format d’archive \end{center} Quel est le but d’un \emph{pack} ? \begin{itemize} \item Alice distribue «~tout~» à Carole, \item Carole n’a pas installé Guix mais aura l’exact même environnement. \end{itemize} \begin{exampleblock}{Qu’est-ce qu’un format d’archive ?} \begin{itemize} \item \texttt{tar} (\emph{tarballs}) \item Docker \item Singularity \item paquet binaire Debian \texttt{.deb} \end{itemize} \end{exampleblock} \end{frame} Un \emph{pack} est un \emph{lot de logiciels} enregistrés sous leur forme binaire dans un format spécifique. Le format d’archivage \texttt{tar} est probablement le plus connu, historiquement. Aujourd’hui, \hrefsf{https://www.docker.com/}{Docker} ou \hrefsf{https://sylabs.io/guides/3.4/user-guide/quick_start.html}{Singularity} sont très largement utilisés comme format de conteneur. \thisslide{tout} \begin{frame}[label=tout, fragile]{Qu'est-ce que «~tout~» ?} \begin{center} Carole a besoin de la \emph{clôture transitive} (= toutes les dépendances) \end{center} \begin{exampleblock}{} \begin{verbatim} $ guix size python-numpy --sort=closure store item total self python-numpy-1.20.3 301.5 23.6 7.8% ... python-3.9.9 155.3 63.7 21.1% openblas-0.3.18 152.8 40.0 13.3% ... total: 301.5 MiB \end{verbatim} \end{exampleblock} \begin{alertblock}{} \begin{center} \texttt{guix pack} permet de créer cette archive contenant «~tout~» \end{center} \end{alertblock} \end{frame} \clearpage % workaround Le but d’un conteneur est de capturer l’intégralité de la pile logicielle pour fonctionner indépendamment du système hôte. Guix fournit une commande (\texttt{guix size}) pour examiner la taille des éléments à inclure. Par exemple, le paquet \texttt{python-numpy} ne représente que moins de 8\% des 301,5Mo totaux nécessaires à son bon fonctionnement. Nous voyons que le paquet \texttt{python-numpy} a aussi besoin du paquet \texttt{python} ainsi que de la bibliothèque d’algèbre linéaire \texttt{openblas}, entre autres. \thisslide{pack2} \begin{frame}[label=pack2, fragile]{Création d’un \emph{pack} pour le distribuer} \begin{itemize} \item Alice construit un \emph{pack} au format Docker \begin{exampleblock}{} \begin{center} \verb+guix pack --format=docker -m manifest.scm+ \end{center} \end{exampleblock} puis distribue ce conteneur Docker (via un \emph{registry} ou autre). \item Carole n'utilise pas \small{(encore?)}\normalsize{} Guix \begin{exampleblock}{} \begin{verbatim} $ docker run -ti projet-alice python3 Python 3.9.9 (main, Jan 1 1970, 00:00:01) [GCC 10.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> \end{verbatim} \end{exampleblock} et utilise l'exact même environnement computationnel qu'Alice. \end{itemize} \end{frame} \paragraph{Prenons un exemple :} Construire et déployer cette présentation. Les deux commandes suivantes sur une machine ayant Guix permettent de récupérer les sources (\LaTeX) puis de construire la présentation au format PDF. \begin{verbatim} guix shell git nss-certs \ -- git clone https://gitlab.com/zimoun/jres22-tuto-guix guix shell -m manifest.scm \ -- rubber --pdf presentation.tex \end{verbatim} Alice souhaite pouvoir générer cette présentation sur une infrastructure ne possédant pas Guix. À la place, l’infrastructure utilise des conteneurs Docker. Par conséquent, Alice empaquette au format Docker \begin{verbatim} guix pack \ --format=docker \ -C none \ -S /bin=bin -S /lib=lib -S /share=share -S /etc=etc \ -m manifest.scm \ --save-provenance \end{verbatim} qui produit l’élément dans le dépôt (\emph{store}) \texttt{/gnu/store/n92...-rubber-...-docker-pack.tar}. Nous renvoyons à la \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Invoquer-guix-pack}% {\textsf{section du manuel}} pour une description exhaustive des options de la commande \texttt{guix pack}. Notons que \texttt{-{}-symlink / -S} ajoute les liens symboliques spécifiés dans le \emph{pack} ; par exemple, \texttt{-S /bin=bin} crée un lien symbolique \texttt{/bin} qui pointe vers le sous-répertoire \texttt{bin} du profil. \bigskip Ce \emph{pack} une fois créé peut être chargé en local comme image Docker pour, par exemple, ajouter une étiquette (\emph{tag}) et pousser cette image sur un dépôt (\emph{registry}) \begin{verbatim} $ docker load < $(guix pack ...) $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE rubber-texlive-base-texlive-fonts-ec latest 6f08ec6e1f4c 52 years ago 1.03GB $ docker tag 6f08ec6e1f4c zimoun/jres $ docker push zimoun/jres \end{verbatim} où les points \dots~ sont par exemple les options précédentes. \medskip Il faut noter la date qui correspond au 1\ier{} janvier 1970, c.-à-d. qui donne les conditions pour reproduire l'image bit-à-bit. D'autre part, il faut aussi noter que Guix vérifie si l'élément est déjà présent dans le dépôt (\emph{store}). \bigskip Maintenant, il suffit pour Carole de télécharger depuis le dépôt (\emph{registry}) le conteneur Docker. Par exemple, ce conteneur pourrait être utilisé pour de l'intégration continue à travers GitLab~CI (voir l'% \hrefsf{https://gitlab.com/zimoun/jres22-tuto-guix/-/blob/main/.gitlab-ci.yml}% {exemple dédié} pour construire cette présentation). \thisslide{pack3} \begin{frame}[label=pack3, fragile]{Au final, \texttt{guix pack}, c’est\dots} \begin{center} \emph{Agnostique} sur le format du «~conteneur~» \end{center} \begin{tabular}{cc} \begin{minipage}{0.4\linewidth} \begin{exampleblock}{} \begin{itemize} \item \texttt{tar} (\emph{tarballs}) \item Docker \item Singularity \item paquet binaire Debian \texttt{.deb} \end{itemize} \end{exampleblock} \end{minipage} & \begin{minipage}{0.5\linewidth} \begin{alertblock}{} \begin{itemize} \item archives repositionnables \item sans \texttt{Dockerfile} \item via \texttt{squashfs} \item sans \texttt{debian/rule} (expérimental) \end{itemize} \end{alertblock} \end{minipage} \end{tabular} \bigskip \begin{center} \textbf{Adaptable aux cas d’usage} \end{center} \end{frame} \paragraph{Pour aller plus loin :} Peut-on extraire le manifeste Guix d’un \emph{pack} au format Docker ? \begin{center} \hrefsf{https://hpc.guix.info/blog/2021/10/when-docker-images-become-fixed-point/}% {Reproductibilité d'un conteneur Docker généré par Guix} \end{center} \bigskip Internet étant fait de serveurs qui vont et viennent, les URL risquent de ne plus pointer vers le contenu. Par conséquent, nous donnons ici des liens vers des archives (meilleure pérennité) pour le contenu de ce tutoriel : \begin{itemize} \item \hrefsf{https://archive.softwareheritage.org/browse/origin/directory/?origin_url=https://gitlab.com/zimoun/jres22-tuto-guix}% {Source} sur \hrefsf{https://www.softwareheritage.org/}{Software Heritage} \item \hrefsf{https://web.archive.org/web/*/https://zimoun.gitlab.io/jres22-tuto-guix}% {Déploiement} sur \hrefsf{https://web.archive.org/}{Web Archive} \end{itemize} en plus, évidemment, des JRES. \clearpage \subsection{Création d'une machine virtuelle} Dans la section précédente, nous avons vu comme créer des \emph{pack} contenant un déploiement de paquets. Cependant, nous souhaiterions aussi pouvoir déployer des services. \thisslide{image} \begin{frame}[label=image, fragile]{Création d’une image avec \texttt{guix system} : un monde de services} \begin{alertblock}{} \begin{center} \texttt{guix system} permet une \uline{\textbf{configuration déclarative} d'un \emph{système}} \end{center} \end{alertblock} \begin{itemize} \item \texttt{guix system search} pour trouver les services disponibles \item \texttt{guix system image} pour construire une image de type : \begin{itemize} \item qcow2 \item docker \item iso9660, uncompressed-iso9660, efi-raw, raw-with-offset \item rock64-raw, pinebook-pro-raw, pine64-raw, novena-raw \item hurd-raw, hurd-qcow2 \end{itemize} \item \begin{minipage}{1.0\linewidth} \begin{exampleblock}{} \texttt{guix system vm} pour construire une machine virtuelle (VM) \begin{center} (la VM partage son dépôt avec le système hôte) \end{center} \end{exampleblock} \end{minipage} \end{itemize} \end{frame} Sur le même principe que la commande \texttt{guix package}, il est possible de chercher les services disponibles avec \texttt{guix system search}. De plus, la commande \texttt{guix system} permet de générer une image suivant différents formats. Par exemple, ceci permet d’obtenir une image \emph{bootable} qui donne une distribution complète – appelée Guix System. \bigskip La commande qui nous intéresse particulièrement est \texttt{guix system vm}. Elle permet de générer une machine virtuelle (VM) qui partage son dépôt avec son hôte (n’importe quelle distribution Linux avec Guix installé). L’avantage principal est une isolation complète qui, par exemple, permet de fournir des services. Le déploiement de services avec Guix mériterait un tutoriel en soi, nous donnons ici un point d’entrée. \thisslide{image2} \begin{frame}[label=image2, fragile]{Configuration déclarative d'une machine virtuelle} \vspace{-0.3cm} \begin{exampleblock}{} \lstinputlisting[language=Scheme,columns=space-flexible]{example/config-vm-1.scm} \end{exampleblock} \end{frame} Comme pour la gestion de paquets, la configuration de la machine virtuelle se fait dans un langage déclaratif. Le point d’entrée est le mot-clé \texttt{operating-system} (\href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#r_00e9f_00e9rence-de-operating_002dsystem}% {\textsf{décrit dans le manuel}}) qui spécifie les options. En particulier, un champ liste les paquets à provisionner et un autre champ liste les services avec éventuellement leurs caractéristiques. \thisslide{image3} \begin{frame}[label=image3, fragile]{Configuration déclarative d'une machine virtuelle (2)} \vspace{-0.3cm} \begin{exampleblock}{} \lstinputlisting[language=Scheme,columns=space-flexible]{example/config-vm-2.scm} \end{exampleblock} \end{frame} \thisslide{image4} \begin{frame}[label=image4, fragile]{Machines virtuelles avec Guix} % \begin{center} % (\texttt{demo/vm}) % \end{center} \begin{alertblock}{} \begin{itemize} \item Gestion déclarative \item Réutilisation via des patrons (\emph{template}) \end{itemize} \end{alertblock} \end{frame} Par exemple, la commande \begin{center} \texttt{guix system vm src/example/vm-image.scm} \end{center} produit le script \texttt{/gnu/store/0n5...-run-vm.sh} qui lance QEMU avec les éléments du dépôt (\emph{store}) adéquats, c.-à-d. \begin{verbatim} $ /gnu/store/0n5...-run-vm.sh -nic user \end{verbatim} démarre la machine virtuelle avec, ici, le réseau. Ces machines virtuelles peuvent être administrées avec le paquet \texttt{virt-manager}. \begin{frame}[plain,fragile,noframenumbering]{} Très bien tout cela, mais en quoi est-ce \uline{reproductible} ? \vfill{} \begin{center} \textbf{Parlons de versions !} \end{center} \vfill{} \begin{flushright} (Exemple : Carole collabore avec Alice) \end{flushright} \end{frame} \clearpage \section{Une histoire de versions} Le but de cette section est double, d'une part montrer par l'exemple la capacité de Guix de s'affranchir de l'état externe et d'autre part en quoi Guix est dit \emph{fonctionnel}. \subsection*{Version ? Graphe ?} Une question récurrente des nouveaux utilisateurs de Guix est~: comment est-ce que je spécifie la version de l’outil à utiliser ? Une réponse à cette question appelle une autre question~: qu’est-ce que l’on appelle version ? Est-ce la version du code source ? Est-ce la version du binaire ? Mais alors, pour le le même code source transformé par deux chaînes de compilation différentes, appelle-t-on les deux binaires résultants la même \emph{version} ? \thisslide{version} \begin{frame}[label=version, fragile]{Quelle est ma version de Guix ?} % \vspace{-0.25cm} \begin{exampleblock}{} \begin{verbatim} $ guix describe Generation 76 Apr 25 2022 12:44:37 (current) guix eb34ff1 repository URL: https://git.savannah.gnu.org/git/guix.git branch: master commit: eb34ff16cc9038880e87e1a58a93331fca37ad92 $ guix --version guix (GNU Guix) eb34ff16cc9038880e87e1a58a93331fca37ad92 \end{verbatim} \end{exampleblock} % \vspace{-0.175cm} \begin{alertblock}{} \begin{center} Un état fixe toute la collection des paquets et de Guix lui-même \end{center} \end{alertblock} (Un état peut contenir plusieurs canaux (\emph{channel} = dépôt Git),\\ \hfill avec des URL, branches ou commits divers et variés) % \vspace{-0.175cm} % \begin{verbatim} % $ guix package --list-available=^python | head -2 % python 3.9.9 out,tk,idle gnu/packages/python.scm:431:2 % python-absl-py 0.6.1 out gnu/packages/python-xyz.scm:23415:2 % \end{verbatim} \end{frame} Guix capture un état : la liste de tous les paquets et les commandes Guix elles-mêmes. Les commandes Guix sont données par le canal principal et ce canal fournit un ensemble de paquets (et de services). Il est tout à fait possible d’étendre la collection de paquets en fournissant d’autres canaux pour avoir des paquets variants. Par exemple, l’initiative \hrefsf{https://hpc.guix.info/about/}{GuixHPC} (qui correspond à Guix dans un contexte scientifique) essaie de maintenir une \hrefsf{liste de canaux}. \medskip Pour spécifier un canal supplémentaire, l’utilisateur (sans droit particulier) doit modifier le fichier \texttt{\$HOME/.config/guix/channels.scm}, p. ex. \begin{verbatim} (cons (channel (name 'guix-hpc) (url "https://gitlab.inria.fr/guix-hpc/guix-hpc")) %default-channels) \end{verbatim} Si la canal fournit aussi des substituts binaires ce qui évite de consommer des ressources, alors il faut \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Autoriser-un-serveur-de-substituts}% {autoriser le serveur de substituts}. Dans le cas de ce canal, la clé publique est \begin{verbatim} (public-key (ecc (curve Ed25519) (q #89FBA276A976A8DE2A69774771A92C8C879E0F24614AAAAE23119608707B3F06#))) \end{verbatim} L’ajout de serveurs de substituts nécessite cependant des droits d’administration privilégiés pour des raisons de sécurité. \thisslide{dag} \begin{frame}[label=dag, fragile]{État = Graphe Acyclique Dirigé (\emph{DAG})} \vspace{-0.5cm} \begin{center} \texttt{guix graph -{}-max-depth=6 python | dot -Tpng > graph-python.png} \end{center} \vfill{} \includegraphics[width=\textwidth]{static/graph-python.png} \vfill{} Graphe complet : Python = 137 n\oe uds, Numpy = 189, Matplotlib = 915, Scipy = 1439 n\oe uds % graph python-scipy -t bag | grep label | cut -f2 -d'[' | sort | uniq | wc -l \end{frame} Guix capture un état, c.-à-d. que Guix capture le graphe complet pour produire le binaire résultant. Il capture les relations de dépendances, les recettes de construction et la machinerie de Guix elle-même pour traiter tout cela. \medskip Il n’y a pas de résolveur de dépendances qui cherche à trouver la meilleure solution à un problème sous-contraintes. Guix lui construit un graphe à partir de la collection de paquets qu’il connaît dans son état courant. Ensuite, ce graphe peut être \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Options-de-transformation-de-paquets}% {\textsf{transformé}} pour obtenir les variants. \medskip Ainsi la variabilité est contrôlée aussi finement que possible. Dans la plupart des cas d’usage, le résultat final (la courbe publiée par Alice, l’utilisation de tel ou tel outil par Carole, etc.) ne sera pas impacté. La question se pose à l’inverse quand il y a une différence dans ce résultat. D’où vient l’erreur ? En d’autres termes, ce contrôle fin est d’intérêt quand on cherche à redéployer une pile logicielle pour reproduire ou dupliquer. \subsection*{Définir un paquet} \thisslide{def-pkg} \begin{frame}[label=def-pkg, fragile]{Définition d’un paquet (n\oe ud du graphe)} \vspace{-0.3cm} \begin{exampleblock}{} \lstinputlisting[language=Scheme,columns=space-flexible]{example/mock-define-python.scm} \end{exampleblock} \vspace{-0.2cm} \begin{alertblock}{} \begin{itemize} \item Chaque \texttt{inputs} est une définition similaire \hfill (récursion $\rightarrow$ graphe) \item Il n’y a pas de cycle \hfill (\texttt{bzip2} ou ses \texttt{inputs} ne peuvent pas utiliser \texttt{python}) \end{itemize} \end{alertblock} \vspace{-0.25cm} \begin{center} \small{% (Quel commencement du graphe ? Problème du \emph{bootstrap} dont nous ne parlerons pas ici) }\normalsize \end{center} \end{frame} Un paquet correspond à un n\oe ud du graphe. D’une part, il contient des \emph{meta} informations comme le nom, la version du code source, un synopsis et description, la licence. D’autre part, il contient la recette pour être construit par Guix~: où trouver les sources, quelle chaîne de compilation par défaut, quelles dépendances, et quelles modifications spécifiques (\texttt{arguments}) pour indiquer les options de compilation ou les changements mineurs dans la chaîne de compilation. \medskip Pour faciliter la création de nouveaux paquets, \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Invoquer-guix-import}% {\textsf{la commande \texttt{guix import}}} permet de générer une recette Guix à partir des dépôts dédiés à un écosystème (PyPI, CRAN, Bioconductor, etc.). Il faut noter que l’\emph{utilisabilité} de la recette résultante est très variable car elle dépend fortement de la qualité ou disponibilité des métadonnées du dépôt source. \medskip De notre point de vue, empaqueter pour Guix est généralement plus facile que pour les autres gestionnaires. Cependant, la construction totalement isolée de Guix oblige à une certaine gymnastique. Au final, nous tenons à souligner que le travail d’empaquetage quelque soit le gestionnaire sous-jacent est un tâche laborieuse. \clearpage \subsection*{Changer d'état} La \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Invoquer-guix-pull}% {\textsf{commande \texttt{guix pull}}} permet de changer d’état en mettant à jour la collection de paquets des différents canaux et Guix lui-même. Par exemple, la commande \texttt{guix pull --news} permet de savoir quelles sont les différences entre notre état précédent et notre état courant. \medskip La commande \texttt{guix upgrade} permet de mettre à jour les paquets d’un profil. Cette commande respecte les transformations, s’il y a, dans la mise à jour. \medskip En ayant la capacité d’utiliser d’autres canaux, de créer des profils et de mettre à jour la collection des paquets, un utilisateur sans privilège devient autonome dans la gestion de ses outils. Bien entendu, sur une machine mutualisée, l’administrateur peut créer des profils exposés aux utilisateurs pour leurs fournir des suites d’outils par défaut. \thisslide{pull} \begin{frame}[label=pull, fragile]{Concrètement, en pratique ?} \begin{alertblock}{} \begin{center} une version = un graphe \end{center} \end{alertblock} \begin{center} Mise à jour de Guix \texttt{guix pull} (création d'une nouvelle \emph{génération} interne) \end{center} \begin{itemize} \item Il est possible de \uline{spécifier un \emph{état}} : \begin{exampleblock}{} \begin{center} \begin{tabular}{rl} \blue{\texttt{alice@laptop\$}} & \texttt{guix describe -{}-format=channels > alice-laptop.scm} \\ \violet{\texttt{carole@desktop\$}} & \texttt{guix pull -{}-channels=alice-laptop.scm} \end{tabular} \end{center} \end{exampleblock} \item Il est possible de se placer \uline{\textbf{temporairement} dans un état spécifique}\\ \hfill pour exécuter une commande (comme créer un profil) \begin{exampleblock}{} \begin{center} \texttt{guix time-machine -{}-commit=c61df1792c -{}- install python -p python/autres} \end{center} \end{exampleblock} \end{itemize} \end{frame} Comme il est possible de connaître l’historique d’installation et de suppression des paquets d’un profil avec la commande \texttt{guix package -l}, la commande \texttt{guix pull -{}-list-generations} fournit l’historique des états de l’utilisateur. Notons que les commandes Guix elle-mêmes vivent dans un profil particulier (nommé \texttt{\$HOME/.config/guix/current}). \medskip Ainsi, sur une machine multi-utilisateurs, cette liste des états peut différer entre les utilisateurs. La commande \texttt{guix describe} permet de capturer l’état courant pour soit le \emph{versionner} avec un projet, soit le partager. Par exemple, Alice sauvegarde son état courant dans le fichier \texttt{alice-laptop.scm} et transmet à Carole ce fichier. Ensuite, Carole sur une autre machine peut se placer dans l’exact même état qu’Alice. \medskip Lorsque l’on travaille sur plusieurs projets, il peut devenir fastidieux de changer d’état \emph{globalement} et il est souhaitable d’avoir la capacité de se placer temporairement dans un état donné pour réaliser une opération (installation, création de profil, etc.). Ceci est possible avec la \href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Invoquer-guix-time_002dmachine}% {\textsf{commande} \texttt{guix time-machine}}. \thisslide{time-machine} \begin{frame}[label=time-machine, fragile]{Reproductibilité en arrière, en avant : \texttt{guix time-machine}} \vspace{-1cm} \begin{center} \begin{tikzpicture} % draw horizontal line \draw[thick, -Triangle] (0,0) -- (12,0) node[font=\scriptsize,below left=3pt and -8pt]{time}; \node[font=\scriptsize, text height=1.75ex, text depth=.5ex] at (0,-.3) {2018}; % draw vertical lines \foreach \x in {1,...,11} \draw (\x cm,3pt) -- (\x cm,-3pt); \foreach \x/\descr in {3/Carole,6/Alice,8/Bob} \node[font=\scriptsize, text height=1.75ex, text depth=.5ex] at (\x,-.3) {$\descr$}; \node[font=\scriptsize, text height=1.75ex, text depth=.5ex] (Carole) at (3,+.3) {d7e57e}; \node[font=\scriptsize, text height=1.75ex, text depth=.5ex] (Alice) at (6,+.3) {eb34ff1}; \node[font=\scriptsize, text height=1.75ex, text depth=.5ex] (Dan) at (8,+.3) {3682bd}; \draw[->] (Carole.north) to [out=50,in=150] (Alice.west); \draw[->] (Dan.north) to [out=100,in=50] (Alice.east); \draw[lightgray!0!red, line width=4pt] (2,-.6) -- +(8,0); \foreach \x/\percol in {1/75,9/75} \draw[lightgray!\percol!red, line width=4pt] (\x,-.6) -- +(1,0); \node[font=\scriptsize, text height=1.75ex, text depth=.5ex] at (11,-.3) {$Dan$}; \node[font=\scriptsize, text height=1.75ex, text depth=.5ex] (Dan) at (11,+.3) {c99c3d}; \draw[dashed,->] (Dan.north) to [out=40,in=90] (Alice.north); \end{tikzpicture} \end{center} \begin{exampleblock}{} Pour être \uline{reproductible dans le temps}, il faut : \begin{itemize} \item Une préservation de \textbf{tous} les codes source~% \small{% (\href{https://ngyro.com/pog-reports/latest/}% {$\approx 75\%$ archivés \tiny{(lien)}\small} dans~% \href{https://www.softwareheritage.org/}% {Software Heritage \tiny{(lien)}\small})% }\normalsize \item Une \emph{backward} compatibilité du noyau Linux \item Une compatibilité du \emph{hardware} (p. ex. CPU, disque dur \tiny{(NVMe)}\normalsize, etc.) \end{itemize} \end{exampleblock} \begin{alertblock}{} \begin{center} Quelle est la taille de la fenêtre temporelle avec les 3 conditions satisfaites ? \end{center} \end{alertblock} \begin{center} \scriptsize{(À ma connaissance, le projet Guix réalise une expérimentation grandeur nature et quasi-unique depuis sa v1.0 en 2019)} \end{center} \end{frame} Carole et Bob, les collaborateurs d’Alice, qui aussi travaillent sur d’autres projets avec d’autres collaborateurs peuvent convenir d’un état et s’y placer. Ils auront le même environnement logiciel. Grâce aux mécanismes d’\href{https://guix.gnu.org/manual/devel/fr/guix.fr.html#Inf_00e9rieurs}% {inférieurs}, il est possible de tendre à une reproductibilité dans le temps. \medskip Pour assurer cette reproductibilité, le seul point sur lequel nous pouvons directement agir est la sauvegarde de tous les codes sources. Le projet Guix participe à la mise en place de ponts avec des systèmes d’archivage comme Software Heritage. Chaque état correspond à une collection de paquets et donc à des codes sources et des recettes Guix de construction. Le chantier est en cours pour préserver «~quoi~» et «~comment~» construire. \clearpage \section{Au final\dots} \subsection*{Au final\dots} \thisslide{continuum2} \begin{frame}[label=continuum2, fragile]{\dots Guix est un \emph{continuum}% \hfill \small{(sur n'importe quelle distribution Linux)}} \vspace{-0.5cm} \begin{center} \begin{tabular}{llr} un \uline{\textbf{gestionnaire de paquets}} déclaratif & \texttt{guix package} & (\texttt{-m} \emph{manifest}) \\ \ \ temporairement étendu à la volée & \texttt{guix shell} & (\texttt{-{}-container}) \\ \ \ \ \ maîtrisant exactement l'\emph{état} & \texttt{guix time-machine} & (\texttt{-C} \emph{channels}) \\ \ \ \ \ \ \ qui produit des \uline{\textbf{\emph{packs} distribuables}} & \texttt{guix pack} & (\texttt{-f docker}) \\ \ \ \ \ \ \ \ \ qui génèrent des \textbf{\uline{\emph{machines virtuelles}} isolées} & \texttt{guix sytem vm} \\ \ \ \ \ \ \ \ \ \ \ \ \ \ et aussi une bibliothèque Scheme & \texttt{guix repl} & (\emph{extensions}) \\ $\Big($ la distribution Linux elle-même & \texttt{config.scm} & (Guix System) $\Big)$ \end{tabular} \begin{alertblock}{} \begin{center} \textbf{% Guix permet un contrôle fin du graphe de configuration sous-jacent } \end{center} \end{alertblock} \end{center} \begin{exampleblock}{} \begin{center} \texttt{guix time-machine -C channels.scm -{}-} \emph{commande options} \texttt{une-config.scm} \end{center} \end{exampleblock} \begin{alertblock}{} \begin{center} \texttt{une-config.scm} est \textbf{reproductible} d'une machine à l'autre et dans le temps \end{center} \end{alertblock} \end{frame} \thisslide{scenarii2} \begin{frame}[label=scenarii2,fragile]{Scenarii} \vspace{-0.2cm} \begin{itemize} \item Alice utilise \texttt{python@3.9} et \texttt{numpy@1.20.3} \vspace{-0.1cm} \begin{exampleblock}{} \begin{verbatim} $ guix install python python-numpy \end{verbatim} \end{exampleblock} \item Carole \textbf{collabore} avec Alice\ldots{} mais utilise d'autres outils pour un autre projet \vspace{-0.1cm} \begin{exampleblock}{} \begin{verbatim} $ guix time-machine -C version-alice.scm \ -- install -m outils-alice.scm -p projet/alice \end{verbatim} \end{exampleblock} \item Charlie \textbf{mets à jour} son système et \textbf{tout est cassé} \vspace{-0.1cm} \begin{exampleblock}{} \begin{verbatim} $ guix pull --roll-back \end{verbatim} \end{exampleblock} \item Bob utilise les \textbf{{mêmes} versions} qu'Alice mais n'a \textbf{pas le {même} résultat} \vspace{-0.1cm} \begin{exampleblock}{} \begin{verbatim} error: You found a bug \end{verbatim} \end{exampleblock} \item Dan essaie de \textbf{rejouer plus tard} le scénario d'Alice\dots \vspace{-0.25cm} \begin{flushright} \scriptsize{(voir ligne commande Carole)}\normalsize \hfill{} \dots ça dépend de la date du scénario ;-) \end{flushright} \end{itemize} \end{frame} \clearpage \subsection*{Limitations} En tant que contributeur régulier, j'ai une vision biaisée qui peut-être sur-estime les défauts à traiter et sous-estime toutes les fonctionnalités qui résolvent un large spectre de problèmes. Pour sûr, après plus de deux années d'utilisation intensive de l'ordinateur portable à la machine de calcul en passant pour la station de travail, je ne reviendrai pas à des outils sans un paradigme déclaratif et fonctionnel. \thisslide{limit} \begin{frame}[label=limit,fragile]{On s'habitue vite\dots} \begin{itemize} \item Fonctionne uniquement avec Linux. \item Environnement isolé implique une forte transparence, \begin{flushright} c.-à-d., difficile avec des parties propriétaires. \end{flushright} \item Certaines commandes peuvent apparaître lentes (\texttt{pull}, \texttt{search}, etc.), \begin{flushright} ou retourner des erreurs obscures. \end{flushright} \item Les premiers pas requièrent un peu de patience, \begin{flushright} et d’accepter que ce n’est \uline{pas \emph{comme d’habitude}}. \end{flushright} \end{itemize} \vfill{} \begin{alertblock}{} \begin{center} \textbf{La communauté est très accueillante et toujours disponible pour aider} \end{center} \end{alertblock} \end{frame} \begin{enumerate} \item Le problème est la transparence de la chaîne de \emph{bootstrap} : comment construire à «~partir de rien~». Techniquement, en quelques mots, le nœud du problème est le port de la bibliothèque C \texttt{glibc} pour un autre noyau. Autrement dit, quelle est la taille de la graine binaire que l'on s'autorise comme racine du graphe des dépendances ? \item Il est possible d’utiliser des pilotes spécifiques pour certains matériels \emph{hardware} mais c’est du travail. D’un autre côté, dans un contexte de reproductibilité scientifique, ne doit-on pas chercher au maximum la transparence de toute la chaîne de traitement ? L’autre implication est l’utilisation de logiciels requérant par exemple un jeton de licence – comme le compilateur Fortran d’Intel \texttt{ifort}. L’environnement de construction étant totalement isolé, l’accès au jeton est impossible lors de la compilation. \item Tout est régulièrement amélioré, dans la mesure du possible avec les moyens disponibles. \item On y vient, on n’en repart pas. \end{enumerate} \subsection*{Ressources} \thisslide{prod} \begin{frame}[label=prod]{En production} \vspace{-0.2cm} \begin{exampleblock}{} \begin{tabular}{lcrl|c} \textbf{Grid’5000} & & 828-nodes &(12,000+ cores, 31 clusters) &(France) \\ \textbf{GliCID (CCIPL)} & Nantes & 392-nodes &(7500+ cores) &(France) \\ \textbf{PlaFrIM Inria} & Bordeaux & 120-nodes &(3000+ cores) &(France) \\ \textbf{GriCAD} & Grenoble & 72-nodes &(1000+ cores) &(France) \\ \textbf{Max Delbrück Center} & Berlin & 250-nodes &+ workstations &(Allemagne) \\ \textbf{UMC} & Utrecht & 68-nodes &(1000+ cores) &(Pays-Bas) \\ \textbf{UTHSC Pangenome} & & 11-nodes &(264 cores) &(USA) \\ \\ \quad (le vôtre ?) \end{tabular} \end{exampleblock} \vspace{-0.25cm} \begin{center} \includegraphics[width=0.25\paperwidth]{static/guixhpc-logo-transparent-white} \vspace{-0.25cm} \href{https://hpc.guix.info/}{\texttt{https://hpc.guix.info}} \end{center} \vspace{-1.2cm} \begin{flushright} \includegraphics[width=0.175\paperwidth]{static/cafe-guix} \end{flushright} \end{frame} \thisslide{thanks} \begin{frame}[label=thanks]{Remerciements} \begin{itemize} \item Ludovic Courtès \item Ricardo Wurmus (Guix comme bibliothèque Scheme : Guix Workflow Language) \item Mathieu Othacehe (\href{https://guix.gnu.org/cuirass/}% {Cuirass \scriptsize{(lien)} \normalsize = CI} qui assure la disponibilité des \emph{substituts} binaires) \item tous les contributeurs (de la question au \emph{patch} en passant par la rapport de \emph{bug}) \end{itemize} \vfill{} \emph{«~Présidents~» de la session} JRES : \begin{itemize} \item Yann Dupont \item Emmanuel Halbwachs \end{itemize} \end{frame}