Compilation distribuée sur un réseau local

Expérimentations avec DistCC, qui permet de distribuer les tâches de compilation d'un code source.

Compilation distribuée sur un réseau local

Suite à la discussion avec Jeko concernant Arch Linux ARM sur un Raspberry Pi 2 et la possibilité d'utiliser Ghost — sachant que Ghost fonctionne idéalement avec Node.js 0.10 et que ne sont disponibles que les versions 0.8 (ne fonctionne pas) et 0.12 (support instable pour le moment) pour Arch Linux ARM —, j'ai essayé de compiler Node.js en version 0.10 sur mon Raspberry Pi 2 (sans succès pour le moment, on ne s'improvise pas mainteneur de projet).

  1. Mes premières compilations échouaient.
  2. Ça prend du temps de compiler sur un Raspberry Pi, même un deuxième du nom.
  3. Pour vérifier que mon PKGBUILD (recette de compilation pour Arch Linux qui intègre le produit de celle-ci au gestionnaire de paquets) était correct, je relançais à chaque fois une compilation.
  4. Ça prend du temps de compiler sur un Raspberry Pi…

Maître : Raspberry Pi 2

J'allais donc certainement y passer des jours à coups d'essai-erreur, corriger le PKGBUILD, tester, recorriger suite à une nouvelle erreur. Mais en jetant un œil au fichier de configuration /etc/makepkg.conf — makepkg étant l'utilitaire permettant de construire les paquets sur base d'un PKGBUILD sous Arch Linux —, je vis qu'il était possible de distribuer la compilation sur mon réseau local : les machines sur mon réseau allaient pouvoir servir à compiler pour le Raspeberry et ainsi lui alléger la tâche. Le programme mentionné dans ledit fichier de configuration est distcc.

#########################################################################
# BUILD ENVIRONMENT
#########################################################################
#
# Defaults: BUILDENV=(!distcc color !ccache check !sign)
#  A negated environment option will do the opposite of the comments below.
#
#-- distcc:   Use the Distributed C/C++/ObjC compiler
#-- color:    Colorize output messages
#-- ccache:   Use ccache to cache compilation
#-- check:    Run the check() function if present in the PKGBUILD
#-- sign:     Generate PGP signature file
#
BUILDENV=(distcc color ccache check !sign)

Pour activer la distribution de la compilation du code, il faut donc enlever le point d'exclamation devant distcc. J'en ai aussi profité pour activer le cache de compilation ccache. Du coup, j'ai dû installer les deux programmes :

pacman -Sy distcc ccache --needed

Deux sections supplémentaires doivent être peuplées dans /etc/makepkg.conf :

  1. MAKEFLAGS, les arguments qui seront envoyés à la commande make. Où « X » est la somme du nombre maximal de threads par serveur (machine pouvant exécuter la compilation).

     #-- Make Flags: change this for DistCC/SMP systems
     MAKEFLAGS="-jX"
    
  2. DISTCC_HOSTS, l'argument à ajouter sont les adresses IP des serveurs qui vont accueillir la compilation. Chaque adresse est suivie d'une barre oblique ("/") et du nombre de tâches qui pourront être lancées sur ce serveur. De plus, il est une pratique courante de définir le nombre de tâches par machine comme la somme du nombre de cœurs physiques (cœurs par socket) et du nombre de threads par cœurs (dans le cadre de la technologique hyper-threading), le tout plus 1. Sur l'Intel i7-3667U de Karl, la commande nproc me renvoie la valeur 4, qui est la première somme. Je déclarerai 5 tâches dans la configuration de distcc. Sur mon réseau local, karl a l'adresse fixe 192.168.1.69. Ma configuration de distcc sera donc la suivante :

     #-- If using DistCC, your MAKEFLAGS will also need modification. In addition,
     #-- specify a space-delimited list of hosts running in the DistCC cluster.
     DISTCC_HOSTS="192.168.1.69/5"
    

Documentation concernant la compilation distribuée :

Esclave :

Pour pouvoir compiler des paquets pour architecture ARM (armv7l dixit lscpu) sur ma machine x86_64 (c'est-à-dire d'une architecture pour une autre, soit de la compilation croisée), j'ai installé distccd-alarm sur la machine qui « aidera » le RPi à compiler, installation qui permet d'automatiser rapidement le déploiement. Il suffit de 

  • Cloner le dépôt

      git clone https://github.com/WarheadsSE/PKGs.git
    
  • Aller au dossier contenant distccd-alarm

      cd PKGs/distccd-alarm
    
  • Lancer la compilation et l'installation des paquets

      makepkg -sric
    

    Où :

    • -s / --syncdeps installe les dépendances manquantes ;
    • -r / --rmdeps désinstalle les dépendances superflues après compilation ;
    • -i / --install installe le paquet si la compilation s'est bien passée ;
    • -c / --clean nettoie le dossier de compilation après celle-ci.

Cela installe trois paquets, distccd-alarm-armv{5,6h,7h}, pour plusieurs types d'architecture ARM. Celle qui m'intéresse pour le Raspberry Pi 2 est l'ARMv7.

Plusieurs choses à savoir pour déployer cela, donc 

  • Les fichiers de configuration des trois paquets se trouvent dans le dossier /etc/conf.d/ : /etc/conf.d/distccd-armv{5,6h,7h}. J'y autorise tout mon réseau local à dialoguer avec ma machine :

      PATH=/usr/local/x-tools-armv7h/x-tools7h/arm-unknown-linux-gnueabihf/bin:$PATH
      DISTCC_ARGS="--user nobody --allow 192.168.1.0/24"
    
  • Lancer le processus systemd lié :

      systemctl start distccd-armv{5,6h,7h}.service
    

Finalement, il ne reste plus qu'à compiler ses paquets sur le Raspberry Pi. Si le code est en C, C++, Objective C ou Objective C++, il sera compilé par les autres machines, plus puissantes, qui sont déclarées disponibles sur le réseau local.

Documentation concernant la compilation croisée :

En test : configuration Avahi

Plutôt que de déclarer des adresses IP fixes, j'aimerais plutôt utiliser les possibilités d'Avahi. Si mon routeur déconne (il déconne souvent) ou si je change d'environnement, je n'ai pas envie de changer chaque adresse IP dans ma configuration, donc de me rappeler de chaque endroit où j'ai modifié cela. Sur le papier, utiliser Avahi avec distcc permet d'utiliser de façon souple les cœurs disponibles, qu'importe le nombre de machines sur le réseau, etc.

Pour ce faire, il faut activer le support d'Avahi par distcc :

  • Sur les machines esclaves, ajouter --zeroconf au serveur distccd-armv{5,6h,7h}.service, donc dans le fichier de configuration /etc/conf.d/distccd-armv{5,6h,7h} si vous utilisez aussi distccd-alarm.
  • Sur la machine hôte, ajouter la ligne +zeroconf au fichier $HOME/.distcc/hosts.

La commande avahi-browse -r _distcc._tcp permet dès lors d'afficher les machines se déclarant sur le réseau local sous Avahi. Par exemple chez moi :

+   eth0 IPv4 distcc@karl                                   Distributed Compiler local
=   eth0 IPv4 distcc@karl                                   Distributed Compiler local
   hostname = [karl.local]
   address = [192.168.1.69]
   port = [3632]
   txt = ["cc_machine=arm-unknown-linux-gnueabihf" "cc_version=5.1.1" "gnuhost=x86_64-unknown-linux-gnu" "distcc=3.2rc1" "cpus=4" "txtvers=1"]

On voit donc que la machine « karl » annonce qu'elle a 4 cœurs de CPU a « prêter » pour compiler.

Je dois encore parfaire cette configuration chez moi. Si le serveur de compilation distribuée semble pourtant bien configuré, du côté de la machine maîtresse cela semble cafouiller, puisqu'elle n'arrive pas à déléguer la compilation aux autres machines sur le réseau.

Documentation sur la distribution de la compilation via Avahi :